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  }