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