github.com/gophercloud/gophercloud@v1.11.0/internal/acceptance/openstack/networking/v2/networking.go (about)

     1  package v2
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/gophercloud/gophercloud"
     8  	"github.com/gophercloud/gophercloud/internal/acceptance/tools"
     9  	"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/extradhcpopts"
    10  	"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity"
    11  	"github.com/gophercloud/gophercloud/openstack/networking/v2/networks"
    12  	"github.com/gophercloud/gophercloud/openstack/networking/v2/ports"
    13  	"github.com/gophercloud/gophercloud/openstack/networking/v2/subnets"
    14  	th "github.com/gophercloud/gophercloud/testhelper"
    15  )
    16  
    17  // PortWithExtraDHCPOpts represents a port with extra DHCP options configuration.
    18  type PortWithExtraDHCPOpts struct {
    19  	ports.Port
    20  	extradhcpopts.ExtraDHCPOptsExt
    21  }
    22  
    23  // CreateNetwork will create basic network. An error will be returned if the
    24  // network could not be created.
    25  func CreateNetwork(t *testing.T, client *gophercloud.ServiceClient) (*networks.Network, error) {
    26  	networkName := tools.RandomString("TESTACC-", 8)
    27  	networkDescription := tools.RandomString("TESTACC-DESC-", 8)
    28  	createOpts := networks.CreateOpts{
    29  		Name:         networkName,
    30  		Description:  networkDescription,
    31  		AdminStateUp: gophercloud.Enabled,
    32  	}
    33  
    34  	t.Logf("Attempting to create network: %s", networkName)
    35  
    36  	network, err := networks.Create(client, createOpts).Extract()
    37  	if err != nil {
    38  		return network, err
    39  	}
    40  
    41  	t.Logf("Successfully created network.")
    42  
    43  	th.AssertEquals(t, network.Name, networkName)
    44  	th.AssertEquals(t, network.Description, networkDescription)
    45  
    46  	return network, nil
    47  }
    48  
    49  // CreateNetworkWithoutPortSecurity will create a network without port security.
    50  // An error will be returned if the network could not be created.
    51  func CreateNetworkWithoutPortSecurity(t *testing.T, client *gophercloud.ServiceClient) (*networks.Network, error) {
    52  	networkName := tools.RandomString("TESTACC-", 8)
    53  	networkCreateOpts := networks.CreateOpts{
    54  		Name:         networkName,
    55  		AdminStateUp: gophercloud.Enabled,
    56  	}
    57  
    58  	iFalse := false
    59  	createOpts := portsecurity.NetworkCreateOptsExt{
    60  		CreateOptsBuilder:   networkCreateOpts,
    61  		PortSecurityEnabled: &iFalse,
    62  	}
    63  
    64  	t.Logf("Attempting to create network: %s", networkName)
    65  
    66  	network, err := networks.Create(client, createOpts).Extract()
    67  	if err != nil {
    68  		return network, err
    69  	}
    70  
    71  	t.Logf("Successfully created network.")
    72  
    73  	th.AssertEquals(t, network.Name, networkName)
    74  
    75  	return network, nil
    76  }
    77  
    78  // CreatePort will create a port on the specified subnet. An error will be
    79  // returned if the port could not be created.
    80  func CreatePort(t *testing.T, client *gophercloud.ServiceClient, networkID, subnetID string) (*ports.Port, error) {
    81  	portName := tools.RandomString("TESTACC-", 8)
    82  	portDescription := tools.RandomString("TESTACC-DESC-", 8)
    83  
    84  	t.Logf("Attempting to create port: %s", portName)
    85  
    86  	createOpts := ports.CreateOpts{
    87  		NetworkID:    networkID,
    88  		Name:         portName,
    89  		Description:  portDescription,
    90  		AdminStateUp: gophercloud.Enabled,
    91  		FixedIPs:     []ports.IP{{SubnetID: subnetID}},
    92  	}
    93  
    94  	port, err := ports.Create(client, createOpts).Extract()
    95  	if err != nil {
    96  		return port, err
    97  	}
    98  
    99  	if err := WaitForPortToCreate(client, port.ID); err != nil {
   100  		return port, err
   101  	}
   102  
   103  	newPort, err := ports.Get(client, port.ID).Extract()
   104  	if err != nil {
   105  		return newPort, err
   106  	}
   107  
   108  	t.Logf("Successfully created port: %s", portName)
   109  
   110  	th.AssertEquals(t, port.Name, portName)
   111  	th.AssertEquals(t, port.Description, portDescription)
   112  
   113  	return newPort, nil
   114  }
   115  
   116  // CreatePortWithNoSecurityGroup will create a port with no security group
   117  // attached. An error will be returned if the port could not be created.
   118  func CreatePortWithNoSecurityGroup(t *testing.T, client *gophercloud.ServiceClient, networkID, subnetID string) (*ports.Port, error) {
   119  	portName := tools.RandomString("TESTACC-", 8)
   120  	iFalse := false
   121  
   122  	t.Logf("Attempting to create port: %s", portName)
   123  
   124  	createOpts := ports.CreateOpts{
   125  		NetworkID:      networkID,
   126  		Name:           portName,
   127  		AdminStateUp:   &iFalse,
   128  		FixedIPs:       []ports.IP{{SubnetID: subnetID}},
   129  		SecurityGroups: &[]string{},
   130  	}
   131  
   132  	port, err := ports.Create(client, createOpts).Extract()
   133  	if err != nil {
   134  		return port, err
   135  	}
   136  
   137  	if err := WaitForPortToCreate(client, port.ID); err != nil {
   138  		return port, err
   139  	}
   140  
   141  	newPort, err := ports.Get(client, port.ID).Extract()
   142  	if err != nil {
   143  		return newPort, err
   144  	}
   145  
   146  	t.Logf("Successfully created port: %s", portName)
   147  
   148  	th.AssertEquals(t, port.Name, portName)
   149  
   150  	return newPort, nil
   151  }
   152  
   153  // CreatePortWithoutPortSecurity will create a port without port security on the
   154  // specified subnet. An error will be returned if the port could not be created.
   155  func CreatePortWithoutPortSecurity(t *testing.T, client *gophercloud.ServiceClient, networkID, subnetID string) (*ports.Port, error) {
   156  	portName := tools.RandomString("TESTACC-", 8)
   157  
   158  	t.Logf("Attempting to create port: %s", portName)
   159  
   160  	portCreateOpts := ports.CreateOpts{
   161  		NetworkID:    networkID,
   162  		Name:         portName,
   163  		AdminStateUp: gophercloud.Enabled,
   164  		FixedIPs:     []ports.IP{{SubnetID: subnetID}},
   165  	}
   166  
   167  	iFalse := false
   168  	createOpts := portsecurity.PortCreateOptsExt{
   169  		CreateOptsBuilder:   portCreateOpts,
   170  		PortSecurityEnabled: &iFalse,
   171  	}
   172  
   173  	port, err := ports.Create(client, createOpts).Extract()
   174  	if err != nil {
   175  		return port, err
   176  	}
   177  
   178  	if err := WaitForPortToCreate(client, port.ID); err != nil {
   179  		return port, err
   180  	}
   181  
   182  	newPort, err := ports.Get(client, port.ID).Extract()
   183  	if err != nil {
   184  		return newPort, err
   185  	}
   186  
   187  	t.Logf("Successfully created port: %s", portName)
   188  
   189  	th.AssertEquals(t, port.Name, portName)
   190  
   191  	return newPort, nil
   192  }
   193  
   194  // CreatePortWithExtraDHCPOpts will create a port with DHCP options on the
   195  // specified subnet. An error will be returned if the port could not be created.
   196  func CreatePortWithExtraDHCPOpts(t *testing.T, client *gophercloud.ServiceClient, networkID, subnetID string) (*PortWithExtraDHCPOpts, error) {
   197  	portName := tools.RandomString("TESTACC-", 8)
   198  
   199  	t.Logf("Attempting to create port: %s", portName)
   200  
   201  	portCreateOpts := ports.CreateOpts{
   202  		NetworkID:    networkID,
   203  		Name:         portName,
   204  		AdminStateUp: gophercloud.Enabled,
   205  		FixedIPs:     []ports.IP{{SubnetID: subnetID}},
   206  	}
   207  
   208  	createOpts := extradhcpopts.CreateOptsExt{
   209  		CreateOptsBuilder: portCreateOpts,
   210  		ExtraDHCPOpts: []extradhcpopts.CreateExtraDHCPOpt{
   211  			{
   212  				OptName:  "test_option_1",
   213  				OptValue: "test_value_1",
   214  			},
   215  		},
   216  	}
   217  	port := &PortWithExtraDHCPOpts{}
   218  
   219  	err := ports.Create(client, createOpts).ExtractInto(port)
   220  	if err != nil {
   221  		return nil, err
   222  	}
   223  
   224  	if err := WaitForPortToCreate(client, port.ID); err != nil {
   225  		return nil, err
   226  	}
   227  
   228  	err = ports.Get(client, port.ID).ExtractInto(port)
   229  	if err != nil {
   230  		return port, err
   231  	}
   232  
   233  	t.Logf("Successfully created port: %s", portName)
   234  
   235  	return port, nil
   236  }
   237  
   238  // CreatePortWithMultipleFixedIPs will create a port with two FixedIPs on the
   239  // specified subnet. An error will be returned if the port could not be created.
   240  func CreatePortWithMultipleFixedIPs(t *testing.T, client *gophercloud.ServiceClient, networkID, subnetID string) (*ports.Port, error) {
   241  	portName := tools.RandomString("TESTACC-", 8)
   242  	portDescription := tools.RandomString("TESTACC-DESC-", 8)
   243  
   244  	t.Logf("Attempting to create port with two fixed IPs: %s", portName)
   245  
   246  	createOpts := ports.CreateOpts{
   247  		NetworkID:    networkID,
   248  		Name:         portName,
   249  		Description:  portDescription,
   250  		AdminStateUp: gophercloud.Enabled,
   251  		FixedIPs:     []ports.IP{{SubnetID: subnetID}, {SubnetID: subnetID}},
   252  	}
   253  
   254  	port, err := ports.Create(client, createOpts).Extract()
   255  	if err != nil {
   256  		return port, err
   257  	}
   258  
   259  	if err := WaitForPortToCreate(client, port.ID); err != nil {
   260  		return port, err
   261  	}
   262  
   263  	newPort, err := ports.Get(client, port.ID).Extract()
   264  	if err != nil {
   265  		return newPort, err
   266  	}
   267  
   268  	t.Logf("Successfully created port: %s", portName)
   269  
   270  	th.AssertEquals(t, port.Name, portName)
   271  	th.AssertEquals(t, port.Description, portDescription)
   272  
   273  	if len(port.FixedIPs) != 2 {
   274  		t.Fatalf("Failed to create a port with two fixed IPs: %s", portName)
   275  	}
   276  
   277  	return newPort, nil
   278  }
   279  
   280  // CreateSubnet will create a subnet on the specified Network ID. An error
   281  // will be returned if the subnet could not be created.
   282  func CreateSubnet(t *testing.T, client *gophercloud.ServiceClient, networkID string) (*subnets.Subnet, error) {
   283  	subnetName := tools.RandomString("TESTACC-", 8)
   284  	subnetDescription := tools.RandomString("TESTACC-DESC-", 8)
   285  	subnetOctet := tools.RandomInt(1, 250)
   286  	subnetCIDR := fmt.Sprintf("192.168.%d.0/24", subnetOctet)
   287  	subnetGateway := fmt.Sprintf("192.168.%d.1", subnetOctet)
   288  	createOpts := subnets.CreateOpts{
   289  		NetworkID:   networkID,
   290  		CIDR:        subnetCIDR,
   291  		IPVersion:   4,
   292  		Name:        subnetName,
   293  		Description: subnetDescription,
   294  		EnableDHCP:  gophercloud.Disabled,
   295  		GatewayIP:   &subnetGateway,
   296  	}
   297  
   298  	t.Logf("Attempting to create subnet: %s", subnetName)
   299  
   300  	subnet, err := subnets.Create(client, createOpts).Extract()
   301  	if err != nil {
   302  		return subnet, err
   303  	}
   304  
   305  	t.Logf("Successfully created subnet.")
   306  
   307  	th.AssertEquals(t, subnet.Name, subnetName)
   308  	th.AssertEquals(t, subnet.Description, subnetDescription)
   309  	th.AssertEquals(t, subnet.GatewayIP, subnetGateway)
   310  	th.AssertEquals(t, subnet.CIDR, subnetCIDR)
   311  
   312  	return subnet, nil
   313  }
   314  
   315  // CreateSubnet will create a subnet on the specified Network ID and service types.
   316  //
   317  //	An error will be returned if the subnet could not be created.
   318  func CreateSubnetWithServiceTypes(t *testing.T, client *gophercloud.ServiceClient, networkID string) (*subnets.Subnet, error) {
   319  	subnetName := tools.RandomString("TESTACC-", 8)
   320  	subnetDescription := tools.RandomString("TESTACC-DESC-", 8)
   321  	subnetOctet := tools.RandomInt(1, 250)
   322  	subnetCIDR := fmt.Sprintf("192.168.%d.0/24", subnetOctet)
   323  	subnetGateway := fmt.Sprintf("192.168.%d.1", subnetOctet)
   324  	serviceTypes := []string{"network:routed"}
   325  	createOpts := subnets.CreateOpts{
   326  		NetworkID:    networkID,
   327  		CIDR:         subnetCIDR,
   328  		IPVersion:    4,
   329  		Name:         subnetName,
   330  		Description:  subnetDescription,
   331  		EnableDHCP:   gophercloud.Disabled,
   332  		GatewayIP:    &subnetGateway,
   333  		ServiceTypes: serviceTypes,
   334  	}
   335  
   336  	t.Logf("Attempting to create subnet: %s", subnetName)
   337  
   338  	subnet, err := subnets.Create(client, createOpts).Extract()
   339  	if err != nil {
   340  		return subnet, err
   341  	}
   342  
   343  	t.Logf("Successfully created subnet.")
   344  
   345  	th.AssertEquals(t, subnet.Name, subnetName)
   346  	th.AssertEquals(t, subnet.Description, subnetDescription)
   347  	th.AssertEquals(t, subnet.GatewayIP, subnetGateway)
   348  	th.AssertEquals(t, subnet.CIDR, subnetCIDR)
   349  	th.AssertDeepEquals(t, subnet.ServiceTypes, serviceTypes)
   350  
   351  	return subnet, nil
   352  }
   353  
   354  // CreateSubnetWithDefaultGateway will create a subnet on the specified Network
   355  // ID and have Neutron set the gateway by default An error will be returned if
   356  // the subnet could not be created.
   357  func CreateSubnetWithDefaultGateway(t *testing.T, client *gophercloud.ServiceClient, networkID string) (*subnets.Subnet, error) {
   358  	subnetName := tools.RandomString("TESTACC-", 8)
   359  	subnetOctet := tools.RandomInt(1, 250)
   360  	subnetCIDR := fmt.Sprintf("192.168.%d.0/24", subnetOctet)
   361  	defaultGateway := fmt.Sprintf("192.168.%d.1", subnetOctet)
   362  
   363  	createOpts := subnets.CreateOpts{
   364  		NetworkID:  networkID,
   365  		CIDR:       subnetCIDR,
   366  		IPVersion:  4,
   367  		Name:       subnetName,
   368  		EnableDHCP: gophercloud.Disabled,
   369  	}
   370  
   371  	t.Logf("Attempting to create subnet: %s", subnetName)
   372  
   373  	subnet, err := subnets.Create(client, createOpts).Extract()
   374  	if err != nil {
   375  		return subnet, err
   376  	}
   377  
   378  	t.Logf("Successfully created subnet.")
   379  
   380  	th.AssertEquals(t, subnet.Name, subnetName)
   381  	th.AssertEquals(t, subnet.GatewayIP, defaultGateway)
   382  	th.AssertEquals(t, subnet.CIDR, subnetCIDR)
   383  
   384  	return subnet, nil
   385  }
   386  
   387  // CreateSubnetWithNoGateway will create a subnet with no gateway on the
   388  // specified Network ID.  An error will be returned if the subnet could not be
   389  // created.
   390  func CreateSubnetWithNoGateway(t *testing.T, client *gophercloud.ServiceClient, networkID string) (*subnets.Subnet, error) {
   391  	var noGateway = ""
   392  	subnetName := tools.RandomString("TESTACC-", 8)
   393  	subnetOctet := tools.RandomInt(1, 250)
   394  	subnetCIDR := fmt.Sprintf("192.168.%d.0/24", subnetOctet)
   395  	dhcpStart := fmt.Sprintf("192.168.%d.10", subnetOctet)
   396  	dhcpEnd := fmt.Sprintf("192.168.%d.200", subnetOctet)
   397  	createOpts := subnets.CreateOpts{
   398  		NetworkID:  networkID,
   399  		CIDR:       subnetCIDR,
   400  		IPVersion:  4,
   401  		Name:       subnetName,
   402  		EnableDHCP: gophercloud.Disabled,
   403  		GatewayIP:  &noGateway,
   404  		AllocationPools: []subnets.AllocationPool{
   405  			{
   406  				Start: dhcpStart,
   407  				End:   dhcpEnd,
   408  			},
   409  		},
   410  	}
   411  
   412  	t.Logf("Attempting to create subnet: %s", subnetName)
   413  
   414  	subnet, err := subnets.Create(client, createOpts).Extract()
   415  	if err != nil {
   416  		return subnet, err
   417  	}
   418  
   419  	t.Logf("Successfully created subnet.")
   420  
   421  	th.AssertEquals(t, subnet.Name, subnetName)
   422  	th.AssertEquals(t, subnet.GatewayIP, "")
   423  	th.AssertEquals(t, subnet.CIDR, subnetCIDR)
   424  
   425  	return subnet, nil
   426  }
   427  
   428  // CreateSubnetWithSubnetPool will create a subnet associated with the provided subnetpool on the specified Network ID.
   429  // An error will be returned if the subnet or the subnetpool could not be created.
   430  func CreateSubnetWithSubnetPool(t *testing.T, client *gophercloud.ServiceClient, networkID string, subnetPoolID string) (*subnets.Subnet, error) {
   431  	subnetName := tools.RandomString("TESTACC-", 8)
   432  	subnetOctet := tools.RandomInt(1, 250)
   433  	subnetCIDR := fmt.Sprintf("10.%d.0.0/24", subnetOctet)
   434  	createOpts := subnets.CreateOpts{
   435  		NetworkID:    networkID,
   436  		CIDR:         subnetCIDR,
   437  		IPVersion:    4,
   438  		Name:         subnetName,
   439  		EnableDHCP:   gophercloud.Disabled,
   440  		SubnetPoolID: subnetPoolID,
   441  	}
   442  
   443  	t.Logf("Attempting to create subnet: %s", subnetName)
   444  
   445  	subnet, err := subnets.Create(client, createOpts).Extract()
   446  	if err != nil {
   447  		return subnet, err
   448  	}
   449  
   450  	t.Logf("Successfully created subnet.")
   451  
   452  	th.AssertEquals(t, subnet.Name, subnetName)
   453  	th.AssertEquals(t, subnet.CIDR, subnetCIDR)
   454  
   455  	return subnet, nil
   456  }
   457  
   458  // CreateSubnetWithSubnetPoolNoCIDR will create a subnet associated with the
   459  // provided subnetpool on the specified Network ID.
   460  // An error will be returned if the subnet or the subnetpool could not be created.
   461  func CreateSubnetWithSubnetPoolNoCIDR(t *testing.T, client *gophercloud.ServiceClient, networkID string, subnetPoolID string) (*subnets.Subnet, error) {
   462  	subnetName := tools.RandomString("TESTACC-", 8)
   463  	createOpts := subnets.CreateOpts{
   464  		NetworkID:    networkID,
   465  		IPVersion:    4,
   466  		Name:         subnetName,
   467  		EnableDHCP:   gophercloud.Disabled,
   468  		SubnetPoolID: subnetPoolID,
   469  	}
   470  
   471  	t.Logf("Attempting to create subnet: %s", subnetName)
   472  
   473  	subnet, err := subnets.Create(client, createOpts).Extract()
   474  	if err != nil {
   475  		return subnet, err
   476  	}
   477  
   478  	t.Logf("Successfully created subnet.")
   479  
   480  	th.AssertEquals(t, subnet.Name, subnetName)
   481  
   482  	return subnet, nil
   483  }
   484  
   485  // CreateSubnetWithSubnetPoolPrefixlen will create a subnet associated with the
   486  // provided subnetpool on the specified Network ID and with overwritten
   487  // prefixlen instead of the default subnetpool prefixlen.
   488  // An error will be returned if the subnet or the subnetpool could not be created.
   489  func CreateSubnetWithSubnetPoolPrefixlen(t *testing.T, client *gophercloud.ServiceClient, networkID string, subnetPoolID string) (*subnets.Subnet, error) {
   490  	subnetName := tools.RandomString("TESTACC-", 8)
   491  	createOpts := subnets.CreateOpts{
   492  		NetworkID:    networkID,
   493  		IPVersion:    4,
   494  		Name:         subnetName,
   495  		EnableDHCP:   gophercloud.Disabled,
   496  		SubnetPoolID: subnetPoolID,
   497  		Prefixlen:    12,
   498  	}
   499  
   500  	t.Logf("Attempting to create subnet: %s", subnetName)
   501  
   502  	subnet, err := subnets.Create(client, createOpts).Extract()
   503  	if err != nil {
   504  		return subnet, err
   505  	}
   506  
   507  	t.Logf("Successfully created subnet.")
   508  
   509  	th.AssertEquals(t, subnet.Name, subnetName)
   510  
   511  	return subnet, nil
   512  }
   513  
   514  // DeleteNetwork will delete a network with a specified ID. A fatal error will
   515  // occur if the delete was not successful. This works best when used as a
   516  // deferred function.
   517  func DeleteNetwork(t *testing.T, client *gophercloud.ServiceClient, networkID string) {
   518  	t.Logf("Attempting to delete network: %s", networkID)
   519  
   520  	err := networks.Delete(client, networkID).ExtractErr()
   521  	if err != nil {
   522  		t.Fatalf("Unable to delete network %s: %v", networkID, err)
   523  	}
   524  
   525  	t.Logf("Deleted network: %s", networkID)
   526  }
   527  
   528  // DeletePort will delete a port with a specified ID. A fatal error will
   529  // occur if the delete was not successful. This works best when used as a
   530  // deferred function.
   531  func DeletePort(t *testing.T, client *gophercloud.ServiceClient, portID string) {
   532  	t.Logf("Attempting to delete port: %s", portID)
   533  
   534  	err := ports.Delete(client, portID).ExtractErr()
   535  	if err != nil {
   536  		t.Fatalf("Unable to delete port %s: %v", portID, err)
   537  	}
   538  
   539  	t.Logf("Deleted port: %s", portID)
   540  }
   541  
   542  // DeleteSubnet will delete a subnet with a specified ID. A fatal error will
   543  // occur if the delete was not successful. This works best when used as a
   544  // deferred function.
   545  func DeleteSubnet(t *testing.T, client *gophercloud.ServiceClient, subnetID string) {
   546  	t.Logf("Attempting to delete subnet: %s", subnetID)
   547  
   548  	err := subnets.Delete(client, subnetID).ExtractErr()
   549  	if err != nil {
   550  		t.Fatalf("Unable to delete subnet %s: %v", subnetID, err)
   551  	}
   552  
   553  	t.Logf("Deleted subnet: %s", subnetID)
   554  }
   555  
   556  func WaitForPortToCreate(client *gophercloud.ServiceClient, portID string) error {
   557  	return tools.WaitFor(func() (bool, error) {
   558  		p, err := ports.Get(client, portID).Extract()
   559  		if err != nil {
   560  			return false, err
   561  		}
   562  
   563  		if p.Status == "ACTIVE" || p.Status == "DOWN" {
   564  			return true, nil
   565  		}
   566  
   567  		return false, nil
   568  	})
   569  }
   570  
   571  // This is duplicated from https://github.com/gophercloud/utils
   572  // so that Gophercloud "core" doesn't have a dependency on the
   573  // complementary utils repository.
   574  func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
   575  	count := 0
   576  	id := ""
   577  
   578  	listOpts := networks.ListOpts{
   579  		Name: name,
   580  	}
   581  
   582  	pages, err := networks.List(client, listOpts).AllPages()
   583  	if err != nil {
   584  		return "", err
   585  	}
   586  
   587  	all, err := networks.ExtractNetworks(pages)
   588  	if err != nil {
   589  		return "", err
   590  	}
   591  
   592  	for _, s := range all {
   593  		if s.Name == name {
   594  			count++
   595  			id = s.ID
   596  		}
   597  	}
   598  
   599  	switch count {
   600  	case 0:
   601  		return "", gophercloud.ErrResourceNotFound{Name: name, ResourceType: "network"}
   602  	case 1:
   603  		return id, nil
   604  	default:
   605  		return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "network"}
   606  	}
   607  }