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

     1  package lbaas_v2
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"testing"
     7  
     8  	"github.com/gophercloud/gophercloud"
     9  	"github.com/gophercloud/gophercloud/internal/acceptance/tools"
    10  	"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/l7policies"
    11  	"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners"
    12  	"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers"
    13  	"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors"
    14  	"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools"
    15  	th "github.com/gophercloud/gophercloud/testhelper"
    16  )
    17  
    18  // CreateListener will create a listener for a given load balancer on a random
    19  // port with a random name. An error will be returned if the listener could not
    20  // be created.
    21  func CreateListener(t *testing.T, client *gophercloud.ServiceClient, lb *loadbalancers.LoadBalancer) (*listeners.Listener, error) {
    22  	listenerName := tools.RandomString("TESTACCT-", 8)
    23  	listenerDescription := tools.RandomString("TESTACCT-DESC-", 8)
    24  	listenerPort := tools.RandomInt(1, 100)
    25  
    26  	t.Logf("Attempting to create listener %s on port %d", listenerName, listenerPort)
    27  
    28  	createOpts := listeners.CreateOpts{
    29  		Name:           listenerName,
    30  		Description:    listenerDescription,
    31  		LoadbalancerID: lb.ID,
    32  		Protocol:       listeners.ProtocolHTTP,
    33  		ProtocolPort:   listenerPort,
    34  	}
    35  
    36  	listener, err := listeners.Create(client, createOpts).Extract()
    37  	if err != nil {
    38  		return listener, err
    39  	}
    40  
    41  	t.Logf("Successfully created listener %s", listenerName)
    42  
    43  	if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil {
    44  		return listener, fmt.Errorf("Timed out waiting for loadbalancer to become active: %s", err)
    45  	}
    46  
    47  	th.AssertEquals(t, listener.Name, listenerName)
    48  	th.AssertEquals(t, listener.Description, listenerDescription)
    49  	th.AssertEquals(t, listener.Loadbalancers[0].ID, lb.ID)
    50  	th.AssertEquals(t, listener.Protocol, string(listeners.ProtocolHTTP))
    51  	th.AssertEquals(t, listener.ProtocolPort, listenerPort)
    52  
    53  	return listener, nil
    54  }
    55  
    56  // CreateLoadBalancer will create a load balancer with a random name on a given
    57  // subnet. An error will be returned if the loadbalancer could not be created.
    58  func CreateLoadBalancer(t *testing.T, client *gophercloud.ServiceClient, subnetID string) (*loadbalancers.LoadBalancer, error) {
    59  	lbName := tools.RandomString("TESTACCT-", 8)
    60  	lbDescription := tools.RandomString("TESTACCT-DESC-", 8)
    61  
    62  	t.Logf("Attempting to create loadbalancer %s on subnet %s", lbName, subnetID)
    63  
    64  	createOpts := loadbalancers.CreateOpts{
    65  		Name:         lbName,
    66  		Description:  lbDescription,
    67  		VipSubnetID:  subnetID,
    68  		AdminStateUp: gophercloud.Enabled,
    69  	}
    70  
    71  	lb, err := loadbalancers.Create(client, createOpts).Extract()
    72  	if err != nil {
    73  		return lb, err
    74  	}
    75  
    76  	t.Logf("Successfully created loadbalancer %s on subnet %s", lbName, subnetID)
    77  	t.Logf("Waiting for loadbalancer %s to become active", lbName)
    78  
    79  	if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil {
    80  		return lb, err
    81  	}
    82  
    83  	t.Logf("LoadBalancer %s is active", lbName)
    84  
    85  	th.AssertEquals(t, lb.Name, lbName)
    86  	th.AssertEquals(t, lb.Description, lbDescription)
    87  	th.AssertEquals(t, lb.VipSubnetID, subnetID)
    88  	th.AssertEquals(t, lb.AdminStateUp, true)
    89  
    90  	return lb, nil
    91  }
    92  
    93  // CreateMember will create a member with a random name, port, address, and
    94  // weight. An error will be returned if the member could not be created.
    95  func CreateMember(t *testing.T, client *gophercloud.ServiceClient, lb *loadbalancers.LoadBalancer, pool *pools.Pool, subnetID, subnetCIDR string) (*pools.Member, error) {
    96  	memberName := tools.RandomString("TESTACCT-", 8)
    97  	memberPort := tools.RandomInt(100, 1000)
    98  	memberWeight := tools.RandomInt(1, 10)
    99  
   100  	cidrParts := strings.Split(subnetCIDR, "/")
   101  	subnetParts := strings.Split(cidrParts[0], ".")
   102  	memberAddress := fmt.Sprintf("%s.%s.%s.%d", subnetParts[0], subnetParts[1], subnetParts[2], tools.RandomInt(10, 100))
   103  
   104  	t.Logf("Attempting to create member %s", memberName)
   105  
   106  	createOpts := pools.CreateMemberOpts{
   107  		Name:         memberName,
   108  		ProtocolPort: memberPort,
   109  		Weight:       &memberWeight,
   110  		Address:      memberAddress,
   111  		SubnetID:     subnetID,
   112  	}
   113  
   114  	t.Logf("Member create opts: %#v", createOpts)
   115  
   116  	member, err := pools.CreateMember(client, pool.ID, createOpts).Extract()
   117  	if err != nil {
   118  		return member, err
   119  	}
   120  
   121  	t.Logf("Successfully created member %s", memberName)
   122  
   123  	if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil {
   124  		return member, fmt.Errorf("Timed out waiting for loadbalancer to become active: %s", err)
   125  	}
   126  
   127  	th.AssertEquals(t, member.Name, memberName)
   128  
   129  	return member, nil
   130  }
   131  
   132  // CreateMonitor will create a monitor with a random name for a specific pool.
   133  // An error will be returned if the monitor could not be created.
   134  func CreateMonitor(t *testing.T, client *gophercloud.ServiceClient, lb *loadbalancers.LoadBalancer, pool *pools.Pool) (*monitors.Monitor, error) {
   135  	monitorName := tools.RandomString("TESTACCT-", 8)
   136  
   137  	t.Logf("Attempting to create monitor %s", monitorName)
   138  
   139  	createOpts := monitors.CreateOpts{
   140  		PoolID:     pool.ID,
   141  		Name:       monitorName,
   142  		Delay:      10,
   143  		Timeout:    5,
   144  		MaxRetries: 5,
   145  		Type:       monitors.TypePING,
   146  	}
   147  
   148  	monitor, err := monitors.Create(client, createOpts).Extract()
   149  	if err != nil {
   150  		return monitor, err
   151  	}
   152  
   153  	t.Logf("Successfully created monitor: %s", monitorName)
   154  
   155  	if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil {
   156  		return monitor, fmt.Errorf("Timed out waiting for loadbalancer to become active: %s", err)
   157  	}
   158  
   159  	th.AssertEquals(t, monitor.Name, monitorName)
   160  	th.AssertEquals(t, monitor.Type, monitors.TypePING)
   161  
   162  	return monitor, nil
   163  }
   164  
   165  // CreatePool will create a pool with a random name with a specified listener
   166  // and loadbalancer. An error will be returned if the pool could not be
   167  // created.
   168  func CreatePool(t *testing.T, client *gophercloud.ServiceClient, lb *loadbalancers.LoadBalancer) (*pools.Pool, error) {
   169  	poolName := tools.RandomString("TESTACCT-", 8)
   170  	poolDescription := tools.RandomString("TESTACCT-DESC-", 8)
   171  
   172  	t.Logf("Attempting to create pool %s", poolName)
   173  
   174  	createOpts := pools.CreateOpts{
   175  		Name:           poolName,
   176  		Description:    poolDescription,
   177  		Protocol:       pools.ProtocolHTTP,
   178  		LoadbalancerID: lb.ID,
   179  		LBMethod:       pools.LBMethodLeastConnections,
   180  	}
   181  
   182  	pool, err := pools.Create(client, createOpts).Extract()
   183  	if err != nil {
   184  		return pool, err
   185  	}
   186  
   187  	t.Logf("Successfully created pool %s", poolName)
   188  
   189  	if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil {
   190  		return pool, fmt.Errorf("Timed out waiting for loadbalancer to become active: %s", err)
   191  	}
   192  
   193  	th.AssertEquals(t, pool.Name, poolName)
   194  	th.AssertEquals(t, pool.Description, poolDescription)
   195  	th.AssertEquals(t, pool.Protocol, string(pools.ProtocolHTTP))
   196  	th.AssertEquals(t, pool.Loadbalancers[0].ID, lb.ID)
   197  	th.AssertEquals(t, pool.LBMethod, string(pools.LBMethodLeastConnections))
   198  
   199  	return pool, nil
   200  }
   201  
   202  // CreateL7Policy will create a l7 policy with a random name with a specified listener
   203  // and loadbalancer. An error will be returned if the l7 policy could not be
   204  // created.
   205  func CreateL7Policy(t *testing.T, client *gophercloud.ServiceClient, listener *listeners.Listener, lb *loadbalancers.LoadBalancer) (*l7policies.L7Policy, error) {
   206  	policyName := tools.RandomString("TESTACCT-", 8)
   207  	policyDescription := tools.RandomString("TESTACCT-DESC-", 8)
   208  
   209  	t.Logf("Attempting to create l7 policy %s on the %s listener ID", policyName, listener.ID)
   210  
   211  	createOpts := l7policies.CreateOpts{
   212  		Name:        policyName,
   213  		Description: policyDescription,
   214  		ListenerID:  listener.ID,
   215  		Action:      l7policies.ActionRedirectToURL,
   216  		RedirectURL: "http://www.example.com",
   217  	}
   218  
   219  	policy, err := l7policies.Create(client, createOpts).Extract()
   220  	if err != nil {
   221  		return policy, err
   222  	}
   223  
   224  	t.Logf("Successfully created l7 policy %s", policyName)
   225  
   226  	if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil {
   227  		return policy, fmt.Errorf("Timed out waiting for loadbalancer to become active: %s", err)
   228  	}
   229  
   230  	th.AssertEquals(t, policy.Name, policyName)
   231  	th.AssertEquals(t, policy.Description, policyDescription)
   232  	th.AssertEquals(t, policy.ListenerID, listener.ID)
   233  	th.AssertEquals(t, policy.Action, string(l7policies.ActionRedirectToURL))
   234  	th.AssertEquals(t, policy.RedirectURL, "http://www.example.com")
   235  
   236  	return policy, nil
   237  }
   238  
   239  // CreateL7Rule creates a l7 rule for specified l7 policy.
   240  func CreateL7Rule(t *testing.T, client *gophercloud.ServiceClient, policyID string, lb *loadbalancers.LoadBalancer) (*l7policies.Rule, error) {
   241  	t.Logf("Attempting to create l7 rule for policy %s", policyID)
   242  
   243  	createOpts := l7policies.CreateRuleOpts{
   244  		RuleType:    l7policies.TypePath,
   245  		CompareType: l7policies.CompareTypeStartWith,
   246  		Value:       "/api",
   247  	}
   248  
   249  	rule, err := l7policies.CreateRule(client, policyID, createOpts).Extract()
   250  	if err != nil {
   251  		return rule, err
   252  	}
   253  
   254  	t.Logf("Successfully created l7 rule for policy %s", policyID)
   255  
   256  	if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil {
   257  		return rule, fmt.Errorf("Timed out waiting for loadbalancer to become active: %s", err)
   258  	}
   259  
   260  	th.AssertEquals(t, rule.RuleType, string(l7policies.TypePath))
   261  	th.AssertEquals(t, rule.CompareType, string(l7policies.CompareTypeStartWith))
   262  	th.AssertEquals(t, rule.Value, "/api")
   263  
   264  	return rule, nil
   265  }
   266  
   267  // DeleteL7Policy will delete a specified l7 policy. A fatal error will occur if
   268  // the l7 policy could not be deleted. This works best when used as a deferred
   269  // function.
   270  func DeleteL7Policy(t *testing.T, client *gophercloud.ServiceClient, lbID, policyID string) {
   271  	t.Logf("Attempting to delete l7 policy %s", policyID)
   272  
   273  	if err := l7policies.Delete(client, policyID).ExtractErr(); err != nil {
   274  		if _, ok := err.(gophercloud.ErrDefault404); !ok {
   275  			t.Fatalf("Unable to delete l7 policy: %v", err)
   276  		}
   277  	}
   278  
   279  	if err := WaitForLoadBalancerState(client, lbID, "ACTIVE"); err != nil {
   280  		t.Fatalf("Timed out waiting for loadbalancer to become active: %s", err)
   281  	}
   282  
   283  	t.Logf("Successfully deleted l7 policy %s", policyID)
   284  }
   285  
   286  // DeleteL7Rule will delete a specified l7 rule. A fatal error will occur if
   287  // the l7 rule could not be deleted. This works best when used as a deferred
   288  // function.
   289  func DeleteL7Rule(t *testing.T, client *gophercloud.ServiceClient, lbID, policyID, ruleID string) {
   290  	t.Logf("Attempting to delete l7 rule %s", ruleID)
   291  
   292  	if err := l7policies.DeleteRule(client, policyID, ruleID).ExtractErr(); err != nil {
   293  		if _, ok := err.(gophercloud.ErrDefault404); !ok {
   294  			t.Fatalf("Unable to delete l7 rule: %v", err)
   295  		}
   296  	}
   297  
   298  	if err := WaitForLoadBalancerState(client, lbID, "ACTIVE"); err != nil {
   299  		t.Fatalf("Timed out waiting for loadbalancer to become active: %s", err)
   300  	}
   301  
   302  	t.Logf("Successfully deleted l7 rule %s", ruleID)
   303  }
   304  
   305  // DeleteListener will delete a specified listener. A fatal error will occur if
   306  // the listener could not be deleted. This works best when used as a deferred
   307  // function.
   308  func DeleteListener(t *testing.T, client *gophercloud.ServiceClient, lbID, listenerID string) {
   309  	t.Logf("Attempting to delete listener %s", listenerID)
   310  
   311  	if err := listeners.Delete(client, listenerID).ExtractErr(); err != nil {
   312  		if _, ok := err.(gophercloud.ErrDefault404); !ok {
   313  			t.Fatalf("Unable to delete listener: %v", err)
   314  		}
   315  	}
   316  
   317  	if err := WaitForLoadBalancerState(client, lbID, "ACTIVE"); err != nil {
   318  		t.Fatalf("Timed out waiting for loadbalancer to become active: %s", err)
   319  	}
   320  
   321  	t.Logf("Successfully deleted listener %s", listenerID)
   322  }
   323  
   324  // DeleteMember will delete a specified member. A fatal error will occur if the
   325  // member could not be deleted. This works best when used as a deferred
   326  // function.
   327  func DeleteMember(t *testing.T, client *gophercloud.ServiceClient, lbID, poolID, memberID string) {
   328  	t.Logf("Attempting to delete member %s", memberID)
   329  
   330  	if err := pools.DeleteMember(client, poolID, memberID).ExtractErr(); err != nil {
   331  		if _, ok := err.(gophercloud.ErrDefault404); !ok {
   332  			t.Fatalf("Unable to delete member: %s", memberID)
   333  		}
   334  	}
   335  
   336  	if err := WaitForLoadBalancerState(client, lbID, "ACTIVE"); err != nil {
   337  		t.Fatalf("Timed out waiting for loadbalancer to become active: %s", err)
   338  	}
   339  
   340  	t.Logf("Successfully deleted member %s", memberID)
   341  }
   342  
   343  // DeleteLoadBalancer will delete a specified loadbalancer. A fatal error will
   344  // occur if the loadbalancer could not be deleted. This works best when used
   345  // as a deferred function.
   346  func DeleteLoadBalancer(t *testing.T, client *gophercloud.ServiceClient, lbID string) {
   347  	t.Logf("Attempting to delete loadbalancer %s", lbID)
   348  
   349  	if err := loadbalancers.Delete(client, lbID).ExtractErr(); err != nil {
   350  		if _, ok := err.(gophercloud.ErrDefault404); !ok {
   351  			t.Fatalf("Unable to delete loadbalancer: %v", err)
   352  		}
   353  	}
   354  
   355  	t.Logf("Waiting for loadbalancer %s to delete", lbID)
   356  
   357  	if err := WaitForLoadBalancerState(client, lbID, "DELETED"); err != nil {
   358  		t.Fatalf("Loadbalancer did not delete in time: %s", err)
   359  	}
   360  
   361  	t.Logf("Successfully deleted loadbalancer %s", lbID)
   362  }
   363  
   364  // DeleteMonitor will delete a specified monitor. A fatal error will occur if
   365  // the monitor could not be deleted. This works best when used as a deferred
   366  // function.
   367  func DeleteMonitor(t *testing.T, client *gophercloud.ServiceClient, lbID, monitorID string) {
   368  	t.Logf("Attempting to delete monitor %s", monitorID)
   369  
   370  	if err := monitors.Delete(client, monitorID).ExtractErr(); err != nil {
   371  		if _, ok := err.(gophercloud.ErrDefault404); !ok {
   372  			t.Fatalf("Unable to delete monitor: %v", err)
   373  		}
   374  	}
   375  
   376  	if err := WaitForLoadBalancerState(client, lbID, "ACTIVE"); err != nil {
   377  		t.Fatalf("Timed out waiting for loadbalancer to become active: %s", err)
   378  	}
   379  
   380  	t.Logf("Successfully deleted monitor %s", monitorID)
   381  }
   382  
   383  // DeletePool will delete a specified pool. A fatal error will occur if the
   384  // pool could not be deleted. This works best when used as a deferred function.
   385  func DeletePool(t *testing.T, client *gophercloud.ServiceClient, lbID, poolID string) {
   386  	t.Logf("Attempting to delete pool %s", poolID)
   387  
   388  	if err := pools.Delete(client, poolID).ExtractErr(); err != nil {
   389  		if _, ok := err.(gophercloud.ErrDefault404); !ok {
   390  			t.Fatalf("Unable to delete pool: %v", err)
   391  		}
   392  	}
   393  
   394  	if err := WaitForLoadBalancerState(client, lbID, "ACTIVE"); err != nil {
   395  		t.Fatalf("Timed out waiting for loadbalancer to become active: %s", err)
   396  	}
   397  
   398  	t.Logf("Successfully deleted pool %s", poolID)
   399  }
   400  
   401  // WaitForLoadBalancerState will wait until a loadbalancer reaches a given state.
   402  func WaitForLoadBalancerState(client *gophercloud.ServiceClient, lbID, status string) error {
   403  	return tools.WaitFor(func() (bool, error) {
   404  		current, err := loadbalancers.Get(client, lbID).Extract()
   405  		if err != nil {
   406  			if httpStatus, ok := err.(gophercloud.ErrDefault404); ok {
   407  				if httpStatus.Actual == 404 {
   408  					if status == "DELETED" {
   409  						return true, nil
   410  					}
   411  				}
   412  			}
   413  			return false, err
   414  		}
   415  
   416  		if current.ProvisioningStatus == status {
   417  			return true, nil
   418  		}
   419  
   420  		if current.ProvisioningStatus == "ERROR" {
   421  			return false, fmt.Errorf("Load balancer is in ERROR state")
   422  		}
   423  
   424  		return false, nil
   425  	})
   426  }