github.com/vmware/govmomi@v0.37.1/simulator/ip_pool_manager.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 "errors" 21 "fmt" 22 "net" 23 "strconv" 24 "strings" 25 26 "github.com/vmware/govmomi/vim25/methods" 27 "github.com/vmware/govmomi/vim25/mo" 28 "github.com/vmware/govmomi/vim25/soap" 29 "github.com/vmware/govmomi/vim25/types" 30 ) 31 32 var ipPool = MustNewIpPool(&types.IpPool{ 33 Id: 1, 34 Name: "ip-pool", 35 AvailableIpv4Addresses: 250, 36 AvailableIpv6Addresses: 250, 37 AllocatedIpv6Addresses: 0, 38 AllocatedIpv4Addresses: 0, 39 Ipv4Config: &types.IpPoolIpPoolConfigInfo{ 40 Netmask: "10.10.10.255", 41 Gateway: "10.10.10.1", 42 SubnetAddress: "10.10.10.0", 43 Range: "10.10.10.2#250", 44 }, 45 Ipv6Config: &types.IpPoolIpPoolConfigInfo{ 46 Netmask: "2001:4860:0:2001::ff", 47 Gateway: "2001:4860:0:2001::1", 48 SubnetAddress: "2001:4860:0:2001::0", 49 Range: "2001:4860:0:2001::2#250", 50 }, 51 }) 52 53 // IpPoolManager implements a simple IP Pool manager in which all pools are shared 54 // across different datacenters. 55 type IpPoolManager struct { 56 mo.IpPoolManager 57 58 pools map[int32]*IpPool 59 nextPoolId int32 60 } 61 62 func (m *IpPoolManager) init(*Registry) { 63 m.pools = map[int32]*IpPool{ 64 1: ipPool, 65 } 66 m.nextPoolId = 2 67 } 68 69 func (m *IpPoolManager) CreateIpPool(req *types.CreateIpPool) soap.HasFault { 70 body := &methods.CreateIpPoolBody{} 71 id := m.nextPoolId 72 73 var err error 74 m.pools[id], err = NewIpPool(&req.Pool) 75 if err != nil { 76 body.Fault_ = Fault("", &types.RuntimeFault{}) 77 return body 78 } 79 80 m.nextPoolId++ 81 82 body.Res = &types.CreateIpPoolResponse{ 83 Returnval: id, 84 } 85 86 return body 87 } 88 89 func (m *IpPoolManager) DestroyIpPool(req *types.DestroyIpPool) soap.HasFault { 90 delete(m.pools, req.Id) 91 92 return &methods.DestroyIpPoolBody{ 93 Res: &types.DestroyIpPoolResponse{}, 94 } 95 } 96 97 func (m *IpPoolManager) QueryIpPools(req *types.QueryIpPools) soap.HasFault { 98 pools := []types.IpPool{} 99 100 for i := int32(1); i < m.nextPoolId; i++ { 101 if p, ok := m.pools[i]; ok { 102 pools = append(pools, *p.config) 103 } 104 } 105 106 return &methods.QueryIpPoolsBody{ 107 Res: &types.QueryIpPoolsResponse{ 108 Returnval: pools, 109 }, 110 } 111 } 112 113 func (m *IpPoolManager) UpdateIpPool(req *types.UpdateIpPool) soap.HasFault { 114 body := &methods.UpdateIpPoolBody{} 115 116 var pool *IpPool 117 var err error 118 var ok bool 119 120 if pool, ok = m.pools[req.Pool.Id]; !ok { 121 body.Fault_ = Fault("", &types.NotFoundFault{}) 122 return body 123 } 124 125 if pool.config.AllocatedIpv4Addresses+pool.config.AllocatedIpv6Addresses != 0 { 126 body.Fault_ = Fault("update a pool has been used is not supported", &types.RuntimeFault{}) 127 return body 128 } 129 130 m.pools[req.Pool.Id], err = NewIpPool(&req.Pool) 131 if err != nil { 132 body.Fault_ = Fault(err.Error(), &types.RuntimeFault{}) 133 return body 134 } 135 136 body.Res = &types.UpdateIpPoolResponse{} 137 138 return body 139 } 140 141 func (m *IpPoolManager) AllocateIpv4Address(req *types.AllocateIpv4Address) soap.HasFault { 142 body := &methods.AllocateIpv4AddressBody{} 143 144 pool, ok := m.pools[req.PoolId] 145 if !ok { 146 body.Fault_ = Fault("", &types.InvalidArgument{}) 147 return body 148 } 149 150 ip, err := pool.AllocateIPv4(req.AllocationId) 151 if err != nil { 152 body.Fault_ = Fault(err.Error(), &types.RuntimeFault{}) 153 return body 154 } 155 156 body.Res = &types.AllocateIpv4AddressResponse{ 157 Returnval: ip, 158 } 159 160 return body 161 } 162 163 func (m *IpPoolManager) AllocateIpv6Address(req *types.AllocateIpv6Address) soap.HasFault { 164 body := &methods.AllocateIpv6AddressBody{} 165 166 pool, ok := m.pools[req.PoolId] 167 if !ok { 168 body.Fault_ = Fault("", &types.InvalidArgument{}) 169 return body 170 } 171 172 ip, err := pool.AllocateIpv6(req.AllocationId) 173 if err != nil { 174 body.Fault_ = Fault(err.Error(), &types.RuntimeFault{}) 175 return body 176 } 177 178 body.Res = &types.AllocateIpv6AddressResponse{ 179 Returnval: ip, 180 } 181 182 return body 183 } 184 185 func (m *IpPoolManager) ReleaseIpAllocation(req *types.ReleaseIpAllocation) soap.HasFault { 186 body := &methods.ReleaseIpAllocationBody{} 187 188 pool, ok := m.pools[req.PoolId] 189 if !ok { 190 body.Fault_ = Fault("", &types.InvalidArgument{}) 191 return body 192 } 193 194 pool.ReleaseIpv4(req.AllocationId) 195 pool.ReleaseIpv6(req.AllocationId) 196 197 body.Res = &types.ReleaseIpAllocationResponse{} 198 199 return body 200 } 201 202 func (m *IpPoolManager) QueryIPAllocations(req *types.QueryIPAllocations) soap.HasFault { 203 body := &methods.QueryIPAllocationsBody{} 204 205 pool, ok := m.pools[req.PoolId] 206 if !ok { 207 body.Fault_ = Fault("", &types.InvalidArgument{}) 208 return body 209 } 210 211 body.Res = &types.QueryIPAllocationsResponse{} 212 213 ipv4, ok := pool.ipv4Allocation[req.ExtensionKey] 214 if ok { 215 body.Res.Returnval = append(body.Res.Returnval, types.IpPoolManagerIpAllocation{ 216 IpAddress: ipv4, 217 AllocationId: req.ExtensionKey, 218 }) 219 } 220 221 ipv6, ok := pool.ipv6Allocation[req.ExtensionKey] 222 if ok { 223 body.Res.Returnval = append(body.Res.Returnval, types.IpPoolManagerIpAllocation{ 224 IpAddress: ipv6, 225 AllocationId: req.ExtensionKey, 226 }) 227 } 228 229 return body 230 } 231 232 var ( 233 errNoIpAvailable = errors.New("no ip address available") 234 errInvalidAllocation = errors.New("allocation id not recognized") 235 ) 236 237 type IpPool struct { 238 config *types.IpPool 239 ipv4Allocation map[string]string 240 ipv6Allocation map[string]string 241 ipv4Pool []string 242 ipv6Pool []string 243 } 244 245 func MustNewIpPool(config *types.IpPool) *IpPool { 246 pool, err := NewIpPool(config) 247 if err != nil { 248 panic(err) 249 } 250 251 return pool 252 } 253 254 func NewIpPool(config *types.IpPool) (*IpPool, error) { 255 pool := &IpPool{ 256 config: config, 257 ipv4Allocation: make(map[string]string), 258 ipv6Allocation: make(map[string]string), 259 } 260 261 return pool, pool.init() 262 } 263 264 func (p *IpPool) init() error { 265 // IPv4 range 266 if p.config.Ipv4Config != nil { 267 ranges := strings.Split(p.config.Ipv4Config.Range, ",") 268 for _, r := range ranges { 269 sp := strings.Split(r, "#") 270 if len(sp) != 2 { 271 return fmt.Errorf("format of range should be ip#number; got %q", r) 272 } 273 274 ip := net.ParseIP(strings.TrimSpace(sp[0])).To4() 275 if ip == nil { 276 return fmt.Errorf("bad ip format: %q", sp[0]) 277 } 278 279 length, err := strconv.Atoi(sp[1]) 280 if err != nil { 281 return err 282 } 283 284 for i := 0; i < length; i++ { 285 p.ipv4Pool = append(p.ipv4Pool, net.IPv4(ip[0], ip[1], ip[2], ip[3]+byte(i)).String()) 286 } 287 } 288 } 289 290 // IPv6 range 291 if p.config.Ipv6Config != nil { 292 ranges := strings.Split(p.config.Ipv6Config.Range, ",") 293 for _, r := range ranges { 294 sp := strings.Split(r, "#") 295 if len(sp) != 2 { 296 return fmt.Errorf("format of range should be ip#number; got %q", r) 297 } 298 299 ip := net.ParseIP(strings.TrimSpace(sp[0])).To16() 300 if ip == nil { 301 return fmt.Errorf("bad ip format: %q", sp[0]) 302 } 303 304 length, err := strconv.Atoi(sp[1]) 305 if err != nil { 306 return err 307 } 308 309 for i := 0; i < length; i++ { 310 var ipv6 [16]byte 311 copy(ipv6[:], ip) 312 ipv6[15] += byte(i) 313 p.ipv6Pool = append(p.ipv6Pool, net.IP(ipv6[:]).String()) 314 } 315 } 316 } 317 318 return nil 319 } 320 321 func (p *IpPool) AllocateIPv4(allocation string) (string, error) { 322 if ip, ok := p.ipv4Allocation[allocation]; ok { 323 return ip, nil 324 } 325 326 l := len(p.ipv4Pool) 327 if l == 0 { 328 return "", errNoIpAvailable 329 } 330 331 ip := p.ipv4Pool[l-1] 332 333 p.config.AvailableIpv4Addresses-- 334 p.config.AllocatedIpv4Addresses++ 335 p.ipv4Pool = p.ipv4Pool[:l-1] 336 p.ipv4Allocation[allocation] = ip 337 338 return ip, nil 339 } 340 341 func (p *IpPool) ReleaseIpv4(allocation string) error { 342 ip, ok := p.ipv4Allocation[allocation] 343 if !ok { 344 return errInvalidAllocation 345 } 346 347 delete(p.ipv4Allocation, allocation) 348 p.config.AvailableIpv4Addresses++ 349 p.config.AllocatedIpv4Addresses-- 350 p.ipv4Pool = append(p.ipv4Pool, ip) 351 352 return nil 353 } 354 355 func (p *IpPool) AllocateIpv6(allocation string) (string, error) { 356 if ip, ok := p.ipv6Allocation[allocation]; ok { 357 return ip, nil 358 } 359 360 l := len(p.ipv6Pool) 361 if l == 0 { 362 return "", errNoIpAvailable 363 } 364 365 ip := p.ipv6Pool[l-1] 366 367 p.config.AvailableIpv6Addresses-- 368 p.config.AllocatedIpv6Addresses++ 369 p.ipv6Pool = p.ipv6Pool[:l-1] 370 p.ipv6Allocation[allocation] = ip 371 372 return ip, nil 373 } 374 375 func (p *IpPool) ReleaseIpv6(allocation string) error { 376 ip, ok := p.ipv6Allocation[allocation] 377 if !ok { 378 return errInvalidAllocation 379 } 380 381 delete(p.ipv6Allocation, allocation) 382 p.config.AvailableIpv6Addresses++ 383 p.config.AllocatedIpv6Addresses-- 384 p.ipv6Pool = append(p.ipv6Pool, ip) 385 386 return nil 387 }