github.com/vmware/govmomi@v0.51.0/simulator/ip_pool_manager_test.go (about)

     1  // © Broadcom. All Rights Reserved.
     2  // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package simulator
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  	"net"
    11  	"reflect"
    12  	"testing"
    13  
    14  	"github.com/vmware/govmomi"
    15  	"github.com/vmware/govmomi/vim25/methods"
    16  	"github.com/vmware/govmomi/vim25/types"
    17  )
    18  
    19  func TestIpPoolv4(t *testing.T) {
    20  	tests := []struct {
    21  		ipRange string
    22  		length  int32
    23  	}{
    24  		{"10.10.10.2#250", 250},
    25  		{"10.10.10.2#10, 10.10.10.20#20", 30},
    26  		{"10.10.10.2#10, 10.10.10.20#20, 10.10.10.50#20", 50},
    27  	}
    28  
    29  	for _, test := range tests {
    30  		var ipPool = MustNewIpPool(&types.IpPool{
    31  			Id:                     1,
    32  			Name:                   "ip-pool",
    33  			AvailableIpv4Addresses: test.length,
    34  			AvailableIpv6Addresses: 0,
    35  			AllocatedIpv6Addresses: 0,
    36  			AllocatedIpv4Addresses: 0,
    37  			Ipv4Config: &types.IpPoolIpPoolConfigInfo{
    38  				Netmask:       "10.10.10.255",
    39  				Gateway:       "10.10.10.1",
    40  				SubnetAddress: "10.10.10.0",
    41  				Range:         test.ipRange,
    42  			},
    43  		})
    44  
    45  		if len(ipPool.ipv4Pool) != int(test.length) {
    46  			t.Fatalf("expect length to be %d; got %d", test.length, len(ipPool.ipv4Pool))
    47  		}
    48  
    49  		ip, err := ipPool.AllocateIPv4("alloc")
    50  		if err != nil {
    51  			t.Fatal(err)
    52  		}
    53  
    54  		ip2, err := ipPool.AllocateIPv4("alloc")
    55  		if err != nil {
    56  			t.Fatal(err)
    57  		}
    58  		if ip != ip2 {
    59  			t.Fatalf("same allocation key should allocate the same ip; got %s, %s", ip, ip2)
    60  		}
    61  
    62  		err = ipPool.ReleaseIpv4("bad-alloc")
    63  		if err == nil {
    64  			t.Fatal("expect error to release a bad allocation")
    65  		}
    66  
    67  		if len(ipPool.ipv4Pool) != int(test.length)-1 {
    68  			t.Fatalf("expect length to be %d; got %d", test.length-1, len(ipPool.ipv4Pool))
    69  		}
    70  
    71  		err = ipPool.ReleaseIpv4("alloc")
    72  		if err != nil {
    73  			t.Fatal(err)
    74  		}
    75  
    76  		if len(ipPool.ipv4Pool) != int(test.length) {
    77  			t.Fatalf("expect length to be %d; got %d", test.length, len(ipPool.ipv4Pool))
    78  		}
    79  
    80  		allocated := map[string]bool{}
    81  		for i := 0; i < int(test.length); i++ {
    82  			ip, err := ipPool.AllocateIPv4(fmt.Sprintf("alloc-%d", i))
    83  			if err != nil {
    84  				t.Fatal(err)
    85  			}
    86  
    87  			if _, ok := allocated[ip]; ok {
    88  				t.Fatalf("duplicated allocation of ip %q", ip)
    89  			}
    90  			allocated[ip] = true
    91  		}
    92  
    93  		_, err = ipPool.AllocateIPv4("last-allocation")
    94  		if err != errNoIpAvailable {
    95  			t.Fatalf("expect errNoIpAvailable; got %s", err)
    96  		}
    97  	}
    98  }
    99  
   100  func TestIpPoolv6(t *testing.T) {
   101  	tests := []struct {
   102  		ipRange string
   103  		length  int32
   104  	}{
   105  		{"2001:4860:0:2001::2#250", 250},
   106  	}
   107  
   108  	for _, test := range tests {
   109  		var ipPool = MustNewIpPool(&types.IpPool{
   110  			Id:                     1,
   111  			Name:                   "ip-pool",
   112  			AvailableIpv4Addresses: 0,
   113  			AvailableIpv6Addresses: test.length,
   114  			AllocatedIpv6Addresses: 0,
   115  			AllocatedIpv4Addresses: 0,
   116  			Ipv6Config: &types.IpPoolIpPoolConfigInfo{
   117  				Netmask:       "2001:4860:0:2001::ff",
   118  				Gateway:       "2001:4860:0:2001::1",
   119  				SubnetAddress: "2001:4860:0:2001::0",
   120  				Range:         test.ipRange,
   121  			},
   122  		})
   123  
   124  		if len(ipPool.ipv6Pool) != int(test.length) {
   125  			t.Fatalf("expect length to be %d; got %d", test.length, len(ipPool.ipv4Pool))
   126  		}
   127  
   128  		ip, err := ipPool.AllocateIpv6("alloc")
   129  		if err != nil {
   130  			t.Fatal(err)
   131  		}
   132  
   133  		ip2, err := ipPool.AllocateIpv6("alloc")
   134  		if err != nil {
   135  			t.Fatal(err)
   136  		}
   137  		if ip != ip2 {
   138  			t.Fatalf("same allocation key should allocate the same ip; got %s, %s", ip, ip2)
   139  		}
   140  
   141  		err = ipPool.ReleaseIpv6("bad-alloc")
   142  		if err == nil {
   143  			t.Fatal("expect error to release a bad allocation")
   144  		}
   145  
   146  		if len(ipPool.ipv6Pool) != int(test.length)-1 {
   147  			t.Fatalf("expect length to be %d; got %d", test.length-1, len(ipPool.ipv4Pool))
   148  		}
   149  
   150  		err = ipPool.ReleaseIpv6("alloc")
   151  		if err != nil {
   152  			t.Fatal(err)
   153  		}
   154  
   155  		if len(ipPool.ipv6Pool) != int(test.length) {
   156  			t.Fatalf("expect length to be %d; got %d", test.length, len(ipPool.ipv4Pool))
   157  		}
   158  
   159  		allocated := map[string]bool{}
   160  		for i := 0; i < int(test.length); i++ {
   161  			ip, err := ipPool.AllocateIpv6(fmt.Sprintf("alloc-%d", i))
   162  			if err != nil {
   163  				t.Fatal(err)
   164  			}
   165  
   166  			if _, ok := allocated[ip]; ok {
   167  				t.Fatalf("duplicated allocation of ip %q", ip)
   168  			}
   169  			allocated[ip] = true
   170  		}
   171  
   172  		_, err = ipPool.AllocateIpv6("last-allocation")
   173  		if err != errNoIpAvailable {
   174  			t.Fatalf("expect errNoIpAvailable; got %s", err)
   175  		}
   176  	}
   177  }
   178  
   179  func TestIpPoolManagerLifecycle(t *testing.T) {
   180  	ctx := context.Background()
   181  	m := VPX()
   182  
   183  	defer m.Remove()
   184  
   185  	err := m.Create()
   186  	if err != nil {
   187  		t.Fatal(err)
   188  	}
   189  
   190  	s := m.Service.NewServer()
   191  	defer s.Close()
   192  
   193  	c, err := govmomi.NewClient(ctx, s.URL, true)
   194  	if err != nil {
   195  		t.Fatal(err)
   196  	}
   197  
   198  	ref := types.ManagedObjectReference{Type: "IpPoolManager", Value: "IpPoolManager"}
   199  
   200  	var ipPool = &types.IpPool{
   201  		Name:                   "ip-pool",
   202  		AvailableIpv4Addresses: 250,
   203  		AvailableIpv6Addresses: 250,
   204  		AllocatedIpv4Addresses: 0,
   205  		AllocatedIpv6Addresses: 0,
   206  		Ipv4Config: &types.IpPoolIpPoolConfigInfo{
   207  			Netmask:       "10.10.10.255",
   208  			Gateway:       "10.10.10.1",
   209  			SubnetAddress: "10.10.10.0",
   210  			Range:         "10.10.10.2#250",
   211  		},
   212  		Ipv6Config: &types.IpPoolIpPoolConfigInfo{
   213  			Netmask:       "2001:4860:0:2001::ff",
   214  			Gateway:       "2001:4860:0:2001::1",
   215  			SubnetAddress: "2001:4860:0:2001::0",
   216  			Range:         "2001:4860:0:2001::2#250",
   217  		},
   218  	}
   219  
   220  	createReq := &types.CreateIpPool{
   221  		This: ref,
   222  		Pool: *ipPool,
   223  	}
   224  
   225  	createResp, err := methods.CreateIpPool(ctx, c.Client, createReq)
   226  	if err != nil {
   227  		t.Fatal(err)
   228  	}
   229  	if createResp.Returnval != 2 {
   230  		t.Fatalf("expect pool id to be 2; got %d", createResp.Returnval)
   231  	}
   232  
   233  	ipPool.Id = 2
   234  	ipPool.Ipv4Config = &types.IpPoolIpPoolConfigInfo{
   235  		Netmask:       "10.20.10.255",
   236  		Gateway:       "10.20.10.1",
   237  		SubnetAddress: "10.20.10.0",
   238  		Range:         "10.20.10.2#250",
   239  	}
   240  
   241  	updateReq := &types.UpdateIpPool{
   242  		This: ref,
   243  		Pool: *ipPool,
   244  	}
   245  
   246  	_, err = methods.UpdateIpPool(ctx, c.Client, updateReq)
   247  	if err != nil {
   248  		t.Fatal(err)
   249  	}
   250  
   251  	queryReq := &types.QueryIpPools{
   252  		This: ref,
   253  	}
   254  
   255  	queryResp, err := methods.QueryIpPools(ctx, c.Client, queryReq)
   256  	if err != nil {
   257  		t.Fatal(err)
   258  	}
   259  
   260  	if len(queryResp.Returnval) != 2 {
   261  		t.Fatalf("expect length of ip pools is 2; got %d", len(queryResp.Returnval))
   262  	}
   263  	if !reflect.DeepEqual(queryResp.Returnval[1].Ipv4Config, ipPool.Ipv4Config) {
   264  		t.Fatalf("expect query result equal to %+v; got %+v",
   265  			ipPool.Ipv4Config, queryResp.Returnval[1].Ipv4Config)
   266  	}
   267  
   268  	destroyReq := &types.DestroyIpPool{
   269  		This: ref,
   270  		Id:   2,
   271  	}
   272  
   273  	_, err = methods.DestroyIpPool(ctx, c.Client, destroyReq)
   274  	if err != nil {
   275  		t.Fatal(err)
   276  	}
   277  
   278  	queryResp, err = methods.QueryIpPools(ctx, c.Client, queryReq)
   279  	if err != nil {
   280  		t.Fatal(err)
   281  	}
   282  	if len(queryResp.Returnval) != 1 {
   283  		t.Fatalf("expect length of ip pools is 1 (1 deleted); got %d", len(queryResp.Returnval))
   284  	}
   285  }
   286  
   287  func TestIpPoolManagerAllocate(t *testing.T) {
   288  	ctx := context.Background()
   289  	m := VPX()
   290  
   291  	defer m.Remove()
   292  
   293  	err := m.Create()
   294  	if err != nil {
   295  		t.Fatal(err)
   296  	}
   297  
   298  	s := m.Service.NewServer()
   299  	defer s.Close()
   300  
   301  	c, err := govmomi.NewClient(ctx, s.URL, true)
   302  	if err != nil {
   303  		t.Fatal(err)
   304  	}
   305  
   306  	ref := types.ManagedObjectReference{Type: "IpPoolManager", Value: "IpPoolManager"}
   307  
   308  	// Allocate IPv4
   309  	allocateReq := &types.AllocateIpv4Address{
   310  		This:         ref,
   311  		PoolId:       1,
   312  		AllocationId: "alloc",
   313  	}
   314  
   315  	allocateResp, err := methods.AllocateIpv4Address(ctx, c.Client, allocateReq)
   316  	if err != nil {
   317  		t.Fatal(err)
   318  	}
   319  	if net.ParseIP(allocateResp.Returnval) == nil {
   320  		t.Fatalf("%q is not IP address", allocateResp.Returnval)
   321  	}
   322  
   323  	releaseReq := &types.ReleaseIpAllocation{
   324  		This:         ref,
   325  		PoolId:       1,
   326  		AllocationId: "alloc",
   327  	}
   328  
   329  	queryReq := &types.QueryIPAllocations{
   330  		This:         ref,
   331  		PoolId:       1,
   332  		ExtensionKey: "alloc",
   333  	}
   334  
   335  	queryResp, err := methods.QueryIPAllocations(ctx, c.Client, queryReq)
   336  	if err != nil {
   337  		t.Fatal(err)
   338  	}
   339  	if len(queryResp.Returnval) != 1 {
   340  		t.Fatalf("expect length of result 1; got %s", queryResp.Returnval)
   341  	}
   342  	if queryResp.Returnval[0].IpAddress != allocateResp.Returnval {
   343  		t.Fatalf("expect same IP address; got %s, %s", queryResp.Returnval[0].IpAddress, allocateResp.Returnval)
   344  	}
   345  
   346  	_, err = methods.ReleaseIpAllocation(ctx, c.Client, releaseReq)
   347  	if err != nil {
   348  		t.Fatal(err)
   349  	}
   350  }