Skip to content

Commit

Permalink
Merge pull request #158 from NeowayLabs/fixFunctionToGetVMIP
Browse files Browse the repository at this point in the history
Fix function to get VM private IP addresses
  • Loading branch information
katcipis authored Oct 20, 2017
2 parents 7d0ba62 + 1aefd74 commit ebc74ce
Show file tree
Hide file tree
Showing 8 changed files with 207 additions and 26 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
# Release 0.9.1

This release removes the broken function:

* azure_vm_get_ip_address

And adds the new/tested:

* azure_vm_get_private_ip_addrs

# Release 0.9.0

This release breaks the API of the following functions:
Expand Down
26 changes: 20 additions & 6 deletions azure/vm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -268,13 +268,27 @@ fn azure_vm_delete(name, group) {
)
}

fn azure_vm_get_ip_address(name, group, iface_index, ip_index) {
info <= azure vm list-ip-address $group --json

#echo $ips
ip <= echo $info | jq -r ".[0].networkProfile.networkInterfaces["+$iface_index+"].expanded.ipConfigurations["+$ip_index+"].privateIPAddress"
# azure_vm_get_names will return a list with all names of
# VMs inside the given resource group. An empty list is
# returned if there is no VM on the given group.
#
# returns an error string if something goes wrong, empty string otherwise.
fn azure_vm_get_names(group) {
out, status <= az vm list --resource-group klb-examples-vm | jq -r ".[].name"
if $status != "0" {
return (), format("error getting vms names for resgroup[%s], output: %s", $group, $out)
}
if $out == "" {
return (), ""
}
return split($out, "\n"), ""
}

return $ip
fn azure_vm_get_private_ip_addrs(name, group) {
info <= az vm list-ip-addresses --name $name --resource-group $group
ipsraw <= echo $info | jq -r ".[0].virtualMachine.network.privateIpAddresses[]"
ips <= split($ipsraw, "\n")
return $ips
}

# azure_vm_availset_create creates a new instance of Availset.
Expand Down
2 changes: 1 addition & 1 deletion examples/azure/vm/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import klb/azure/vnet
import klb/azure/nsg
import klb/azure/route
import klb/azure/snapshot
import klb/azure/public-ip
import klb/azure/public_ip
import config.sh


Expand Down
14 changes: 14 additions & 0 deletions tests/azure/testdata/get_vm_ips.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env nash

import klb/azure/login
import klb/azure/vm

resgroup = $ARGS[1]
vmname = $ARGS[2]
output = $ARGS[3]

azure_login()

res <= azure_vm_get_private_ip_addrs($vmname, $resgroup)
echo $res > $output
echo "done"
70 changes: 69 additions & 1 deletion tests/azure/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func TestVM(t *testing.T) {
fixture.Run(t, "VMSnapshotPremium", vmtesttimeout, location, testVMSnapshotPremium)
fixture.Run(t, "VMPremiumDiskToStdSnapshot", vmtesttimeout, location, testVMPremiumDiskToStdSnapshot)
fixture.Run(t, "VMDuplicatedAvSet", vmtesttimeout, location, testDuplicatedAvailabilitySet)
fixture.Run(t, "VMGetIPAddress", vmtesttimeout, location, testGetVMIPAddress)
}

func genUniqName() string {
Expand Down Expand Up @@ -130,6 +131,73 @@ func testStandardDiskVM(t *testing.T, f fixture.F) {
testVMCreation(t, f, "Basic_A0", "Standard_LRS", "None")
}

func testGetVMIPAddress(
t *testing.T,
f fixture.F,
) {
// Regression test for stupid mistake

resources := createVMResources(t, f)
create := func(nic string) string {
createVMNIC(f, nic, resources.vnet, resources.subnet)
return createVM(
t,
f,
resources.availSet,
nic,
"Basic_A0",
"Standard_LRS",
"ReadWrite",
)
}
vm1 := create("nic1")
vm2 := create("nic2")

vms := azure.NewVM(f)

expectedVM1IPs := vms.IPs(t, vm1)
expectedVM2IPs := vms.IPs(t, vm2)

gotVM1IPs := getVMIPs(t, f, vm1)
gotVM2IPs := getVMIPs(t, f, vm2)

assertOneIP := func(vm string, ips []string) {
if len(ips) == 0 {
t.Fatalf("vm[%s] has no IP", vm)
}
if len(ips) > 1 {
t.Fatalf("vm[%s] has more than one IPs[%s]", vm, ips)
}
}

assertSameIP := func(vm string, expectedIP string, gotIP string) {
if expectedIP != gotIP {
t.Fatalf("vm[%s] IPs do not match [%s] != [%s]", expectedIP, gotIP)
}
}

assertOneIP(vm1, expectedVM1IPs)
assertOneIP(vm2, expectedVM2IPs)

assertOneIP(vm1, gotVM1IPs)
assertOneIP(vm2, gotVM2IPs)

assertSameIP(vm1, expectedVM1IPs[0], gotVM1IPs[0])
assertSameIP(vm2, expectedVM2IPs[0], gotVM2IPs[0])
}

func getVMIPs(t *testing.T, f fixture.F, vmname string) []string {
rawIPs := execWithIPC(t, f, func(outfile string) {
f.Shell.Run(
"./testdata/get_vm_ips.sh",
f.ResGroupName,
vmname,
outfile,
)
})
return strings.Split(rawIPs, " ")
}

type VMDisk struct {
Name string
Sku string
Expand Down Expand Up @@ -184,7 +252,7 @@ func testVMSnapshot(
})

f.Logger.Println("created snapshots, retrieving ids")
ids := strings.Split(strings.Trim(string(idsraw), "\n"), "\n")
ids := strings.Split(idsraw, "\n")
f.Logger.Printf("parsed ids: %s", ids)

if len(ids) != len(disks) {
Expand Down
45 changes: 28 additions & 17 deletions tests/lib/azure/fixture/resourcegroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"log"
"testing"
"time"

"github.com/Azure/azure-sdk-for-go/arm/resources/resources"
"github.com/NeowayLabs/klb/tests/lib/retrier"
Expand Down Expand Up @@ -71,22 +72,32 @@ func (r *ResourceGroup) Delete(t *testing.T, name string) {

r.client.Delete(name, r.ctx.Done())

resgroup, err := r.client.Get(name)
if err != nil {
r.logger.Printf("ResourceGroup.Delete finished")
return
}
r.logger.Printf("ResourceGroup.Delete: still exists, checking if deprovisioning")
if resgroup.Properties == nil {
t.Fatal("ResourceGroup.Delete: resgroup does not have properties")
}
if resgroup.Properties.ProvisioningState == nil {
t.Fatal("ResourceGroup.Delete: resgroup does not have ProvisioningState")
}
provisioningState := *resgroup.Properties.ProvisioningState
expectedState := "Deleting"
if *resgroup.Properties.ProvisioningState != expectedState {
t.Fatalf("ResourceGroup.Delete: expected state[%s] got [%s]", expectedState, provisioningState)
r.checkDeleted(t, name)
}

func (r *ResourceGroup) checkDeleted(t *testing.T, name string) {
deadline := time.Now().Add(30 * time.Second)

for time.Now().Before(deadline) {
resgroup, err := r.client.Get(name)
if err != nil {
r.logger.Printf("ResourceGroup.Delete finished")
return
}
r.logger.Printf("ResourceGroup.Delete: still exists, checking if deprovisioning")
if resgroup.Properties == nil {
t.Fatal("ResourceGroup.Delete: resgroup does not have properties")
}
if resgroup.Properties.ProvisioningState == nil {
t.Fatal("ResourceGroup.Delete: resgroup does not have ProvisioningState")
}
provisioningState := *resgroup.Properties.ProvisioningState
expectedState := "Deleting"
if provisioningState == expectedState {
r.logger.Printf("ResourceGroup.Delete: resgroup is deprovisioning, should be ok")
return
}
r.logger.Printf("ResourceGroup:Delete: resgroup not deleting or deleted yet")
time.Sleep(time.Second)
}
r.logger.Printf("ResourceGroup.Delete: resgroup is deprovisioning, should be ok")
}
24 changes: 23 additions & 1 deletion tests/lib/azure/nic.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package azure
import (
"errors"
"fmt"
"strings"
"testing"

"github.com/Azure/azure-sdk-for-go/arm/network"
Expand Down Expand Up @@ -49,15 +50,36 @@ type NicIPConfig struct {
LBBackendAddrPoolsIDs []string
}

func parseNICID(t *testing.T, nicID string) (string, string) {
// example:
// /subscriptions/e3e74e5f-cc81-49d1-8fab-00fff864c080/resourceGroups/klb-VMGetIPAddress-1508439367-7943/providers/Microsoft.Network/networkInterfaces/nic1
// FIXME: Did not found a way to get directly by the ID =(
// This is a bad/coupled solution
parsed := strings.Split(nicID, "/")
if len(parsed) != 9 {
t.Fatalf("unexpected NIC ID[%s] parsed[%s], M$ protocol probably changed", nicID, parsed)
}
return parsed[4], parsed[8]
}

func (nic *Nic) GetIPConfigsByID(t *testing.T, ID string) ([]NicIPConfig, error) {
resgroup, nicname := parseNICID(t, ID)
return nic.getIPConfigs(t, resgroup, nicname)
}

func (nic *Nic) GetIPConfigs(t *testing.T, name string) ([]NicIPConfig, error) {
return nic.getIPConfigs(t, nic.f.ResGroupName, name)
}

func (nic *Nic) getIPConfigs(t *testing.T, resgroup string, nicname string) ([]NicIPConfig, error) {

var ipconfigs []NicIPConfig

wraperror := func(err error) error {
return fmt.Errorf("Nic.GetInfo: error[%s]", err)
}

n, err := nic.client.Get(nic.f.ResGroupName, name, "")
n, err := nic.client.Get(resgroup, nicname, "")
if err != nil {
return []NicIPConfig{}, wraperror(err)
}
Expand Down
42 changes: 42 additions & 0 deletions tests/lib/azure/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,48 @@ func NewVM(f fixture.F) *VM {
return as
}

func (vm *VM) IPs(t *testing.T, vmname string) []string {
abortonerr := func(err error) {
if err != nil {
t.Fatalf("error[%s] getting IP address for vm[%s]", err, vmname)
}
}

v, err := vm.client.Get(vm.f.ResGroupName, vmname, "")
abortonerr(err)

if v.VirtualMachineProperties == nil {
abortonerr(errors.New("no virtual machine properties found"))
}
properties := v.VirtualMachineProperties

if properties.NetworkProfile == nil {
abortonerr(errors.New("Field NetworkProfile is nil!"))
}
network := *properties.NetworkProfile.NetworkInterfaces
if len(network) == 0 {
abortonerr(errors.New("Field NetworkInterfaces is nil!"))
}

ips := []string{}
nic := NewNic(vm.f)

for _, net := range network {
if net.ID == nil {
abortonerr(errors.New("network interface ID is nil!"))
}

ipConfigs, err := nic.GetIPConfigsByID(t, *net.ID)
abortonerr(err)

for _, ipConfig := range ipConfigs {
ips = append(ips, ipConfig.PrivateIPAddress)
}
}

return ips
}

func (vm *VM) OsDisk(t *testing.T, vmname string) VMOsDisk {

var osdisk *VMOsDisk
Expand Down

0 comments on commit ebc74ce

Please sign in to comment.