github.com/vnpaycloud-console/gophercloud/v2@v2.0.5/internal/acceptance/openstack/networking/v2/extensions/layer3/layer3.go (about)

     1  package layer3
     2  
     3  import (
     4  	"context"
     5  	"net/http"
     6  	"testing"
     7  
     8  	"github.com/vnpaycloud-console/gophercloud/v2/openstack/networking/v2/extensions/layer3/addressscopes"
     9  
    10  	"github.com/vnpaycloud-console/gophercloud/v2"
    11  	"github.com/vnpaycloud-console/gophercloud/v2/internal/acceptance/clients"
    12  	"github.com/vnpaycloud-console/gophercloud/v2/internal/acceptance/tools"
    13  	"github.com/vnpaycloud-console/gophercloud/v2/openstack/networking/v2/extensions/layer3/floatingips"
    14  	"github.com/vnpaycloud-console/gophercloud/v2/openstack/networking/v2/extensions/layer3/portforwarding"
    15  
    16  	"github.com/vnpaycloud-console/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers"
    17  	"github.com/vnpaycloud-console/gophercloud/v2/openstack/networking/v2/ports"
    18  	th "github.com/vnpaycloud-console/gophercloud/v2/testhelper"
    19  )
    20  
    21  // CreateFloatingIP creates a floating IP on a given network and port. An error
    22  // will be returned if the creation failed.
    23  func CreateFloatingIP(t *testing.T, client *gophercloud.ServiceClient, networkID, portID string) (*floatingips.FloatingIP, error) {
    24  	t.Logf("Attempting to create floating IP on port: %s", portID)
    25  
    26  	fipDescription := "Test floating IP"
    27  	createOpts := &floatingips.CreateOpts{
    28  		Description:       fipDescription,
    29  		FloatingNetworkID: networkID,
    30  		PortID:            portID,
    31  	}
    32  
    33  	floatingIP, err := floatingips.Create(context.TODO(), client, createOpts).Extract()
    34  	if err != nil {
    35  		return floatingIP, err
    36  	}
    37  
    38  	t.Logf("Created floating IP.")
    39  
    40  	th.AssertEquals(t, floatingIP.Description, fipDescription)
    41  
    42  	return floatingIP, err
    43  }
    44  
    45  // CreateFloatingIPWithFixedIP creates a floating IP on a given network and port with a
    46  // defined fixed IP. An error will be returned if the creation failed.
    47  func CreateFloatingIPWithFixedIP(t *testing.T, client *gophercloud.ServiceClient, networkID, portID, fixedIP string) (*floatingips.FloatingIP, error) {
    48  	t.Logf("Attempting to create floating IP on port: %s and address: %s", portID, fixedIP)
    49  
    50  	fipDescription := "Test floating IP"
    51  	createOpts := &floatingips.CreateOpts{
    52  		Description:       fipDescription,
    53  		FloatingNetworkID: networkID,
    54  		PortID:            portID,
    55  		FixedIP:           fixedIP,
    56  	}
    57  
    58  	floatingIP, err := floatingips.Create(context.TODO(), client, createOpts).Extract()
    59  	if err != nil {
    60  		return floatingIP, err
    61  	}
    62  
    63  	t.Logf("Created floating IP.")
    64  
    65  	th.AssertEquals(t, floatingIP.Description, fipDescription)
    66  	th.AssertEquals(t, floatingIP.FixedIP, fixedIP)
    67  
    68  	return floatingIP, err
    69  }
    70  
    71  // CreatePortForwarding creates a port forwarding for a given floating IP
    72  // and port. An error will be returned if the creation failed.
    73  func CreatePortForwarding(t *testing.T, client *gophercloud.ServiceClient, fipID string, portID string, portFixedIPs []ports.IP) (*portforwarding.PortForwarding, error) {
    74  	t.Logf("Attempting to create Port forwarding for floating IP with ID: %s", fipID)
    75  
    76  	fixedIP := portFixedIPs[0]
    77  	internalIP := fixedIP.IPAddress
    78  	pfDescription := "Test description"
    79  	createOpts := &portforwarding.CreateOpts{
    80  		Description:       pfDescription,
    81  		Protocol:          "tcp",
    82  		InternalPort:      25,
    83  		ExternalPort:      2230,
    84  		InternalIPAddress: internalIP,
    85  		InternalPortID:    portID,
    86  	}
    87  
    88  	pf, err := portforwarding.Create(context.TODO(), client, fipID, createOpts).Extract()
    89  	if err != nil {
    90  		return pf, err
    91  	}
    92  
    93  	t.Logf("Created Port Forwarding.")
    94  
    95  	th.AssertEquals(t, pf.Protocol, "tcp")
    96  
    97  	return pf, err
    98  }
    99  
   100  // DeletePortForwarding deletes a Port Forwarding with a given ID and a given floating IP ID.
   101  // A fatal error is returned if the deletion fails. Works best as a deferred function
   102  func DeletePortForwarding(t *testing.T, client *gophercloud.ServiceClient, fipID string, pfID string) {
   103  	t.Logf("Attempting to delete the port forwarding with ID %s for floating IP with ID %s", pfID, fipID)
   104  
   105  	err := portforwarding.Delete(context.TODO(), client, fipID, pfID).ExtractErr()
   106  	if err != nil {
   107  		t.Fatalf("Failed to delete Port forwarding with ID %s for floating IP with ID %s", pfID, fipID)
   108  	}
   109  	t.Logf("Successfully deleted the port forwarding with ID %s for floating IP with ID %s", pfID, fipID)
   110  
   111  }
   112  
   113  // CreateExternalRouter creates a router on the external network. This requires
   114  // the OS_EXTGW_ID environment variable to be set. An error is returned if the
   115  // creation failed.
   116  func CreateExternalRouter(t *testing.T, client *gophercloud.ServiceClient) (*routers.Router, error) {
   117  	var router *routers.Router
   118  	choices, err := clients.AcceptanceTestChoicesFromEnv()
   119  	if err != nil {
   120  		return router, err
   121  	}
   122  
   123  	routerName := tools.RandomString("TESTACC-", 8)
   124  	routerDescription := tools.RandomString("TESTACC-DESC-", 8)
   125  
   126  	t.Logf("Attempting to create external router: %s", routerName)
   127  
   128  	adminStateUp := true
   129  	gatewayInfo := routers.GatewayInfo{
   130  		NetworkID: choices.ExternalNetworkID,
   131  	}
   132  
   133  	createOpts := routers.CreateOpts{
   134  		Name:         routerName,
   135  		Description:  routerDescription,
   136  		AdminStateUp: &adminStateUp,
   137  		GatewayInfo:  &gatewayInfo,
   138  	}
   139  
   140  	router, err = routers.Create(context.TODO(), client, createOpts).Extract()
   141  	if err != nil {
   142  		return router, err
   143  	}
   144  
   145  	if err := WaitForRouterToCreate(client, router.ID); err != nil {
   146  		return router, err
   147  	}
   148  
   149  	t.Logf("Created router: %s", routerName)
   150  
   151  	th.AssertEquals(t, router.Name, routerName)
   152  	th.AssertEquals(t, router.Description, routerDescription)
   153  
   154  	return router, nil
   155  }
   156  
   157  // CreateRouter creates a router on a specified Network ID. An error will be
   158  // returned if the creation failed.
   159  func CreateRouter(t *testing.T, client *gophercloud.ServiceClient, networkID string) (*routers.Router, error) {
   160  	routerName := tools.RandomString("TESTACC-", 8)
   161  	routerDescription := tools.RandomString("TESTACC-DESC-", 8)
   162  
   163  	t.Logf("Attempting to create router: %s", routerName)
   164  
   165  	adminStateUp := true
   166  	createOpts := routers.CreateOpts{
   167  		Name:         routerName,
   168  		Description:  routerDescription,
   169  		AdminStateUp: &adminStateUp,
   170  	}
   171  
   172  	router, err := routers.Create(context.TODO(), client, createOpts).Extract()
   173  	if err != nil {
   174  		return router, err
   175  	}
   176  
   177  	if err := WaitForRouterToCreate(client, router.ID); err != nil {
   178  		return router, err
   179  	}
   180  
   181  	t.Logf("Created router: %s", routerName)
   182  
   183  	th.AssertEquals(t, router.Name, routerName)
   184  	th.AssertEquals(t, router.Description, routerDescription)
   185  
   186  	return router, nil
   187  }
   188  
   189  // CreateRouterInterface will attach a subnet to a router. An error will be
   190  // returned if the operation fails.
   191  func CreateRouterInterface(t *testing.T, client *gophercloud.ServiceClient, portID, routerID string) (*routers.InterfaceInfo, error) {
   192  	t.Logf("Attempting to add port %s to router %s", portID, routerID)
   193  
   194  	aiOpts := routers.AddInterfaceOpts{
   195  		PortID: portID,
   196  	}
   197  
   198  	iface, err := routers.AddInterface(context.TODO(), client, routerID, aiOpts).Extract()
   199  	if err != nil {
   200  		return iface, err
   201  	}
   202  
   203  	if err := WaitForRouterInterfaceToAttach(client, portID); err != nil {
   204  		return iface, err
   205  	}
   206  
   207  	t.Logf("Successfully added port %s to router %s", portID, routerID)
   208  	return iface, nil
   209  }
   210  
   211  // CreateRouterInterfaceOnSubnet will attach a subnet to a router. An error will be
   212  // returned if the operation fails.
   213  func CreateRouterInterfaceOnSubnet(t *testing.T, client *gophercloud.ServiceClient, subnetID, routerID string) (*routers.InterfaceInfo, error) {
   214  	t.Logf("Attempting to add subnet %s to router %s", subnetID, routerID)
   215  
   216  	aiOpts := routers.AddInterfaceOpts{
   217  		SubnetID: subnetID,
   218  	}
   219  
   220  	iface, err := routers.AddInterface(context.TODO(), client, routerID, aiOpts).Extract()
   221  	if err != nil {
   222  		return iface, err
   223  	}
   224  
   225  	if err := WaitForRouterInterfaceToAttach(client, iface.PortID); err != nil {
   226  		return iface, err
   227  	}
   228  
   229  	t.Logf("Successfully added subnet %s to router %s", subnetID, routerID)
   230  	return iface, nil
   231  }
   232  
   233  // DeleteRouter deletes a router of a specified ID. A fatal error will occur
   234  // if the deletion failed. This works best when used as a deferred function.
   235  func DeleteRouter(t *testing.T, client *gophercloud.ServiceClient, routerID string) {
   236  	t.Logf("Attempting to delete router: %s", routerID)
   237  
   238  	err := routers.Delete(context.TODO(), client, routerID).ExtractErr()
   239  	if err != nil {
   240  		t.Fatalf("Error deleting router: %v", err)
   241  	}
   242  
   243  	if err := WaitForRouterToDelete(client, routerID); err != nil {
   244  		t.Fatalf("Error waiting for router to delete: %v", err)
   245  	}
   246  
   247  	t.Logf("Deleted router: %s", routerID)
   248  }
   249  
   250  // DeleteRouterInterface will detach a subnet to a router. A fatal error will
   251  // occur if the deletion failed. This works best when used as a deferred
   252  // function.
   253  func DeleteRouterInterface(t *testing.T, client *gophercloud.ServiceClient, portID, routerID string) {
   254  	t.Logf("Attempting to detach port %s from router %s", portID, routerID)
   255  
   256  	riOpts := routers.RemoveInterfaceOpts{
   257  		PortID: portID,
   258  	}
   259  
   260  	_, err := routers.RemoveInterface(context.TODO(), client, routerID, riOpts).Extract()
   261  	if err != nil {
   262  		t.Fatalf("Failed to detach port %s from router %s", portID, routerID)
   263  	}
   264  
   265  	if err := WaitForRouterInterfaceToDetach(client, portID); err != nil {
   266  		t.Fatalf("Failed to wait for port %s to detach from router %s", portID, routerID)
   267  	}
   268  
   269  	t.Logf("Successfully detached port %s from router %s", portID, routerID)
   270  }
   271  
   272  // DeleteFloatingIP deletes a floatingIP of a specified ID. A fatal error will
   273  // occur if the deletion failed. This works best when used as a deferred
   274  // function.
   275  func DeleteFloatingIP(t *testing.T, client *gophercloud.ServiceClient, floatingIPID string) {
   276  	t.Logf("Attempting to delete floating IP: %s", floatingIPID)
   277  
   278  	err := floatingips.Delete(context.TODO(), client, floatingIPID).ExtractErr()
   279  	if err != nil {
   280  		t.Fatalf("Failed to delete floating IP: %v", err)
   281  	}
   282  
   283  	t.Logf("Deleted floating IP: %s", floatingIPID)
   284  }
   285  
   286  func WaitForRouterToCreate(client *gophercloud.ServiceClient, routerID string) error {
   287  	return tools.WaitFor(func(ctx context.Context) (bool, error) {
   288  		r, err := routers.Get(ctx, client, routerID).Extract()
   289  		if err != nil {
   290  			return false, err
   291  		}
   292  
   293  		if r.Status == "ACTIVE" {
   294  			return true, nil
   295  		}
   296  
   297  		return false, nil
   298  	})
   299  }
   300  
   301  func WaitForRouterToDelete(client *gophercloud.ServiceClient, routerID string) error {
   302  	return tools.WaitFor(func(ctx context.Context) (bool, error) {
   303  		_, err := routers.Get(ctx, client, routerID).Extract()
   304  		if err != nil {
   305  			if gophercloud.ResponseCodeIs(err, http.StatusNotFound) {
   306  				return true, nil
   307  			}
   308  
   309  			return false, err
   310  		}
   311  
   312  		return false, nil
   313  	})
   314  }
   315  
   316  func WaitForRouterInterfaceToAttach(client *gophercloud.ServiceClient, routerInterfaceID string) error {
   317  	return tools.WaitFor(func(ctx context.Context) (bool, error) {
   318  		r, err := ports.Get(ctx, client, routerInterfaceID).Extract()
   319  		if err != nil {
   320  			return false, err
   321  		}
   322  
   323  		if r.Status == "ACTIVE" {
   324  			return true, nil
   325  		}
   326  
   327  		return false, nil
   328  	})
   329  }
   330  
   331  func WaitForRouterInterfaceToDetach(client *gophercloud.ServiceClient, routerInterfaceID string) error {
   332  	return tools.WaitFor(func(ctx context.Context) (bool, error) {
   333  		r, err := ports.Get(ctx, client, routerInterfaceID).Extract()
   334  		if err != nil {
   335  			if gophercloud.ResponseCodeIs(err, http.StatusNotFound) {
   336  				return true, nil
   337  			}
   338  
   339  			if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok {
   340  				if errCode.Actual == 409 {
   341  					return false, nil
   342  				}
   343  			}
   344  
   345  			return false, err
   346  		}
   347  
   348  		if r.Status == "ACTIVE" {
   349  			return true, nil
   350  		}
   351  
   352  		return false, nil
   353  	})
   354  }
   355  
   356  // CreateAddressScope will create an address-scope. An error will be returned if
   357  // the address-scope could not be created.
   358  func CreateAddressScope(t *testing.T, client *gophercloud.ServiceClient) (*addressscopes.AddressScope, error) {
   359  	addressScopeName := tools.RandomString("TESTACC-", 8)
   360  	createOpts := addressscopes.CreateOpts{
   361  		Name:      addressScopeName,
   362  		IPVersion: 4,
   363  	}
   364  
   365  	t.Logf("Attempting to create an address-scope: %s", addressScopeName)
   366  
   367  	addressScope, err := addressscopes.Create(context.TODO(), client, createOpts).Extract()
   368  	if err != nil {
   369  		return nil, err
   370  	}
   371  
   372  	t.Logf("Successfully created the addressscopes.")
   373  
   374  	th.AssertEquals(t, addressScope.Name, addressScopeName)
   375  	th.AssertEquals(t, addressScope.IPVersion, int(gophercloud.IPv4))
   376  
   377  	return addressScope, nil
   378  }
   379  
   380  // DeleteAddressScope will delete an address-scope with the specified ID.
   381  // A fatal error will occur if the delete was not successful.
   382  func DeleteAddressScope(t *testing.T, client *gophercloud.ServiceClient, addressScopeID string) {
   383  	t.Logf("Attempting to delete the address-scope: %s", addressScopeID)
   384  
   385  	err := addressscopes.Delete(context.TODO(), client, addressScopeID).ExtractErr()
   386  	if err != nil {
   387  		t.Fatalf("Unable to delete address-scope %s: %v", addressScopeID, err)
   388  	}
   389  
   390  	t.Logf("Deleted address-scope: %s", addressScopeID)
   391  }