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 }