From 57d5f2534021c86a273ebbedeac1316c8fb1ac9e Mon Sep 17 00:00:00 2001 From: Zhenguo Niu Date: Tue, 25 May 2021 14:10:12 +0800 Subject: [PATCH] Add ELB v3 l7policy and l7rule (#1161) --- docs/resources/elb_l7policy.md | 48 +++ docs/resources/elb_l7rule.md | 48 +++ huaweicloud/provider.go | 2 + .../resource_huaweicloud_elb_l7policy.go | 217 ++++++++++ .../resource_huaweicloud_elb_l7policy_test.go | 139 +++++++ .../resource_huaweicloud_elb_l7rule.go | 231 +++++++++++ .../resource_huaweicloud_elb_l7rule_test.go | 199 ++++++++++ .../openstack/elb/v3/l7policies/requests.go | 375 ++++++++++++++++++ .../openstack/elb/v3/l7policies/results.go | 245 ++++++++++++ .../openstack/elb/v3/l7policies/urls.go | 25 ++ vendor/modules.txt | 1 + 11 files changed, 1530 insertions(+) create mode 100644 docs/resources/elb_l7policy.md create mode 100644 docs/resources/elb_l7rule.md create mode 100644 huaweicloud/resource_huaweicloud_elb_l7policy.go create mode 100644 huaweicloud/resource_huaweicloud_elb_l7policy_test.go create mode 100644 huaweicloud/resource_huaweicloud_elb_l7rule.go create mode 100644 huaweicloud/resource_huaweicloud_elb_l7rule_test.go create mode 100644 vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/l7policies/requests.go create mode 100644 vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/l7policies/results.go create mode 100644 vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/l7policies/urls.go diff --git a/docs/resources/elb_l7policy.md b/docs/resources/elb_l7policy.md new file mode 100644 index 0000000000..baee85f7ca --- /dev/null +++ b/docs/resources/elb_l7policy.md @@ -0,0 +1,48 @@ +--- +subcategory: "Dedicated Load Balance (Dedicated ELB)" +--- + +# huaweicloud\_elb\_l7policy + +Manages an ELB L7 Policy resource within HuaweiCloud. + +## Example Usage + +```hcl +resource "huaweicloud_elb_l7policy" "policy_1" { + name = "policy_1" + description = "test description" + listener_id = {{ listener_id }} + redirect_pool_id = {{ pool_id }} +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Optional, String, ForceNew) The region in which to create the L7 Policy resource. + If omitted, the provider-level region will be used. + Changing this creates a new L7 Policy. + +* `name` - (Optional, String) Human-readable name for the L7 Policy. Does not have + to be unique. + +* `description` - (Optional, String) Human-readable description for the L7 Policy. + +* `listener_id` - (Required, String, ForceNew) The Listener on which the L7 Policy will be associated with. + Changing this creates a new L7 Policy. + +* `redirect_pool_id` - (Required, String) Requests matching this policy will be redirected to the pool with this ID. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The unique ID for the L7 policy. + +## Timeouts +This resource provides the following timeouts configuration options: +- `create` - Default is 10 minute. +- `update` - Default is 10 minute. +- `delete` - Default is 10 minute. diff --git a/docs/resources/elb_l7rule.md b/docs/resources/elb_l7rule.md new file mode 100644 index 0000000000..8f1d673a01 --- /dev/null +++ b/docs/resources/elb_l7rule.md @@ -0,0 +1,48 @@ +--- +subcategory: "Dedicated Load Balance (Dedicated ELB)" +--- + +# huaweicloud\_elb\_l7rule + +Manages an ELB L7 Rule resource within HuaweiCloud. + +## Example Usage + +```hcl +resource "huaweicloud_elb_l7rule" "l7rule_1" { + l7policy_id = {{ policy_id }} + type = "PATH" + compare_type = "EQUAL_TO" + value = "/api" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Optional, String, ForceNew) The region in which to create the L7 Rule resource. + If omitted, the provider-level region will be used. + Changing this creates a new L7 Rule. + +* `type` - (Required, String, ForceNew) The L7 Rule type - can either be HOST\_NAME or PATH. Changing this creates a new L7 Rule. + +* `compare_type` - (Required, String) The comparison type for the L7 rule - can either be + STARTS\_WITH, EQUAL_TO or REGEX + +* `l7policy_id` - (Required, String, ForceNew) The ID of the L7 Policy. Changing this creates a new + L7 Rule. + +* `value` - (Required, String) The value to use for the comparison. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The unique ID for the L7 Rule. + +## Timeouts +This resource provides the following timeouts configuration options: +- `create` - Default is 10 minute. +- `update` - Default is 10 minute. +- `delete` - Default is 10 minute. diff --git a/huaweicloud/provider.go b/huaweicloud/provider.go index 07b851c156..52a260f42b 100644 --- a/huaweicloud/provider.go +++ b/huaweicloud/provider.go @@ -401,6 +401,8 @@ func Provider() terraform.ResourceProvider { "huaweicloud_dns_zone": ResourceDNSZoneV2(), "huaweicloud_dws_cluster": resourceDwsCluster(), "huaweicloud_elb_certificate": ResourceCertificateV3(), + "huaweicloud_elb_l7policy": ResourceL7PolicyV3(), + "huaweicloud_elb_l7rule": ResourceL7RuleV3(), "huaweicloud_elb_listener": ResourceListenerV3(), "huaweicloud_elb_loadbalancer": ResourceLoadBalancerV3(), "huaweicloud_elb_ipgroup": ResourceIpGroupV3(), diff --git a/huaweicloud/resource_huaweicloud_elb_l7policy.go b/huaweicloud/resource_huaweicloud_elb_l7policy.go new file mode 100644 index 0000000000..9ce32d9dc3 --- /dev/null +++ b/huaweicloud/resource_huaweicloud_elb_l7policy.go @@ -0,0 +1,217 @@ +package huaweicloud + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/openstack/elb/v3/l7policies" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" +) + +func ResourceL7PolicyV3() *schema.Resource { + return &schema.Resource{ + Create: resourceL7PolicyV3Create, + Read: resourceL7PolicyV3Read, + Update: resourceL7PolicyV3Update, + Delete: resourceL7PolicyV3Delete, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + + "name": { + Type: schema.TypeString, + Optional: true, + }, + + "description": { + Type: schema.TypeString, + Optional: true, + }, + + "listener_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "redirect_pool_id": { + Type: schema.TypeString, + Required: true, + }, + }, + } +} + +func resourceL7PolicyV3Create(d *schema.ResourceData, meta interface{}) error { + config := meta.(*config.Config) + lbClient, err := config.ElbV3Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud elb client: %s", err) + } + + createOpts := l7policies.CreateOpts{ + Name: d.Get("name").(string), + Description: d.Get("description").(string), + Action: "REDIRECT_TO_POOL", + ListenerID: d.Get("listener_id").(string), + RedirectPoolID: d.Get("redirect_pool_id").(string), + } + + log.Printf("[DEBUG] Create Options: %#v", createOpts) + l7Policy, err := l7policies.Create(lbClient, createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating L7 Policy: %s", err) + } + + timeout := d.Timeout(schema.TimeoutCreate) + // Wait for L7 Policy to become active before continuing + err = waitForElbV3Policy(lbClient, l7Policy.ID, "ACTIVE", nil, timeout) + if err != nil { + return err + } + + d.SetId(l7Policy.ID) + + return resourceL7PolicyV3Read(d, meta) +} + +func resourceL7PolicyV3Read(d *schema.ResourceData, meta interface{}) error { + config := meta.(*config.Config) + lbClient, err := config.ElbV3Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud elb client: %s", err) + } + + l7Policy, err := l7policies.Get(lbClient, d.Id()).Extract() + if err != nil { + return CheckDeleted(d, err, "L7 Policy") + } + + log.Printf("[DEBUG] Retrieved L7 Policy %s: %#v", d.Id(), l7Policy) + + d.Set("description", l7Policy.Description) + d.Set("name", l7Policy.Name) + d.Set("listener_id", l7Policy.ListenerID) + d.Set("redirect_pool_id", l7Policy.RedirectPoolID) + d.Set("region", GetRegion(d, config)) + + return nil +} + +func resourceL7PolicyV3Update(d *schema.ResourceData, meta interface{}) error { + config := meta.(*config.Config) + lbClient, err := config.ElbV3Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud elb client: %s", err) + } + + var updateOpts l7policies.UpdateOpts + + if d.HasChange("name") { + name := d.Get("name").(string) + updateOpts.Name = &name + } + if d.HasChange("description") { + description := d.Get("description").(string) + updateOpts.Description = &description + } + if d.HasChange("redirect_pool_id") { + redirectPoolID := d.Get("redirect_pool_id").(string) + updateOpts.RedirectPoolID = &redirectPoolID + } + + log.Printf("[DEBUG] Updating L7 Policy %s with options: %#v", d.Id(), updateOpts) + _, err = l7policies.Update(lbClient, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Unable to update L7 Policy %s: %s", d.Id(), err) + } + + timeout := d.Timeout(schema.TimeoutUpdate) + err = waitForElbV3Policy(lbClient, d.Id(), "ACTIVE", nil, timeout) + if err != nil { + return err + } + + return resourceL7PolicyV3Read(d, meta) +} + +func resourceL7PolicyV3Delete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*config.Config) + lbClient, err := config.ElbV3Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud elb client: %s", err) + } + + log.Printf("[DEBUG] Attempting to delete L7 Policy %s", d.Id()) + err = l7policies.Delete(lbClient, d.Id()).ExtractErr() + if err != nil { + return CheckDeleted(d, err, "Error deleting L7 Policy") + } + + timeout := d.Timeout(schema.TimeoutDelete) + err = waitForElbV3Policy(lbClient, d.Id(), "DELETED", nil, timeout) + if err != nil { + return err + } + + return nil +} + +func waitForElbV3Policy(elbClient *golangsdk.ServiceClient, + id string, target string, pending []string, timeout time.Duration) error { + + log.Printf("[DEBUG] Waiting for policy %s to become %s", id, target) + + stateConf := &resource.StateChangeConf{ + Target: []string{target}, + Pending: pending, + Refresh: resourceElbV3PolicyRefreshFunc(elbClient, id), + Timeout: timeout, + Delay: 5 * time.Second, + PollInterval: 3 * time.Second, + } + + _, err := stateConf.WaitForState() + if err != nil { + if _, ok := err.(golangsdk.ErrDefault404); ok { + switch target { + case "DELETED": + return nil + default: + return fmt.Errorf("Error: policy %s not found: %s", id, err) + } + } + return fmt.Errorf("Error waiting for policy %s to become %s: %s", id, target, err) + } + + return nil +} + +func resourceElbV3PolicyRefreshFunc(elbClient *golangsdk.ServiceClient, + id string) resource.StateRefreshFunc { + + return func() (interface{}, string, error) { + policy, err := l7policies.Get(elbClient, id).Extract() + if err != nil { + return nil, "", err + } + + return policy, policy.ProvisioningStatus, nil + } +} diff --git a/huaweicloud/resource_huaweicloud_elb_l7policy_test.go b/huaweicloud/resource_huaweicloud_elb_l7policy_test.go new file mode 100644 index 0000000000..1b63e20804 --- /dev/null +++ b/huaweicloud/resource_huaweicloud_elb_l7policy_test.go @@ -0,0 +1,139 @@ +package huaweicloud + +import ( + "fmt" + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + + "github.com/huaweicloud/golangsdk/openstack/elb/v3/l7policies" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" +) + +func TestAccElbV3L7Policy_basic(t *testing.T) { + var l7Policy l7policies.L7Policy + rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + resourceName := "huaweicloud_elb_l7policy.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckElbV3L7PolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckElbV3L7PolicyConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckElbV3L7PolicyExists(resourceName, &l7Policy), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "description", "test description"), + resource.TestMatchResourceAttr(resourceName, "listener_id", + regexp.MustCompile("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$")), + ), + }, + }, + }) +} + +func testAccCheckElbV3L7PolicyDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*config.Config) + lbClient, err := config.ElbV3Client(HW_REGION_NAME) + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud load balancing client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "huaweicloud_elb_l7policy" { + continue + } + + _, err := l7policies.Get(lbClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("L7 Policy still exists: %s", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckElbV3L7PolicyExists(n string, l7Policy *l7policies.L7Policy) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + config := testAccProvider.Meta().(*config.Config) + lbClient, err := config.ElbV3Client(HW_REGION_NAME) + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud load balancing client: %s", err) + } + + found, err := l7policies.Get(lbClient, rs.Primary.ID).Extract() + if err != nil { + return err + } + + if found.ID != rs.Primary.ID { + return fmt.Errorf("Policy not found") + } + + *l7Policy = *found + + return nil + } +} + +func testAccCheckElbV3L7PolicyConfig_basic(rName string) string { + return fmt.Sprintf(` +data "huaweicloud_vpc_subnet" "test" { + name = "subnet-default" +} + +data "huaweicloud_availability_zones" "test" {} + +resource "huaweicloud_elb_loadbalancer" "test" { + name = "%s" + ipv4_subnet_id = data.huaweicloud_vpc_subnet.test.subnet_id + ipv6_network_id = data.huaweicloud_vpc_subnet.test.id + + availability_zone = [ + data.huaweicloud_availability_zones.test.names[0] + ] +} + +resource "huaweicloud_elb_listener" "test" { + name = "%s" + description = "test description" + protocol = "HTTP" + protocol_port = 8080 + loadbalancer_id = huaweicloud_elb_loadbalancer.test.id + + forward_eip = true + + idle_timeout = 60 + request_timeout = 60 + response_timeout = 60 +} + +resource "huaweicloud_elb_pool" "test" { + name = "%s" + protocol = "HTTP" + lb_method = "LEAST_CONNECTIONS" + loadbalancer_id = huaweicloud_elb_loadbalancer.test.id +} + +resource "huaweicloud_elb_l7policy" "test" { + name = "%s" + description = "test description" + listener_id = huaweicloud_elb_listener.test.id + redirect_pool_id = huaweicloud_elb_pool.test.id +} +`, rName, rName, rName, rName) +} diff --git a/huaweicloud/resource_huaweicloud_elb_l7rule.go b/huaweicloud/resource_huaweicloud_elb_l7rule.go new file mode 100644 index 0000000000..8b3bffcbef --- /dev/null +++ b/huaweicloud/resource_huaweicloud_elb_l7rule.go @@ -0,0 +1,231 @@ +package huaweicloud + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/openstack/elb/v3/l7policies" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" +) + +func ResourceL7RuleV3() *schema.Resource { + return &schema.Resource{ + Create: resourceL7RuleV3Create, + Read: resourceL7RuleV3Read, + Update: resourceL7RuleV3Update, + Delete: resourceL7RuleV3Delete, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + + "type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + "HOST_NAME", "PATH", + }, true), + }, + + "compare_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "STARTS_WITH", "EQUAL_TO", "REGEX", + }, true), + }, + + "l7policy_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "value": { + Type: schema.TypeString, + Required: true, + ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { + if len(v.(string)) == 0 { + errors = append(errors, fmt.Errorf("'value' field should not be empty")) + } + return + }, + }, + }, + } +} + +func resourceL7RuleV3Create(d *schema.ResourceData, meta interface{}) error { + config := meta.(*config.Config) + lbClient, err := config.ElbV3Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud elb client: %s", err) + } + + l7policyID := d.Get("l7policy_id").(string) + ruleType := d.Get("type").(string) + compareType := d.Get("compare_type").(string) + + createOpts := l7policies.CreateRuleOpts{ + RuleType: l7policies.RuleType(ruleType), + CompareType: l7policies.CompareType(compareType), + Value: d.Get("value").(string), + } + + log.Printf("[DEBUG] Create Options: %#v", createOpts) + l7Rule, err := l7policies.CreateRule(lbClient, l7policyID, createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating L7 Rule: %s", err) + } + + timeout := d.Timeout(schema.TimeoutCreate) + // Wait for L7 Rule to become active before continuing + err = waitForElbV3Rule(lbClient, l7policyID, l7Rule.ID, "ACTIVE", nil, timeout) + if err != nil { + return err + } + + d.SetId(l7Rule.ID) + + return resourceL7RuleV3Read(d, meta) +} + +func resourceL7RuleV3Read(d *schema.ResourceData, meta interface{}) error { + config := meta.(*config.Config) + lbClient, err := config.ElbV3Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud elb client: %s", err) + } + + l7policyID := d.Get("l7policy_id").(string) + + l7Rule, err := l7policies.GetRule(lbClient, l7policyID, d.Id()).Extract() + if err != nil { + return CheckDeleted(d, err, "L7 Rule") + } + + log.Printf("[DEBUG] Retrieved L7 Rule %s: %#v", d.Id(), l7Rule) + + d.Set("l7policy_id", l7policyID) + d.Set("type", l7Rule.RuleType) + d.Set("compare_type", l7Rule.CompareType) + d.Set("value", l7Rule.Value) + + return nil +} + +func resourceL7RuleV3Update(d *schema.ResourceData, meta interface{}) error { + config := meta.(*config.Config) + lbClient, err := config.ElbV3Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud elb client: %s", err) + } + + l7policyID := d.Get("l7policy_id").(string) + var updateOpts l7policies.UpdateRuleOpts + + if d.HasChange("compare_type") { + updateOpts.CompareType = l7policies.CompareType(d.Get("compare_type").(string)) + } + if d.HasChange("value") { + updateOpts.Value = d.Get("value").(string) + } + + log.Printf("[DEBUG] Updating L7 Rule %s with options: %#v", d.Id(), updateOpts) + _, err = l7policies.UpdateRule(lbClient, l7policyID, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Unable to update L7 Rule %s: %s", d.Id(), err) + } + + timeout := d.Timeout(schema.TimeoutUpdate) + // Wait for L7 Rule to become active before continuing + err = waitForElbV3Rule(lbClient, l7policyID, d.Id(), "ACTIVE", nil, timeout) + if err != nil { + return err + } + + return resourceL7RuleV3Read(d, meta) +} + +func resourceL7RuleV3Delete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*config.Config) + lbClient, err := config.ElbV3Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud elb client: %s", err) + } + + l7policyID := d.Get("l7policy_id").(string) + log.Printf("[DEBUG] Attempting to delete L7 Rule %s", d.Id()) + err = l7policies.DeleteRule(lbClient, l7policyID, d.Id()).ExtractErr() + if err != nil { + return CheckDeleted(d, err, "Error deleting L7 Rule") + } + + timeout := d.Timeout(schema.TimeoutDelete) + err = waitForElbV3Rule(lbClient, l7policyID, d.Id(), "DELETED", nil, timeout) + if err != nil { + return err + } + + return nil +} + +func waitForElbV3Rule(elbClient *golangsdk.ServiceClient, l7policyID string, + id string, target string, pending []string, timeout time.Duration) error { + + log.Printf("[DEBUG] Waiting for rule %s to become %s", id, target) + + stateConf := &resource.StateChangeConf{ + Target: []string{target}, + Pending: pending, + Refresh: resourceElbV3RuleRefreshFunc(elbClient, l7policyID, id), + Timeout: timeout, + Delay: 5 * time.Second, + PollInterval: 3 * time.Second, + } + + _, err := stateConf.WaitForState() + if err != nil { + if _, ok := err.(golangsdk.ErrDefault404); ok { + switch target { + case "DELETED": + return nil + default: + return fmt.Errorf("Error: rule %s not found: %s", id, err) + } + } + return fmt.Errorf("Error waiting for rule %s to become %s: %s", id, target, err) + } + + return nil +} + +func resourceElbV3RuleRefreshFunc(elbClient *golangsdk.ServiceClient, + l7policyID string, id string) resource.StateRefreshFunc { + + return func() (interface{}, string, error) { + rule, err := l7policies.GetRule(elbClient, l7policyID, id).Extract() + if err != nil { + return nil, "", err + } + + return rule, rule.ProvisioningStatus, nil + } +} diff --git a/huaweicloud/resource_huaweicloud_elb_l7rule_test.go b/huaweicloud/resource_huaweicloud_elb_l7rule_test.go new file mode 100644 index 0000000000..3e9fa4f5ce --- /dev/null +++ b/huaweicloud/resource_huaweicloud_elb_l7rule_test.go @@ -0,0 +1,199 @@ +package huaweicloud + +import ( + "fmt" + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + + l7rules "github.com/huaweicloud/golangsdk/openstack/elb/v3/l7policies" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" +) + +func TestAccElbV3L7Rule_basic(t *testing.T) { + var l7rule l7rules.Rule + rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + resourceName := "huaweicloud_elb_l7rule.l7rule_1" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckElbV3L7RuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckElbV3L7RuleConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckElbV3L7RuleExists(resourceName, &l7rule), + resource.TestCheckResourceAttr(resourceName, "type", "PATH"), + resource.TestCheckResourceAttr(resourceName, "compare_type", "EQUAL_TO"), + resource.TestCheckResourceAttr(resourceName, "value", "/api"), + resource.TestMatchResourceAttr(resourceName, "l7policy_id", + regexp.MustCompile("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$")), + ), + }, + { + Config: testAccCheckElbV3L7RuleConfig_update(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckElbV3L7RuleExists(resourceName, &l7rule), + resource.TestCheckResourceAttr(resourceName, "type", "PATH"), + resource.TestCheckResourceAttr(resourceName, "compare_type", "STARTS_WITH"), + resource.TestCheckResourceAttr(resourceName, "value", "/images"), + ), + }, + }, + }) +} + +func testAccCheckElbV3L7RuleDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*config.Config) + lbClient, err := config.ElbV3Client(HW_REGION_NAME) + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud load balancing client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "huaweicloud_elb_l7rule" { + continue + } + + l7policyID := "" + for k, v := range rs.Primary.Attributes { + if k == "l7policy_id" { + l7policyID = v + break + } + } + + if l7policyID == "" { + return fmt.Errorf("Unable to find l7policy_id") + } + + _, err := l7rules.GetRule(lbClient, l7policyID, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("L7 Rule still exists: %s", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckElbV3L7RuleExists(n string, l7rule *l7rules.Rule) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + config := testAccProvider.Meta().(*config.Config) + lbClient, err := config.ElbV3Client(HW_REGION_NAME) + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud load balancing client: %s", err) + } + + l7policyID := "" + for k, v := range rs.Primary.Attributes { + if k == "l7policy_id" { + l7policyID = v + break + } + } + + if l7policyID == "" { + return fmt.Errorf("Unable to find l7policy_id") + } + + found, err := l7rules.GetRule(lbClient, l7policyID, rs.Primary.ID).Extract() + if err != nil { + return err + } + + if found.ID != rs.Primary.ID { + return fmt.Errorf("Policy not found") + } + + *l7rule = *found + + return nil + } +} + +func testAccCheckElbV3L7RuleConfig(rName string) string { + return fmt.Sprintf(` +data "huaweicloud_vpc_subnet" "test" { + name = "subnet-default" +} + +data "huaweicloud_availability_zones" "test" {} + +resource "huaweicloud_elb_loadbalancer" "test" { + name = "%s" + ipv4_subnet_id = data.huaweicloud_vpc_subnet.test.subnet_id + ipv6_network_id = data.huaweicloud_vpc_subnet.test.id + + availability_zone = [ + data.huaweicloud_availability_zones.test.names[0] + ] +} + +resource "huaweicloud_elb_listener" "test" { + name = "%s" + description = "test description" + protocol = "HTTP" + protocol_port = 8080 + loadbalancer_id = huaweicloud_elb_loadbalancer.test.id + + forward_eip = true + + idle_timeout = 60 + request_timeout = 60 + response_timeout = 60 +} + +resource "huaweicloud_elb_pool" "test" { + name = "%s" + protocol = "HTTP" + lb_method = "LEAST_CONNECTIONS" + loadbalancer_id = huaweicloud_elb_loadbalancer.test.id +} + +resource "huaweicloud_elb_l7policy" "test" { + name = "%s" + description = "test description" + listener_id = huaweicloud_elb_listener.test.id + redirect_pool_id = huaweicloud_elb_pool.test.id +} +`, rName, rName, rName, rName) +} + +func testAccCheckElbV3L7RuleConfig_basic(rName string) string { + return fmt.Sprintf(` +%s + +resource "huaweicloud_elb_l7rule" "l7rule_1" { + l7policy_id = huaweicloud_elb_l7policy.test.id + type = "PATH" + compare_type = "EQUAL_TO" + value = "/api" +} +`, testAccCheckElbV3L7RuleConfig(rName)) +} + +func testAccCheckElbV3L7RuleConfig_update(rName string) string { + return fmt.Sprintf(` +%s + +resource "huaweicloud_elb_l7rule" "l7rule_1" { + l7policy_id = huaweicloud_elb_l7policy.test.id + type = "PATH" + compare_type = "STARTS_WITH" + value = "/images" +} +`, testAccCheckElbV3L7RuleConfig(rName)) +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/l7policies/requests.go b/vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/l7policies/requests.go new file mode 100644 index 0000000000..ae3ad8d551 --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/l7policies/requests.go @@ -0,0 +1,375 @@ +package l7policies + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/pagination" +) + +// CreateOptsBuilder allows extensions to add additional parameters to the +// Create request. +type CreateOptsBuilder interface { + ToL7PolicyCreateMap() (map[string]interface{}, error) +} + +type Action string +type RuleType string +type CompareType string + +const ( + ActionRedirectToPool Action = "REDIRECT_TO_POOL" + ActionRedirectToListener Action = "REDIRECT_TO_LISTENER" + ActionReject Action = "REJECT" + + TypeCookie RuleType = "COOKIE" + TypeFileType RuleType = "FILE_TYPE" + TypeHeader RuleType = "HEADER" + TypeHostName RuleType = "HOST_NAME" + TypePath RuleType = "PATH" + + CompareTypeContains CompareType = "CONTAINS" + CompareTypeEndWith CompareType = "ENDS_WITH" + CompareTypeEqual CompareType = "EQUAL_TO" + CompareTypeRegex CompareType = "REGEX" + CompareTypeStartWith CompareType = "STARTS_WITH" +) + +// CreateOpts is the common options struct used in this package's Create +// operation. +type CreateOpts struct { + // Name of the L7 policy. + Name string `json:"name,omitempty"` + + // The ID of the listener. + ListenerID string `json:"listener_id" required:"true"` + + // The L7 policy action. One of REDIRECT_TO_POOL, REDIRECT_TO_URL, or REJECT. + Action Action `json:"action" required:"true"` + + // The position of this policy on the listener. + Position int32 `json:"position,omitempty"` + + // The priority of this policy on the listener. + Priority int32 `json:"priority,omitempty"` + + // A human-readable description for the resource. + Description string `json:"description,omitempty"` + + // Requests matching this policy will be redirected to the pool with this ID. + // Only valid if action is REDIRECT_TO_POOL. + RedirectPoolID string `json:"redirect_pool_id,omitempty"` + + // Requests matching this policy will be redirected to this Listener. + // Only valid if action is REDIRECT_TO_LISTENER. + RedirectListenerID string `json:"redirect_listener_id,omitempty"` + + // The administrative state of the Loadbalancer. A valid value is true (UP) + // or false (DOWN). + AdminStateUp *bool `json:"admin_state_up,omitempty"` +} + +// ToL7PolicyCreateMap builds a request body from CreateOpts. +func (opts CreateOpts) ToL7PolicyCreateMap() (map[string]interface{}, error) { + return golangsdk.BuildRequestBody(opts, "l7policy") +} + +// Create accepts a CreateOpts struct and uses the values to create a new l7policy. +func Create(c *golangsdk.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { + b, err := opts.ToL7PolicyCreateMap() + if err != nil { + r.Err = err + return + } + _, r.Err = c.Post(rootURL(c), b, &r.Body, nil) + return +} + +// ListOptsBuilder allows extensions to add additional parameters to the +// List request. +type ListOptsBuilder interface { + ToL7PolicyListQuery() (string, error) +} + +// ListOpts allows the filtering and sorting of paginated collections through +// the API. +type ListOpts struct { + Name string `q:"name"` + Description string `q:"description"` + ListenerID string `q:"listener_id"` + Action string `q:"action"` + TenantID string `q:"tenant_id"` + RedirectPoolID string `q:"redirect_pool_id"` + RedirectListenerID string `q:"redirect_listener_id"` + Position int32 `q:"position"` + AdminStateUp bool `q:"admin_state_up"` + ID string `q:"id"` + Limit int `q:"limit"` + Marker string `q:"marker"` + SortKey string `q:"sort_key"` + SortDir string `q:"sort_dir"` +} + +// ToL7PolicyListQuery formats a ListOpts into a query string. +func (opts ListOpts) ToL7PolicyListQuery() (string, error) { + q, err := golangsdk.BuildQueryString(opts) + return q.String(), err +} + +// List returns a Pager which allows you to iterate over a collection of +// l7policies. It accepts a ListOpts struct, which allows you to filter and sort +// the returned collection for greater efficiency. +// +// Default policy settings return only those l7policies that are owned by the +// project who submits the request, unless an admin user submits the request. +func List(c *golangsdk.ServiceClient, opts ListOptsBuilder) pagination.Pager { + url := rootURL(c) + if opts != nil { + query, err := opts.ToL7PolicyListQuery() + if err != nil { + return pagination.Pager{Err: err} + } + url += query + } + return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page { + return L7PolicyPage{pagination.LinkedPageBase{PageResult: r}} + }) +} + +// Get retrieves a particular l7policy based on its unique ID. +func Get(c *golangsdk.ServiceClient, id string) (r GetResult) { + _, r.Err = c.Get(resourceURL(c, id), &r.Body, nil) + return +} + +// Delete will permanently delete a particular l7policy based on its unique ID. +func Delete(c *golangsdk.ServiceClient, id string) (r DeleteResult) { + _, r.Err = c.Delete(resourceURL(c, id), nil) + return +} + +// UpdateOptsBuilder allows extensions to add additional parameters to the +// Update request. +type UpdateOptsBuilder interface { + ToL7PolicyUpdateMap() (map[string]interface{}, error) +} + +// UpdateOpts is the common options struct used in this package's Update +// operation. +type UpdateOpts struct { + // Name of the L7 policy, empty string is allowed. + Name *string `json:"name,omitempty"` + + // The L7 policy action. One of REDIRECT_TO_POOL, REDIRECT_TO_URL, or REJECT. + Action Action `json:"action,omitempty"` + + // The position of this policy on the listener. + Position int32 `json:"position,omitempty"` + + // A human-readable description for the resource, empty string is allowed. + Description *string `json:"description,omitempty"` + + // Requests matching this policy will be redirected to the pool with this ID. + // Only valid if action is REDIRECT_TO_POOL. + RedirectPoolID *string `json:"redirect_pool_id,omitempty"` + + // Requests matching this policy will be redirected to this LISTENER. + // Only valid if action is REDIRECT_TO_LISTENER. + RedirectListenerID *string `json:"redirect_listener_id,omitempty"` + + // The administrative state of the Loadbalancer. A valid value is true (UP) + // or false (DOWN). + AdminStateUp *bool `json:"admin_state_up,omitempty"` +} + +// ToL7PolicyUpdateMap builds a request body from UpdateOpts. +func (opts UpdateOpts) ToL7PolicyUpdateMap() (map[string]interface{}, error) { + b, err := golangsdk.BuildRequestBody(opts, "l7policy") + if err != nil { + return nil, err + } + + m := b["l7policy"].(map[string]interface{}) + + if m["redirect_pool_id"] == "" { + m["redirect_pool_id"] = nil + } + + if m["redirect_url"] == "" { + m["redirect_url"] = nil + } + + return b, nil +} + +// Update allows l7policy to be updated. +func Update(c *golangsdk.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { + b, err := opts.ToL7PolicyUpdateMap() + if err != nil { + r.Err = err + return + } + _, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +// CreateRuleOpts is the common options struct used in this package's CreateRule +// operation. +type CreateRuleOpts struct { + // The L7 rule type. One of COOKIE, FILE_TYPE, HEADER, HOST_NAME, or PATH. + RuleType RuleType `json:"type" required:"true"` + + // The comparison type for the L7 rule. One of CONTAINS, ENDS_WITH, EQUAL_TO, REGEX, or STARTS_WITH. + CompareType CompareType `json:"compare_type" required:"true"` + + // The value to use for the comparison. For example, the file type to compare. + Value string `json:"value" required:"true"` + + // TenantID is the UUID of the tenant who owns the rule in octavia. + // Only administrative users can specify a project UUID other than their own. + TenantID string `json:"tenant_id,omitempty"` + + // The key to use for the comparison. For example, the name of the cookie to evaluate. + Key string `json:"key,omitempty"` + + // When true the logic of the rule is inverted. For example, with invert true, + // equal to would become not equal to. Default is false. + Invert bool `json:"invert,omitempty"` + + // The administrative state of the Loadbalancer. A valid value is true (UP) + // or false (DOWN). + AdminStateUp *bool `json:"admin_state_up,omitempty"` +} + +// ToRuleCreateMap builds a request body from CreateRuleOpts. +func (opts CreateRuleOpts) ToRuleCreateMap() (map[string]interface{}, error) { + return golangsdk.BuildRequestBody(opts, "rule") +} + +// CreateRule will create and associate a Rule with a particular L7Policy. +func CreateRule(c *golangsdk.ServiceClient, policyID string, opts CreateRuleOpts) (r CreateRuleResult) { + b, err := opts.ToRuleCreateMap() + if err != nil { + r.Err = err + return + } + _, r.Err = c.Post(ruleRootURL(c, policyID), b, &r.Body, nil) + return +} + +// ListRulesOptsBuilder allows extensions to add additional parameters to the +// ListRules request. +type ListRulesOptsBuilder interface { + ToRulesListQuery() (string, error) +} + +// ListRulesOpts allows the filtering and sorting of paginated collections +// through the API. +type ListRulesOpts struct { + RuleType RuleType `q:"type"` + TenantID string `q:"tenant_id"` + CompareType CompareType `q:"compare_type"` + Value string `q:"value"` + Key string `q:"key"` + Invert bool `q:"invert"` + AdminStateUp bool `q:"admin_state_up"` + ID string `q:"id"` + Limit int `q:"limit"` + Marker string `q:"marker"` + SortKey string `q:"sort_key"` + SortDir string `q:"sort_dir"` +} + +// ToRulesListQuery formats a ListOpts into a query string. +func (opts ListRulesOpts) ToRulesListQuery() (string, error) { + q, err := golangsdk.BuildQueryString(opts) + return q.String(), err +} + +// ListRules returns a Pager which allows you to iterate over a collection of +// rules. It accepts a ListRulesOptsBuilder, which allows you to filter and +// sort the returned collection for greater efficiency. +// +// Default policy settings return only those rules that are owned by the +// project who submits the request, unless an admin user submits the request. +func ListRules(c *golangsdk.ServiceClient, policyID string, opts ListRulesOptsBuilder) pagination.Pager { + url := ruleRootURL(c, policyID) + if opts != nil { + query, err := opts.ToRulesListQuery() + if err != nil { + return pagination.Pager{Err: err} + } + url += query + } + return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page { + return RulePage{pagination.LinkedPageBase{PageResult: r}} + }) +} + +// GetRule retrieves a particular L7Policy Rule based on its unique ID. +func GetRule(c *golangsdk.ServiceClient, policyID string, ruleID string) (r GetRuleResult) { + _, r.Err = c.Get(ruleResourceURL(c, policyID, ruleID), &r.Body, nil) + return +} + +// DeleteRule will remove a Rule from a particular L7Policy. +func DeleteRule(c *golangsdk.ServiceClient, policyID string, ruleID string) (r DeleteRuleResult) { + _, r.Err = c.Delete(ruleResourceURL(c, policyID, ruleID), nil) + return +} + +// UpdateRuleOptsBuilder allows to add additional parameters to the PUT request. +type UpdateRuleOptsBuilder interface { + ToRuleUpdateMap() (map[string]interface{}, error) +} + +// UpdateRuleOpts is the common options struct used in this package's Update +// operation. +type UpdateRuleOpts struct { + // The L7 rule type. One of COOKIE, FILE_TYPE, HEADER, HOST_NAME, or PATH. + RuleType RuleType `json:"type,omitempty"` + + // The comparison type for the L7 rule. One of CONTAINS, ENDS_WITH, EQUAL_TO, REGEX, or STARTS_WITH. + CompareType CompareType `json:"compare_type,omitempty"` + + // The value to use for the comparison. For example, the file type to compare. + Value string `json:"value,omitempty"` + + // The key to use for the comparison. For example, the name of the cookie to evaluate. + Key *string `json:"key,omitempty"` + + // When true the logic of the rule is inverted. For example, with invert true, + // equal to would become not equal to. Default is false. + Invert *bool `json:"invert,omitempty"` + + // The administrative state of the Loadbalancer. A valid value is true (UP) + // or false (DOWN). + AdminStateUp *bool `json:"admin_state_up,omitempty"` +} + +// ToRuleUpdateMap builds a request body from UpdateRuleOpts. +func (opts UpdateRuleOpts) ToRuleUpdateMap() (map[string]interface{}, error) { + b, err := golangsdk.BuildRequestBody(opts, "rule") + if err != nil { + return nil, err + } + + if m := b["rule"].(map[string]interface{}); m["key"] == "" { + m["key"] = nil + } + + return b, nil +} + +// UpdateRule allows Rule to be updated. +func UpdateRule(c *golangsdk.ServiceClient, policyID string, ruleID string, opts UpdateRuleOptsBuilder) (r UpdateRuleResult) { + b, err := opts.ToRuleUpdateMap() + if err != nil { + r.Err = err + return + } + _, r.Err = c.Put(ruleResourceURL(c, policyID, ruleID), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200, 201, 202}, + }) + return +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/l7policies/results.go b/vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/l7policies/results.go new file mode 100644 index 0000000000..2020848814 --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/l7policies/results.go @@ -0,0 +1,245 @@ +package l7policies + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/pagination" +) + +// L7Policy is a collection of L7 rules associated with a Listener, and which +// may also have an association to a back-end pool. +type L7Policy struct { + // The unique ID for the L7 policy. + ID string `json:"id"` + + // Name of the L7 policy. + Name string `json:"name"` + + // The ID of the listener. + ListenerID string `json:"listener_id"` + + // The L7 policy action. One of REDIRECT_TO_POOL, REDIRECT_TO_URL, or REJECT. + Action string `json:"action"` + + // The position of this policy on the listener. + Position int32 `json:"position"` + + // A human-readable description for the resource. + Description string `json:"description"` + + // TenantID is the UUID of the tenant who owns the L7 policy in octavia. + // Only administrative users can specify a project UUID other than their own. + TenantID string `json:"tenant_id"` + + // Requests matching this policy will be redirected to the pool with this ID. + // Only valid if action is REDIRECT_TO_POOL. + RedirectPoolID string `json:"redirect_pool_id"` + + // Requests matching this policy will be redirected to this Listener. + // Only valid if action is REDIRECT_TO_LISTENER. + RedirectListenerID string `json:"redirect_listener_id"` + + // The administrative state of the L7 policy, which is up (true) or down (false). + AdminStateUp bool `json:"admin_state_up"` + + // The provisioning status of the L7 policy. + // This value is ACTIVE, PENDING_* or ERROR. + // This field seems to only be returned during a call to a load balancer's /status + // see: https://github.com/gophercloud/gophercloud/issues/1362 + ProvisioningStatus string `json:"provisioning_status"` + + // The operating status of the L7 policy. + // This field seems to only be returned during a call to a load balancer's /status + // see: https://github.com/gophercloud/gophercloud/issues/1362 + OperatingStatus string `json:"operating_status"` + + // Rules are List of associated L7 rule IDs. + Rules []Rule `json:"rules"` +} + +// Rule represents layer 7 load balancing rule. +type Rule struct { + // The unique ID for the L7 rule. + ID string `json:"id"` + + // The L7 rule type. One of COOKIE, FILE_TYPE, HEADER, HOST_NAME, or PATH. + RuleType string `json:"type"` + + // The comparison type for the L7 rule. One of CONTAINS, ENDS_WITH, EQUAL_TO, REGEX, or STARTS_WITH. + CompareType string `json:"compare_type"` + + // The value to use for the comparison. For example, the file type to compare. + Value string `json:"value"` + + // TenantID is the UUID of the tenant who owns the rule in octavia. + // Only administrative users can specify a project UUID other than their own. + TenantID string `json:"tenant_id"` + + // The key to use for the comparison. For example, the name of the cookie to evaluate. + Key string `json:"key"` + + // When true the logic of the rule is inverted. For example, with invert true, + // equal to would become not equal to. Default is false. + Invert bool `json:"invert"` + + // The administrative state of the L7 rule, which is up (true) or down (false). + AdminStateUp bool `json:"admin_state_up"` + + // The provisioning status of the L7 rule. + // This value is ACTIVE, PENDING_* or ERROR. + // This field seems to only be returned during a call to a load balancer's /status + // see: https://github.com/gophercloud/gophercloud/issues/1362 + ProvisioningStatus string `json:"provisioning_status"` + + // The operating status of the L7 policy. + // This field seems to only be returned during a call to a load balancer's /status + // see: https://github.com/gophercloud/gophercloud/issues/1362 + OperatingStatus string `json:"operating_status"` +} + +type commonResult struct { + golangsdk.Result +} + +// Extract is a function that accepts a result and extracts a l7policy. +func (r commonResult) Extract() (*L7Policy, error) { + var s struct { + L7Policy *L7Policy `json:"l7policy"` + } + err := r.ExtractInto(&s) + return s.L7Policy, err +} + +// CreateResult represents the result of a Create operation. Call its Extract +// method to interpret the result as a L7Policy. +type CreateResult struct { + commonResult +} + +// L7PolicyPage is the page returned by a pager when traversing over a +// collection of l7policies. +type L7PolicyPage struct { + pagination.LinkedPageBase +} + +// NextPageURL is invoked when a paginated collection of l7policies has reached +// the end of a page and the pager seeks to traverse over a new one. In order +// to do this, it needs to construct the next page's URL. +func (r L7PolicyPage) NextPageURL() (string, error) { + var s struct { + Links []golangsdk.Link `json:"l7policies_links"` + } + err := r.ExtractInto(&s) + if err != nil { + return "", err + } + return golangsdk.ExtractNextURL(s.Links) +} + +// IsEmpty checks whether a L7PolicyPage struct is empty. +func (r L7PolicyPage) IsEmpty() (bool, error) { + is, err := ExtractL7Policies(r) + return len(is) == 0, err +} + +// ExtractL7Policies accepts a Page struct, specifically a L7PolicyPage struct, +// and extracts the elements into a slice of L7Policy structs. In other words, +// a generic collection is mapped into a relevant slice. +func ExtractL7Policies(r pagination.Page) ([]L7Policy, error) { + var s struct { + L7Policies []L7Policy `json:"l7policies"` + } + err := (r.(L7PolicyPage)).ExtractInto(&s) + return s.L7Policies, err +} + +// GetResult represents the result of a Get operation. Call its Extract +// method to interpret the result as a L7Policy. +type GetResult struct { + commonResult +} + +// DeleteResult represents the result of a Delete operation. Call its +// ExtractErr method to determine if the request succeeded or failed. +type DeleteResult struct { + golangsdk.ErrResult +} + +// UpdateResult represents the result of an Update operation. Call its Extract +// method to interpret the result as a L7Policy. +type UpdateResult struct { + commonResult +} + +type commonRuleResult struct { + golangsdk.Result +} + +// Extract is a function that accepts a result and extracts a rule. +func (r commonRuleResult) Extract() (*Rule, error) { + var s struct { + Rule *Rule `json:"rule"` + } + err := r.ExtractInto(&s) + return s.Rule, err +} + +// CreateRuleResult represents the result of a CreateRule operation. +// Call its Extract method to interpret it as a Rule. +type CreateRuleResult struct { + commonRuleResult +} + +// RulePage is the page returned by a pager when traversing over a +// collection of Rules in a L7Policy. +type RulePage struct { + pagination.LinkedPageBase +} + +// NextPageURL is invoked when a paginated collection of rules has reached +// the end of a page and the pager seeks to traverse over a new one. In order +// to do this, it needs to construct the next page's URL. +func (r RulePage) NextPageURL() (string, error) { + var s struct { + Links []golangsdk.Link `json:"rules_links"` + } + err := r.ExtractInto(&s) + if err != nil { + return "", err + } + return golangsdk.ExtractNextURL(s.Links) +} + +// IsEmpty checks whether a RulePage struct is empty. +func (r RulePage) IsEmpty() (bool, error) { + is, err := ExtractRules(r) + return len(is) == 0, err +} + +// ExtractRules accepts a Page struct, specifically a RulePage struct, +// and extracts the elements into a slice of Rules structs. In other words, +// a generic collection is mapped into a relevant slice. +func ExtractRules(r pagination.Page) ([]Rule, error) { + var s struct { + Rules []Rule `json:"rules"` + } + err := (r.(RulePage)).ExtractInto(&s) + return s.Rules, err +} + +// GetRuleResult represents the result of a GetRule operation. +// Call its Extract method to interpret it as a Rule. +type GetRuleResult struct { + commonRuleResult +} + +// DeleteRuleResult represents the result of a DeleteRule operation. +// Call its ExtractErr method to determine if the request succeeded or failed. +type DeleteRuleResult struct { + golangsdk.ErrResult +} + +// UpdateRuleResult represents the result of an UpdateRule operation. +// Call its Extract method to interpret it as a Rule. +type UpdateRuleResult struct { + commonRuleResult +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/l7policies/urls.go b/vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/l7policies/urls.go new file mode 100644 index 0000000000..924e93103a --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/l7policies/urls.go @@ -0,0 +1,25 @@ +package l7policies + +import "github.com/huaweicloud/golangsdk" + +const ( + rootPath = "elb" + resourcePath = "l7policies" + rulePath = "rules" +) + +func rootURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL(rootPath, resourcePath) +} + +func resourceURL(c *golangsdk.ServiceClient, id string) string { + return c.ServiceURL(rootPath, resourcePath, id) +} + +func ruleRootURL(c *golangsdk.ServiceClient, policyID string) string { + return c.ServiceURL(rootPath, resourcePath, policyID, rulePath) +} + +func ruleResourceURL(c *golangsdk.ServiceClient, policyID string, ruleID string) string { + return c.ServiceURL(rootPath, resourcePath, policyID, rulePath, ruleID) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 1f4a8dc65a..25699d26fe 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -340,6 +340,7 @@ github.com/huaweicloud/golangsdk/openstack/elb/v2/loadbalancers github.com/huaweicloud/golangsdk/openstack/elb/v3/certificates github.com/huaweicloud/golangsdk/openstack/elb/v3/flavors github.com/huaweicloud/golangsdk/openstack/elb/v3/ipgroups +github.com/huaweicloud/golangsdk/openstack/elb/v3/l7policies github.com/huaweicloud/golangsdk/openstack/elb/v3/listeners github.com/huaweicloud/golangsdk/openstack/elb/v3/loadbalancers github.com/huaweicloud/golangsdk/openstack/elb/v3/pools