gopkg.in/goose.v2@v2.0.1/testservices/neutronmodel/neutronmodel.go (about) 1 // neutronmodel is a package to allow novatestservices and neutrontestservices 2 // to share data related to FloatingIPs, Networks and SecurityGroups. 3 4 package neutronmodel 5 6 import ( 7 "net" 8 "strconv" 9 "sync" 10 11 "gopkg.in/goose.v2/neutron" 12 "gopkg.in/goose.v2/nova" 13 "gopkg.in/goose.v2/testservices" 14 ) 15 16 type NeutronModel struct { 17 groups map[string]neutron.SecurityGroupV2 18 rules map[string]neutron.SecurityGroupRuleV2 19 floatingIPs map[string]neutron.FloatingIPV2 20 networks map[string]neutron.NetworkV2 21 serverGroups map[string][]string 22 serverIPs map[string][]string 23 ports map[string]neutron.PortV2 24 nextGroupId int 25 nextRuleId int 26 nextPortId int 27 nextIPId int 28 rwMu *sync.RWMutex 29 } 30 31 // New setups the default data Network and Security Group for the neutron and 32 // nova test services. 33 func New() *NeutronModel { 34 // Real openstack instances have a default security group "out of the box". So we add it here. 35 defaultSecurityGroups := []neutron.SecurityGroupV2{ 36 {Id: "999", TenantId: "1", Name: "default", Description: "default group"}, 37 } 38 // There are no create/delete network/subnet commands, so make a few default 39 t := true 40 f := false 41 defaultNetworks := []neutron.NetworkV2{ 42 { // for use by opentstack provider test 43 Id: "1", 44 Name: "net", 45 SubnetIds: []string{"sub-net"}, 46 External: false, 47 AvailabilityZones: []string{"nova"}, 48 PortSecurityEnabled: &t, 49 }, 50 { // for use by opentstack provider test 51 Id: "2", 52 Name: "net-disabled", 53 SubnetIds: []string{"sub-net2"}, 54 External: false, 55 AvailabilityZones: []string{"nova"}, 56 PortSecurityEnabled: &f, 57 }, 58 { 59 Id: "999", 60 Name: "private_999", 61 SubnetIds: []string{"999-01"}, 62 External: false, 63 AvailabilityZones: []string{"test-available"}, 64 }, 65 { 66 Id: "998", 67 Name: "ext-net", 68 SubnetIds: []string{"998-01"}, 69 External: true, 70 AvailabilityZones: []string{"test-available"}, 71 TenantId: "tenant-one", 72 }, 73 { 74 Id: "997", 75 Name: "ext-net-wrong-az", 76 SubnetIds: []string{"997-01"}, 77 External: true, 78 AvailabilityZones: []string{"unavailable-az"}, 79 TenantId: "tenant-two", 80 }, 81 } 82 defaultPorts := []neutron.PortV2{} 83 84 neutronModel := &NeutronModel{ 85 groups: make(map[string]neutron.SecurityGroupV2), 86 rules: make(map[string]neutron.SecurityGroupRuleV2), 87 floatingIPs: make(map[string]neutron.FloatingIPV2), 88 networks: make(map[string]neutron.NetworkV2), 89 ports: make(map[string]neutron.PortV2), 90 rwMu: &sync.RWMutex{}, 91 } 92 93 for _, group := range defaultSecurityGroups { 94 err := neutronModel.AddSecurityGroup(group) 95 if err != nil { 96 panic(err) 97 } 98 } 99 for _, net := range defaultNetworks { 100 err := neutronModel.AddNetwork(net) 101 if err != nil { 102 panic(err) 103 } 104 } 105 for _, port := range defaultPorts { 106 err := neutronModel.AddPort(port) 107 if err != nil { 108 panic(err) 109 } 110 } 111 return neutronModel 112 } 113 114 // convertNeutronToNovaSecurityGroup converts a nova.SecurityGroup to 115 // neutron.SecurityGroupV2. 116 func (n *NeutronModel) convertNeutronToNovaSecurityGroup(group neutron.SecurityGroupV2) nova.SecurityGroup { 117 novaGroup := nova.SecurityGroup{ 118 TenantId: group.TenantId, 119 Id: group.Id, 120 Name: group.Name, 121 Description: group.Description, 122 Rules: []nova.SecurityGroupRule{}, 123 } 124 var novaRules []nova.SecurityGroupRule 125 for _, rule := range group.Rules { 126 novaRules = append(novaRules, nova.SecurityGroupRule{ 127 FromPort: rule.PortRangeMin, 128 ToPort: rule.PortRangeMax, 129 Id: rule.Id, 130 ParentGroupId: rule.ParentGroupId, 131 IPProtocol: rule.IPProtocol, 132 IPRange: map[string]string{"cidr": rule.RemoteIPPrefix}, 133 }) 134 } 135 if len(novaRules) > 0 { 136 novaGroup.Rules = novaRules 137 } 138 return novaGroup 139 } 140 141 // convertNeutronToNovaSecurityGroup converts a neutron.SecurityGroupV2 to a 142 // nova.SecurityGroup. 143 func (n *NeutronModel) convertNovaToNeutronSecurityGroup(group nova.SecurityGroup) neutron.SecurityGroupV2 { 144 neutronGroup := neutron.SecurityGroupV2{ 145 TenantId: group.TenantId, 146 Id: group.Id, 147 Name: group.Name, 148 Description: group.Description, 149 Rules: []neutron.SecurityGroupRuleV2{}, 150 } 151 var neutronRules []neutron.SecurityGroupRuleV2 152 for _, rule := range group.Rules { 153 neutronRules = append(neutronRules, neutron.SecurityGroupRuleV2{ 154 PortRangeMin: rule.FromPort, 155 PortRangeMax: rule.ToPort, 156 Id: rule.Id, 157 ParentGroupId: rule.ParentGroupId, 158 IPProtocol: rule.IPProtocol, 159 RemoteIPPrefix: rule.IPRange["cidr"], 160 }) 161 } 162 if len(neutronRules) > 0 { 163 neutronGroup.Rules = neutronRules 164 } 165 return neutronGroup 166 } 167 168 // UpdateSecurityGroup updates an existing security group given a 169 // neutron.SecurityGroupRuleV2. 170 func (n *NeutronModel) UpdateSecurityGroup(group neutron.SecurityGroupV2) error { 171 n.rwMu.Lock() 172 defer n.rwMu.Unlock() 173 existingGroup, err := n.SecurityGroup(group.Id) 174 if err != nil { 175 return testservices.NewSecurityGroupByIDNotFoundError(group.Id) 176 } 177 existingGroup.Name = group.Name 178 existingGroup.Description = group.Description 179 n.groups[group.Id] = *existingGroup 180 return nil 181 } 182 183 // UpdateNovaSecurityGroup updates an existing security group given a nova.SecurityGroup. 184 func (n *NeutronModel) UpdateNovaSecurityGroup(group nova.SecurityGroup) error { 185 return n.UpdateSecurityGroup(n.convertNovaToNeutronSecurityGroup(group)) 186 } 187 188 // AddSecurityGroup creates a new security group given a neutron.SecurityGroupV2. 189 func (n *NeutronModel) AddSecurityGroup(group neutron.SecurityGroupV2) error { 190 n.rwMu.Lock() 191 defer n.rwMu.Unlock() 192 if _, err := n.SecurityGroup(group.Id); err == nil { 193 return testservices.NewSecurityGroupAlreadyExistsError(group.Id) 194 } 195 // Neutron adds 2 default egress security group rules to new security 196 // groups, copy that behavior here. 197 id, _ := strconv.Atoi(group.Id) 198 id1 := id * 999 199 id2 := id * 998 200 group.Rules = []neutron.SecurityGroupRuleV2{ 201 { 202 Direction: "egress", 203 EthernetType: "IPv4", 204 Id: strconv.Itoa(id1), 205 TenantId: group.TenantId, 206 ParentGroupId: group.Id, 207 }, 208 { 209 Direction: "egress", 210 EthernetType: "IPv6", 211 Id: strconv.Itoa(id2), 212 TenantId: group.TenantId, 213 ParentGroupId: group.Id, 214 }, 215 } 216 for _, rule := range group.Rules { 217 n.rules[rule.Id] = rule 218 } 219 n.groups[group.Id] = group 220 return nil 221 } 222 223 // AddNovaSecurityGroup creates a new security group given a nova.SecurityGroup. 224 func (n *NeutronModel) AddNovaSecurityGroup(group nova.SecurityGroup) error { 225 err := n.AddSecurityGroup(n.convertNovaToNeutronSecurityGroup(group)) 226 if err != nil { 227 return err 228 } 229 return err 230 } 231 232 // SecurityGroup retrieves an existing group by ID, data in neutron.SecurityGroupV2 form. 233 func (n *NeutronModel) SecurityGroup(groupId string) (*neutron.SecurityGroupV2, error) { 234 if n.rwMu == nil { 235 n.rwMu.RLock() 236 defer n.rwMu.RUnlock() 237 } 238 group, ok := n.groups[groupId] 239 if !ok { 240 return nil, testservices.NewSecurityGroupByIDNotFoundError(groupId) 241 } 242 return &group, nil 243 } 244 245 // NovaSecurityGroup retrieves an existing group by ID, data in nova.SecurityGroup form. 246 func (n *NeutronModel) NovaSecurityGroup(groupId string) (*nova.SecurityGroup, error) { 247 group, err := n.SecurityGroup(groupId) 248 if err != nil { 249 return nil, err 250 } 251 novaGroup := n.convertNeutronToNovaSecurityGroup(*group) 252 return &novaGroup, nil 253 } 254 255 // SecurityGroupByName retrieves an existing named group, data in 256 // neutron.SecurityGroupV2 form. 257 func (n *NeutronModel) SecurityGroupByName(groupName string) ([]neutron.SecurityGroupV2, error) { 258 n.rwMu.RLock() 259 defer n.rwMu.RUnlock() 260 var foundGrps []neutron.SecurityGroupV2 261 for _, group := range n.groups { 262 if group.Name == groupName { 263 foundGrps = append(foundGrps, group) 264 } 265 } 266 return foundGrps, nil 267 //return nil, testservices.NewSecurityGroupByNameNotFoundError(groupName) 268 } 269 270 // NovaSecurityGroupByName retrieves an existing named group, data in 271 // nova.SecurityGroup form. 272 func (n *NeutronModel) NovaSecurityGroupByName(groupName string) (*nova.SecurityGroup, error) { 273 groups, err := n.SecurityGroupByName(groupName) 274 if err != nil { 275 return nil, err 276 } 277 // Nova SecurityGroupsByName expects only 1 return value, return 278 // the first one found. 279 novaGroup := n.convertNeutronToNovaSecurityGroup(groups[0]) 280 return &novaGroup, nil 281 } 282 283 // AllSecurityGroups returns a list of all existing groups, data in 284 // neutron.SecurityGroupV2 form. 285 func (n *NeutronModel) AllSecurityGroups() []neutron.SecurityGroupV2 { 286 n.rwMu.RLock() 287 defer n.rwMu.RUnlock() 288 var groups []neutron.SecurityGroupV2 289 for _, group := range n.groups { 290 groups = append(groups, group) 291 } 292 return groups 293 } 294 295 // AllNovaSecurityGroups returns a list of all existing groups, 296 // nova.SecurityGroup form. 297 func (n *NeutronModel) AllNovaSecurityGroups() []nova.SecurityGroup { 298 neutronGroups := n.AllSecurityGroups() 299 var groups []nova.SecurityGroup 300 for _, group := range neutronGroups { 301 groups = append(groups, n.convertNeutronToNovaSecurityGroup(group)) 302 } 303 return groups 304 } 305 306 // RemoveSecurityGroup deletes an existing group. 307 func (n *NeutronModel) RemoveSecurityGroup(groupId string) error { 308 n.rwMu.Lock() 309 defer n.rwMu.Unlock() 310 if _, err := n.SecurityGroup(groupId); err != nil { 311 return err 312 } 313 delete(n.groups, groupId) 314 return nil 315 } 316 317 // AddSecurityGroupRule creates a new rule in an existing group. 318 // This can be either an ingress or an egress rule (see the notes 319 // about neutron.RuleInfoV2). 320 func (n *NeutronModel) AddSecurityGroupRule(ruleId string, rule neutron.RuleInfoV2) error { 321 n.rwMu.Lock() 322 defer n.rwMu.Unlock() 323 if _, err := n.SecurityGroupRule(ruleId); err == nil { 324 return testservices.NewNeutronSecurityGroupRuleAlreadyExistsError(rule.ParentGroupId) 325 } 326 group, err := n.SecurityGroup(rule.ParentGroupId) 327 if err != nil { 328 return err 329 } 330 newrule := neutron.SecurityGroupRuleV2{ 331 ParentGroupId: rule.ParentGroupId, 332 Id: ruleId, 333 RemoteIPPrefix: rule.RemoteIPPrefix, 334 } 335 if rule.Direction == "ingress" || rule.Direction == "egress" { 336 newrule.Direction = rule.Direction 337 } else { 338 return testservices.NewInvalidDirectionSecurityGroupError(rule.Direction) 339 } 340 if rule.PortRangeMin != 0 { 341 newrule.PortRangeMin = &rule.PortRangeMin 342 } 343 if rule.PortRangeMax != 0 { 344 newrule.PortRangeMax = &rule.PortRangeMax 345 } 346 if rule.IPProtocol != "" { 347 newrule.IPProtocol = &rule.IPProtocol 348 } 349 switch rule.EthernetType { 350 case "": 351 // Neutron assumes IPv4 if no EthernetType is specified 352 newrule.EthernetType = "IPv4" 353 case "IPv4", "IPv6": 354 newrule.EthernetType = rule.EthernetType 355 default: 356 return testservices.NewSecurityGroupRuleInvalidEthernetType(rule.EthernetType) 357 } 358 if newrule.RemoteIPPrefix != "" { 359 ip, _, err := net.ParseCIDR(newrule.RemoteIPPrefix) 360 if err != nil { 361 return testservices.NewSecurityGroupRuleInvalidCIDR(rule.RemoteIPPrefix) 362 } 363 if (newrule.EthernetType == "IPv4" && ip.To4() == nil) || 364 (newrule.EthernetType == "IPv6" && ip.To4() != nil) { 365 return testservices.NewSecurityGroupRuleParameterConflict("ethertype", newrule.EthernetType, "CIDR", newrule.RemoteIPPrefix) 366 } 367 } 368 if group.TenantId != "" { 369 newrule.TenantId = group.TenantId 370 } 371 372 group.Rules = append(group.Rules, newrule) 373 n.groups[group.Id] = *group 374 n.rules[newrule.Id] = newrule 375 return nil 376 } 377 378 // AddSecurityGroupRule creates a new rule in an existing group, data in nova.RuleInfo 379 // form. Rule is assumed to be ingress. 380 func (n *NeutronModel) AddNovaSecurityGroupRule(ruleId string, rule nova.RuleInfo) error { 381 neutronRule := neutron.RuleInfoV2{ 382 IPProtocol: rule.IPProtocol, 383 PortRangeMin: rule.FromPort, 384 PortRangeMax: rule.ToPort, 385 RemoteIPPrefix: rule.Cidr, 386 ParentGroupId: rule.ParentGroupId, 387 Direction: "ingress", 388 } 389 return n.AddSecurityGroupRule(ruleId, neutronRule) 390 } 391 392 // HasSecurityGroupRule returns whether the given group contains the given rule, 393 // or (when groupId="-1") whether the given rule exists. 394 func (n *NeutronModel) HasSecurityGroupRule(groupId, ruleId string) bool { 395 n.rwMu.RLock() 396 defer n.rwMu.RUnlock() 397 rule, ok := n.rules[ruleId] 398 _, err := n.SecurityGroup(groupId) 399 return ok && (groupId == "-1" || (err == nil && rule.ParentGroupId == groupId)) 400 } 401 402 // SecurityGroupRule retrieves an existing rule by ID, data in neutron.SecurityGroupRuleV2 form. 403 func (n *NeutronModel) SecurityGroupRule(ruleId string) (*neutron.SecurityGroupRuleV2, error) { 404 if n.rwMu == nil { 405 n.rwMu.RLock() 406 defer n.rwMu.RUnlock() 407 } 408 rule, ok := n.rules[ruleId] 409 if !ok { 410 return nil, testservices.NewSecurityGroupRuleNotFoundError(ruleId) 411 } 412 return &rule, nil 413 } 414 415 // SecurityGroupRule retrieves an existing rule by ID, data in nova.SecurityGroupRule form. 416 func (n *NeutronModel) NovaSecurityGroupRule(ruleId string) (*nova.SecurityGroupRule, error) { 417 rule, err := n.SecurityGroupRule(ruleId) 418 if err != nil { 419 return nil, err 420 } 421 novaRule := &nova.SecurityGroupRule{ 422 IPProtocol: rule.IPProtocol, 423 FromPort: rule.PortRangeMin, 424 ToPort: rule.PortRangeMax, 425 ParentGroupId: rule.ParentGroupId, 426 } 427 return novaRule, nil 428 } 429 430 // RemoveSecurityGroupRule deletes an existing rule from its group. 431 func (n *NeutronModel) RemoveSecurityGroupRule(ruleId string) error { 432 n.rwMu.Lock() 433 defer n.rwMu.Unlock() 434 rule, err := n.SecurityGroupRule(ruleId) 435 if err != nil { 436 return err 437 } 438 if group, err := n.SecurityGroup(rule.ParentGroupId); err == nil { 439 idx := -1 440 for ri, ru := range group.Rules { 441 if ru.Id == ruleId { 442 idx = ri 443 break 444 } 445 } 446 if idx != -1 { 447 group.Rules = append(group.Rules[:idx], group.Rules[idx+1:]...) 448 n.groups[group.Id] = *group 449 } 450 // Silently ignore missing rules... 451 } 452 // ...or groups 453 delete(n.rules, ruleId) 454 return nil 455 } 456 457 // AddFloatingIP creates a new floating IP address in the pool, given a neutron.FloatingIPV2. 458 func (n *NeutronModel) AddFloatingIP(ip neutron.FloatingIPV2) error { 459 n.rwMu.Lock() 460 defer n.rwMu.Unlock() 461 if _, err := n.FloatingIP(ip.Id); err == nil { 462 return testservices.NewFloatingIPExistsError(ip.Id) 463 } 464 n.floatingIPs[ip.Id] = ip 465 return nil 466 } 467 468 // AddNovaFloatingIP creates a new floatingIP IP address in the pool, given a nova.FloatingIP. 469 func (n *NeutronModel) AddNovaFloatingIP(ip nova.FloatingIP) error { 470 fip := neutron.FloatingIPV2{Id: ip.Id, IP: ip.IP} 471 if ip.FixedIP != nil { 472 fip.FixedIP = *ip.FixedIP 473 } 474 return n.AddFloatingIP(fip) 475 } 476 477 // HasFloatingIP returns whether the given floating IP address exists. 478 func (n *NeutronModel) HasFloatingIP(address string) bool { 479 n.rwMu.RLock() 480 defer n.rwMu.RUnlock() 481 if len(n.floatingIPs) == 0 { 482 return false 483 } 484 for _, fip := range n.floatingIPs { 485 if fip.IP == address { 486 return true 487 } 488 } 489 return false 490 } 491 492 // FloatingIP retrieves a neutron floating IP by ID. 493 func (n *NeutronModel) FloatingIP(ipId string) (*neutron.FloatingIPV2, error) { 494 if n.rwMu == nil { 495 n.rwMu.RLock() 496 defer n.rwMu.RUnlock() 497 } 498 ip, ok := n.floatingIPs[ipId] 499 if !ok { 500 return nil, testservices.NewFloatingIPNotFoundError(ipId) 501 } 502 return &ip, nil 503 } 504 505 // NovaFloatingIP retrieves a nova floating IP by ID. 506 func (n *NeutronModel) NovaFloatingIP(ipId string) (*nova.FloatingIP, error) { 507 fip, err := n.FloatingIP(ipId) 508 if err != nil { 509 return nil, err 510 } 511 return &nova.FloatingIP{Id: fip.Id, IP: fip.IP, FixedIP: &fip.FixedIP}, nil 512 } 513 514 // FloatingIPByAddr retrieves a neutron floating IP by address. 515 func (n *NeutronModel) FloatingIPByAddr(address string) (*neutron.FloatingIPV2, error) { 516 n.rwMu.RLock() 517 defer n.rwMu.RUnlock() 518 for _, fip := range n.floatingIPs { 519 if fip.IP == address { 520 return &fip, nil 521 } 522 } 523 return nil, testservices.NewFloatingIPNotFoundError(address) 524 } 525 526 // NovaFloatingIPByAddr retrieves a nova floating IP by address. 527 func (n *NeutronModel) NovaFloatingIPByAddr(address string) (*nova.FloatingIP, error) { 528 fip, err := n.FloatingIPByAddr(address) 529 if err != nil { 530 return nil, err 531 } 532 return &nova.FloatingIP{Id: fip.Id, IP: fip.IP, FixedIP: &fip.FixedIP}, nil 533 } 534 535 // AllFloatingIPs returns a list of all created floating IPs, data in 536 // neutron.FloatingIPV2 form. 537 func (n *NeutronModel) AllFloatingIPs() []neutron.FloatingIPV2 { 538 n.rwMu.RLock() 539 defer n.rwMu.RUnlock() 540 var fips []neutron.FloatingIPV2 541 for _, fip := range n.floatingIPs { 542 fips = append(fips, fip) 543 } 544 return fips 545 } 546 547 // AllNovaFloatingIPs returns a list of all created floating IPs, data in 548 // nova.FloatingIP form. 549 func (n *NeutronModel) AllNovaFloatingIPs() []nova.FloatingIP { 550 neutronFips := n.AllFloatingIPs() 551 var novaFips []nova.FloatingIP 552 for _, fip := range neutronFips { 553 novaFips = append(novaFips, nova.FloatingIP{ 554 Id: fip.Id, 555 IP: fip.IP, 556 FixedIP: &fip.FixedIP, 557 }) 558 } 559 return novaFips 560 } 561 562 // RemoveFloatingIP deletes an existing floating IP by ID. 563 func (n *NeutronModel) RemoveFloatingIP(ipId string) error { 564 n.rwMu.Lock() 565 defer n.rwMu.Unlock() 566 if _, err := n.FloatingIP(ipId); err != nil { 567 return err 568 } 569 delete(n.floatingIPs, ipId) 570 return nil 571 } 572 573 // UpdateNovaFloatingIP updates the Fixed IP, given a nova.FloatingIP. 574 func (n *NeutronModel) UpdateNovaFloatingIP(fip *nova.FloatingIP) error { 575 n.rwMu.Lock() 576 defer n.rwMu.Unlock() 577 ip, ok := n.floatingIPs[fip.Id] 578 if !ok { 579 return testservices.NewFloatingIPNotFoundError(fip.Id) 580 } 581 if fip.FixedIP != nil { 582 ip.FixedIP = *fip.FixedIP 583 } 584 n.floatingIPs[fip.Id] = ip 585 return nil 586 } 587 588 // AllNetworks returns a list of all existing networks in neutron.NetworkV2. 589 func (n *NeutronModel) AllNetworks() (networks []neutron.NetworkV2) { 590 n.rwMu.RLock() 591 defer n.rwMu.RUnlock() 592 for _, net := range n.networks { 593 networks = append(networks, net) 594 } 595 return networks 596 } 597 598 // AllNovaNetworks returns of list of all existing networks in nova.Network form. 599 func (n *NeutronModel) AllNovaNetworks() (networks []nova.Network) { 600 neutronNetworks := n.AllNetworks() 601 var novaNetworks []nova.Network 602 for _, net := range neutronNetworks { 603 // copy Id and Name to new Nova Network, leave off Cidr for 604 // Neutron networking keeps Cidr in a subnet, not a network. 605 novaNetworks = append(novaNetworks, nova.Network{ 606 Id: net.Id, 607 Label: net.Name, 608 }) 609 } 610 return novaNetworks 611 } 612 613 // Network retrieves the network in Neutron Network form by ID. 614 func (n *NeutronModel) Network(networkId string) (*neutron.NetworkV2, error) { 615 if n.rwMu == nil { 616 n.rwMu.RLock() 617 defer n.rwMu.RUnlock() 618 } 619 network, ok := n.networks[networkId] 620 if !ok { 621 return nil, testservices.NewNetworkNotFoundError(networkId) 622 } 623 return &network, nil 624 } 625 626 // NovaNetwork retrieves the network in Nova Network form by ID. 627 func (n *NeutronModel) NovaNetwork(networkId string) (*nova.Network, error) { 628 neutronNet, err := n.Network(networkId) 629 if err != nil { 630 return nil, err 631 } 632 return &nova.Network{Id: neutronNet.Id, Label: neutronNet.Name}, nil 633 } 634 635 // AddNetwork creates a new network. 636 func (n *NeutronModel) AddNetwork(network neutron.NetworkV2) error { 637 n.rwMu.Lock() 638 defer n.rwMu.Unlock() 639 if _, err := n.Network(network.Id); err == nil { 640 return testservices.NewNetworkAlreadyExistsError(network.Id) 641 } 642 if network.SubnetIds == nil { 643 network.SubnetIds = []string{} 644 } 645 n.networks[network.Id] = network 646 return nil 647 } 648 649 // RemoveNetwork deletes an existing group. 650 func (n *NeutronModel) RemoveNetwork(netId string) error { 651 n.rwMu.Lock() 652 defer n.rwMu.Unlock() 653 if _, err := n.Network(netId); err != nil { 654 return err 655 } 656 delete(n.networks, netId) 657 return nil 658 } 659 660 // AddPort creates a new port given a neutron.PortV2. 661 func (n *NeutronModel) AddPort(port neutron.PortV2) error { 662 n.rwMu.Lock() 663 defer n.rwMu.Unlock() 664 if _, err := n.Port(port.Id); err == nil { 665 return testservices.NewPortAlreadyExistsError(port.Id) 666 } 667 668 n.ports[port.Id] = port 669 return nil 670 } 671 672 // Port retrieves an existing port by ID, data in neutron.PortV2 form. 673 func (n *NeutronModel) Port(portId string) (*neutron.PortV2, error) { 674 if n.rwMu == nil { 675 n.rwMu.RLock() 676 defer n.rwMu.RUnlock() 677 } 678 port, ok := n.ports[portId] 679 if !ok { 680 return nil, testservices.NewPortByIDNotFoundError(portId) 681 } 682 return &port, nil 683 } 684 685 // AllPorts returns a list of all existing ports, data in 686 // neutron.PortV2 form. 687 func (n *NeutronModel) AllPorts() []neutron.PortV2 { 688 n.rwMu.RLock() 689 defer n.rwMu.RUnlock() 690 var ports []neutron.PortV2 691 for _, port := range n.ports { 692 ports = append(ports, port) 693 } 694 return ports 695 } 696 697 // RemovePort deletes an existing group. 698 func (n *NeutronModel) RemovePort(portId string) error { 699 n.rwMu.Lock() 700 defer n.rwMu.Unlock() 701 if _, err := n.Port(portId); err != nil { 702 return err 703 } 704 delete(n.ports, portId) 705 return nil 706 }