diff --git a/docs/resources/elb_monitor.md b/docs/resources/elb_monitor.md new file mode 100644 index 0000000000..60cd21bc47 --- /dev/null +++ b/docs/resources/elb_monitor.md @@ -0,0 +1,58 @@ +--- +subcategory: "Dedicated Load Balance (Dedicated ELB)" +--- + +# huaweicloud\_elb\_monitor + +Manages an ELB monitor resource within HuaweiCloud. + +## Example Usage + +```hcl +resource "huaweicloud_elb_monitor" "monitor_1" { + protocol = "HTTP" + interval = 30 + timeout = 15 + max_retries = 10 + url_path = "/api" + port = 8888 + pool_id = huaweicloud_elb_pool.test.id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Optional, String, ForceNew) The region in which to create the ELB monitor resource. + If omitted, the provider-level region will be used. + Changing this creates a new monitor. + +* `pool_id` - (Required, String, ForceNew) The id of the pool that this monitor will be assigned to. + +* `protocol` - (Required, String, ForceNew) The type of probe, which is TCP, HTTP, or HTTPS, + that is sent by the load balancer to verify the member state. Changing this + creates a new monitor. + +* `domain_name` - (Optional, String) The Domain Name of the Monitor. + +* `port` - (Optional, Int) Specifies the health check port. The value ranges from 1 to 65535. + +* `interval` - (Required, Int) The time, in seconds, between sending probes to members. + +* `timeout` - (Required, Int) Maximum number of seconds for a monitor to wait for a + ping reply before it times out. The value must be less than the delay + value. + +* `max_retries` - (Required, Int) Number of permissible ping failures before + changing the member's status to INACTIVE. Must be a number between 1 + and 10. + +* `url_path` - (Optional, String) Required for HTTP(S) types. URI path that will be + accessed if monitor type is HTTP or HTTPS. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The unique ID for the monitor. diff --git a/go.mod b/go.mod index b299b469c7..5d8b2a454b 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/hashicorp/errwrap v1.0.0 github.com/hashicorp/go-multierror v1.0.0 github.com/hashicorp/terraform-plugin-sdk v1.16.0 - github.com/huaweicloud/golangsdk v0.0.0-20210524113822-7a55f63ba01a + github.com/huaweicloud/golangsdk v0.0.0-20210525085405-858f9079f00d github.com/jen20/awspolicyequivalence v1.1.0 github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa // indirect github.com/stretchr/testify v1.4.0 diff --git a/go.sum b/go.sum index d17ec45ef7..5e66c1ab52 100644 --- a/go.sum +++ b/go.sum @@ -206,8 +206,8 @@ github.com/hashicorp/terraform-svchost v0.0.0-20191011084731-65d371908596/go.mod github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/huaweicloud/golangsdk v0.0.0-20210524113822-7a55f63ba01a h1:YOG5x5keo4dVV542nonlxCha9V0UvpNFo+lhmfEbhwg= -github.com/huaweicloud/golangsdk v0.0.0-20210524113822-7a55f63ba01a/go.mod h1:fcOI5u+0f62JtJd7zkCch/Z57BNC6bhqb32TKuiF4r0= +github.com/huaweicloud/golangsdk v0.0.0-20210525085405-858f9079f00d h1:0kH5vNsd5m/T1WqMmYZAOpVk75a/MZ6MmUSNLUrqOWY= +github.com/huaweicloud/golangsdk v0.0.0-20210525085405-858f9079f00d/go.mod h1:fcOI5u+0f62JtJd7zkCch/Z57BNC6bhqb32TKuiF4r0= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= diff --git a/huaweicloud/provider.go b/huaweicloud/provider.go index 52a260f42b..b4a8f78834 100644 --- a/huaweicloud/provider.go +++ b/huaweicloud/provider.go @@ -405,6 +405,7 @@ func Provider() terraform.ResourceProvider { "huaweicloud_elb_l7rule": ResourceL7RuleV3(), "huaweicloud_elb_listener": ResourceListenerV3(), "huaweicloud_elb_loadbalancer": ResourceLoadBalancerV3(), + "huaweicloud_elb_monitor": ResourceMonitorV3(), "huaweicloud_elb_ipgroup": ResourceIpGroupV3(), "huaweicloud_elb_pool": ResourcePoolV3(), "huaweicloud_elb_member": ResourceMemberV3(), diff --git a/huaweicloud/resource_huaweicloud_elb_monitor.go b/huaweicloud/resource_huaweicloud_elb_monitor.go new file mode 100644 index 0000000000..bd76316323 --- /dev/null +++ b/huaweicloud/resource_huaweicloud_elb_monitor.go @@ -0,0 +1,181 @@ +package huaweicloud + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + + "github.com/huaweicloud/golangsdk/openstack/elb/v3/monitors" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" +) + +func ResourceMonitorV3() *schema.Resource { + return &schema.Resource{ + Create: resourceMonitorV3Create, + Read: resourceMonitorV3Read, + Update: resourceMonitorV3Update, + Delete: resourceMonitorV3Delete, + + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + + "domain_name": { + Type: schema.TypeString, + Optional: true, + }, + + "pool_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "protocol": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "interval": { + Type: schema.TypeInt, + Required: true, + }, + + "timeout": { + Type: schema.TypeInt, + Required: true, + }, + + "max_retries": { + Type: schema.TypeInt, + Required: true, + }, + + "port": { + Type: schema.TypeInt, + Optional: true, + }, + + "url_path": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + }, + } +} + +func resourceMonitorV3Create(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 := monitors.CreateOpts{ + PoolID: d.Get("pool_id").(string), + Type: d.Get("protocol").(string), + Delay: d.Get("interval").(int), + Timeout: d.Get("timeout").(int), + MaxRetries: d.Get("max_retries").(int), + URLPath: d.Get("url_path").(string), + DomainName: d.Get("domain_name").(string), + MonitorPort: d.Get("port").(int), + } + + log.Printf("[DEBUG] Create Options: %#v", createOpts) + monitor, err := monitors.Create(lbClient, createOpts).Extract() + if err != nil { + return fmt.Errorf("Unable to create monitor: %s", err) + } + + d.SetId(monitor.ID) + + return resourceMonitorV3Read(d, meta) +} + +func resourceMonitorV3Read(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) + } + + monitor, err := monitors.Get(lbClient, d.Id()).Extract() + if err != nil { + return CheckDeleted(d, err, "monitor") + } + + log.Printf("[DEBUG] Retrieved monitor %s: %#v", d.Id(), monitor) + + d.Set("protocol", monitor.Type) + d.Set("interval", monitor.Delay) + d.Set("timeout", monitor.Timeout) + d.Set("max_retries", monitor.MaxRetries) + d.Set("url_path", monitor.URLPath) + d.Set("domain_name", monitor.DomainName) + d.Set("region", GetRegion(d, config)) + if monitor.MonitorPort != 0 { + d.Set("port", monitor.MonitorPort) + } + + return nil +} + +func resourceMonitorV3Update(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 monitors.UpdateOpts + if d.HasChange("url_path") { + updateOpts.URLPath = d.Get("url_path").(string) + } + if d.HasChange("interval") { + updateOpts.Delay = d.Get("interval").(int) + } + if d.HasChange("timeout") { + updateOpts.Timeout = d.Get("timeout").(int) + } + if d.HasChange("max_retries") { + updateOpts.MaxRetries = d.Get("max_retries").(int) + } + if d.HasChange("domain_name") { + updateOpts.DomainName = d.Get("domain_name").(string) + } + if d.HasChange("port") { + updateOpts.MonitorPort = d.Get("port").(int) + } + + log.Printf("[DEBUG] Updating monitor %s with options: %#v", d.Id(), updateOpts) + _, err = monitors.Update(lbClient, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Unable to update monitor %s: %s", d.Id(), err) + } + + return resourceMonitorV3Read(d, meta) +} + +func resourceMonitorV3Delete(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] Deleting monitor %s", d.Id()) + err = monitors.Delete(lbClient, d.Id()).ExtractErr() + if err != nil { + return fmt.Errorf("Unable to delete monitor %s: %s", d.Id(), err) + } + + return nil +} diff --git a/huaweicloud/resource_huaweicloud_elb_monitor_test.go b/huaweicloud/resource_huaweicloud_elb_monitor_test.go new file mode 100644 index 0000000000..0d270727ff --- /dev/null +++ b/huaweicloud/resource_huaweicloud_elb_monitor_test.go @@ -0,0 +1,161 @@ +package huaweicloud + +import ( + "fmt" + "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/monitors" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" +) + +func TestAccElbV3Monitor_basic(t *testing.T) { + var monitor monitors.Monitor + rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + resourceName := "huaweicloud_elb_monitor.monitor_1" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckElbV3MonitorDestroy, + Steps: []resource.TestStep{ + { + Config: testAccElbV3MonitorConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckElbV3MonitorExists(resourceName, &monitor), + resource.TestCheckResourceAttr(resourceName, "interval", "20"), + resource.TestCheckResourceAttr(resourceName, "timeout", "10"), + resource.TestCheckResourceAttr(resourceName, "max_retries", "5"), + resource.TestCheckResourceAttr(resourceName, "url_path", "/aa"), + resource.TestCheckResourceAttr(resourceName, "domain_name", "www.aa.com"), + ), + }, + { + Config: testAccElbV3MonitorConfig_update(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "interval", "30"), + resource.TestCheckResourceAttr(resourceName, "timeout", "15"), + resource.TestCheckResourceAttr(resourceName, "max_retries", "10"), + resource.TestCheckResourceAttr(resourceName, "port", "8888"), + resource.TestCheckResourceAttr(resourceName, "url_path", "/bb"), + resource.TestCheckResourceAttr(resourceName, "domain_name", "www.bb.com"), + ), + }, + }, + }) +} + +func testAccCheckElbV3MonitorDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*config.Config) + elbClient, err := config.ElbV3Client(HW_REGION_NAME) + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud elb client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "huaweicloud_elb_monitor" { + continue + } + + _, err := monitors.Get(elbClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("Monitor still exists: %s", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckElbV3MonitorExists(n string, monitor *monitors.Monitor) 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) + elbClient, err := config.ElbV3Client(HW_REGION_NAME) + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud elb client: %s", err) + } + + found, err := monitors.Get(elbClient, rs.Primary.ID).Extract() + if err != nil { + return err + } + + if found.ID != rs.Primary.ID { + return fmt.Errorf("Monitor not found") + } + + *monitor = *found + + return nil + } +} + +func testAccCheckElbV3MonitorConfig(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_pool" "test" { + name = "%s" + protocol = "HTTP" + lb_method = "LEAST_CONNECTIONS" + loadbalancer_id = huaweicloud_elb_loadbalancer.test.id +} +`, rName, rName) +} + +func testAccElbV3MonitorConfig_basic(rName string) string { + return fmt.Sprintf(` +%s + +resource "huaweicloud_elb_monitor" "monitor_1" { + protocol = "HTTP" + interval = 20 + timeout = 10 + max_retries = 5 + url_path = "/aa" + domain_name = "www.aa.com" + pool_id = huaweicloud_elb_pool.test.id +} +`, testAccCheckElbV3MonitorConfig(rName)) +} + +func testAccElbV3MonitorConfig_update(rName string) string { + return fmt.Sprintf(` +%s + +resource "huaweicloud_elb_monitor" "monitor_1" { + protocol = "HTTP" + interval = 30 + timeout = 15 + max_retries = 10 + url_path = "/bb" + domain_name = "www.bb.com" + port = 8888 + pool_id = huaweicloud_elb_pool.test.id +} +`, testAccCheckElbV3MonitorConfig(rName)) +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/monitors/requests.go b/vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/monitors/requests.go new file mode 100644 index 0000000000..6a23da9dcb --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/monitors/requests.go @@ -0,0 +1,262 @@ +package monitors + +import ( + "fmt" + + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/pagination" +) + +// ListOptsBuilder allows extensions to add additional parameters to the +// List request. +type ListOptsBuilder interface { + ToMonitorListQuery() (string, error) +} + +// ListOpts allows the filtering and sorting of paginated collections through +// the API. Filtering is achieved by passing in struct field values that map to +// the Monitor attributes you want to see returned. SortKey allows you to +// sort by a particular Monitor attribute. SortDir sets the direction, and is +// either `asc' or `desc'. Marker and Limit are used for pagination. +type ListOpts struct { + ID string `q:"id"` + Name string `q:"name"` + TenantID string `q:"tenant_id"` + ProjectID string `q:"project_id"` + PoolID string `q:"pool_id"` + Type string `q:"type"` + Delay int `q:"delay"` + Timeout int `q:"timeout"` + MaxRetries int `q:"max_retries"` + HTTPMethod string `q:"http_method"` + URLPath string `q:"url_path"` + ExpectedCodes string `q:"expected_codes"` + AdminStateUp *bool `q:"admin_state_up"` + Status string `q:"status"` + Limit int `q:"limit"` + Marker string `q:"marker"` + SortKey string `q:"sort_key"` + SortDir string `q:"sort_dir"` +} + +// ToMonitorListQuery formats a ListOpts into a query string. +func (opts ListOpts) ToMonitorListQuery() (string, error) { + q, err := golangsdk.BuildQueryString(opts) + if err != nil { + return "", err + } + return q.String(), nil +} + +// List returns a Pager which allows you to iterate over a collection of +// health monitors. It accepts a ListOpts struct, which allows you to filter and sort +// the returned collection for greater efficiency. +// +// Default policy settings return only those health monitors that are owned by the +// tenant 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.ToMonitorListQuery() + if err != nil { + return pagination.Pager{Err: err} + } + url += query + } + return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page { + return MonitorPage{pagination.LinkedPageBase{PageResult: r}} + }) +} + +// Constants that represent approved monitoring types. +const ( + TypePING = "PING" + TypeTCP = "TCP" + TypeHTTP = "HTTP" + TypeHTTPS = "HTTPS" +) + +var ( + errDelayMustGETimeout = fmt.Errorf("Delay must be greater than or equal to timeout") +) + +// CreateOptsBuilder allows extensions to add additional parameters to the +// List request. +type CreateOptsBuilder interface { + ToMonitorCreateMap() (map[string]interface{}, error) +} + +// CreateOpts is the common options struct used in this package's Create +// operation. +type CreateOpts struct { + // The Pool to Monitor. + PoolID string `json:"pool_id" required:"true"` + + // The type of probe, which is PING, TCP, HTTP, or HTTPS, that is + // sent by the load balancer to verify the member state. + Type string `json:"type" required:"true"` + + // The time, in seconds, between sending probes to members. + Delay int `json:"delay" required:"true"` + + // Maximum number of seconds for a Monitor to wait for a ping reply + // before it times out. The value must be less than the delay value. + Timeout int `json:"timeout" required:"true"` + + // Number of permissible ping failures before changing the member's + // status to INACTIVE. Must be a number between 1 and 10. + MaxRetries int `json:"max_retries" required:"true"` + + // URI path that will be accessed if Monitor type is HTTP or HTTPS. + // Required for HTTP(S) types. + URLPath string `json:"url_path,omitempty"` + + // Domain Name. + DomainName string `json:"domain_name,omitempty"` + + // The HTTP method used for requests by the Monitor. If this attribute + // is not specified, it defaults to "GET". + HTTPMethod string `json:"http_method,omitempty"` + + // Expected HTTP codes for a passing HTTP(S) Monitor. You can either specify + // a single status like "200", or a range like "200-202". + ExpectedCodes string `json:"expected_codes,omitempty"` + + // TenantID is the UUID of the project who owns the Monitor. + // Only administrative users can specify a project UUID other than their own. + TenantID string `json:"tenant_id,omitempty"` + + // ProjectID is the UUID of the project who owns the Monitor. + // Only administrative users can specify a project UUID other than their own. + ProjectID string `json:"project_id,omitempty"` + + // The Name of the Monitor. + Name string `json:"name,omitempty"` + + // The administrative state of the Monitor. A valid value is true (UP) + // or false (DOWN). + AdminStateUp *bool `json:"admin_state_up,omitempty"` + + // The Port of the Monitor. + MonitorPort int `json:"monitor_port,omitempty"` +} + +// ToMonitorCreateMap builds a request body from CreateOpts. +func (opts CreateOpts) ToMonitorCreateMap() (map[string]interface{}, error) { + if opts.Type == TypeHTTP || opts.Type == TypeHTTPS { + if opts.URLPath == "" { + return nil, fmt.Errorf("url_path must be provided for HTTP and HTTPS") + } + } + + b, err := golangsdk.BuildRequestBody(opts, "healthmonitor") + if err != nil { + return nil, err + } + + return b, nil +} + +/* + Create is an operation which provisions a new Health Monitor. There are + different types of Monitor you can provision: PING, TCP or HTTP(S). Below + are examples of how to create each one. + + Here is an example config struct to use when creating a PING or TCP Monitor: + + CreateOpts{Type: TypePING, Delay: 20, Timeout: 10, MaxRetries: 3} + CreateOpts{Type: TypeTCP, Delay: 20, Timeout: 10, MaxRetries: 3} + + Here is an example config struct to use when creating a HTTP(S) Monitor: + + CreateOpts{Type: TypeHTTP, Delay: 20, Timeout: 10, MaxRetries: 3, + HttpMethod: "HEAD", ExpectedCodes: "200", PoolID: "2c946bfc-1804-43ab-a2ff-58f6a762b505"} +*/ +func Create(c *golangsdk.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { + b, err := opts.ToMonitorCreateMap() + if err != nil { + r.Err = err + return + } + _, r.Err = c.Post(rootURL(c), b, &r.Body, nil) + return +} + +// Get retrieves a particular Health Monitor 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 +} + +// UpdateOptsBuilder allows extensions to add additional parameters to the +// Update request. +type UpdateOptsBuilder interface { + ToMonitorUpdateMap() (map[string]interface{}, error) +} + +// UpdateOpts is the common options struct used in this package's Update +// operation. +type UpdateOpts struct { + // The time, in seconds, between sending probes to members. + Delay int `json:"delay,omitempty"` + + // Maximum number of seconds for a Monitor to wait for a ping reply + // before it times out. The value must be less than the delay value. + Timeout int `json:"timeout,omitempty"` + + // Number of permissible ping failures before changing the member's + // status to INACTIVE. Must be a number between 1 and 10. + MaxRetries int `json:"max_retries,omitempty"` + + // URI path that will be accessed if Monitor type is HTTP or HTTPS. + // Required for HTTP(S) types. + URLPath string `json:"url_path,omitempty"` + + // Domain Name. + DomainName string `json:"domain_name,omitempty"` + + // The HTTP method used for requests by the Monitor. If this attribute + // is not specified, it defaults to "GET". Required for HTTP(S) types. + HTTPMethod string `json:"http_method,omitempty"` + + // Expected HTTP codes for a passing HTTP(S) Monitor. You can either specify + // a single status like "200", or a range like "200-202". Required for HTTP(S) + // types. + ExpectedCodes string `json:"expected_codes,omitempty"` + + // The Name of the Monitor. + Name string `json:"name,omitempty"` + + // The administrative state of the Monitor. A valid value is true (UP) + // or false (DOWN). + AdminStateUp *bool `json:"admin_state_up,omitempty"` + + // The Port of the Monitor. + MonitorPort int `json:"monitor_port,omitempty"` +} + +// ToMonitorUpdateMap builds a request body from UpdateOpts. +func (opts UpdateOpts) ToMonitorUpdateMap() (map[string]interface{}, error) { + return golangsdk.BuildRequestBody(opts, "healthmonitor") +} + +// Update is an operation which modifies the attributes of the specified +// Monitor. +func Update(c *golangsdk.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { + b, err := opts.ToMonitorUpdateMap() + if err != nil { + r.Err = err + return + } + + _, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200, 202}, + }) + return +} + +// Delete will permanently delete a particular Monitor based on its unique ID. +func Delete(c *golangsdk.ServiceClient, id string) (r DeleteResult) { + _, r.Err = c.Delete(resourceURL(c, id), nil) + return +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/monitors/results.go b/vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/monitors/results.go new file mode 100644 index 0000000000..c64c744324 --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/monitors/results.go @@ -0,0 +1,159 @@ +package monitors + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/pagination" +) + +type PoolID struct { + ID string `json:"id"` +} + +// Monitor represents a load balancer health monitor. A health monitor is used +// to determine whether or not back-end members of the VIP's pool are usable +// for processing a request. A pool can have several health monitors associated +// with it. There are different types of health monitors supported: +// +// PING: used to ping the members using ICMP. +// TCP: used to connect to the members using TCP. +// HTTP: used to send an HTTP request to the member. +// HTTPS: used to send a secure HTTP request to the member. +// +// When a pool has several monitors associated with it, each member of the pool +// is monitored by all these monitors. If any monitor declares the member as +// unhealthy, then the member status is changed to INACTIVE and the member +// won't participate in its pool's load balancing. In other words, ALL monitors +// must declare the member to be healthy for it to stay ACTIVE. +type Monitor struct { + // The unique ID for the Monitor. + ID string `json:"id"` + + // The Name of the Monitor. + Name string `json:"name"` + + // TenantID is the owner of the Monitor. + TenantID string `json:"tenant_id"` + + // The type of probe sent by the load balancer to verify the member state, + // which is PING, TCP, HTTP, or HTTPS. + Type string `json:"type"` + + // The time, in seconds, between sending probes to members. + Delay int `json:"delay"` + + // The maximum number of seconds for a monitor to wait for a connection to be + // established before it times out. This value must be less than the delay + // value. + Timeout int `json:"timeout"` + + // Number of allowed connection failures before changing the status of the + // member to INACTIVE. A valid value is from 1 to 10. + MaxRetries int `json:"max_retries"` + + // The HTTP method that the monitor uses for requests. + HTTPMethod string `json:"http_method"` + + // The HTTP path of the request sent by the monitor to test the health of a + // member. Must be a string beginning with a forward slash (/). + URLPath string `json:"url_path" ` + + // Domain Name. + DomainName string `json:"domain_name" ` + + // Expected HTTP codes for a passing HTTP(S) monitor. + ExpectedCodes string `json:"expected_codes"` + + // The administrative state of the health monitor, which is up (true) or + // down (false). + AdminStateUp bool `json:"admin_state_up"` + + // The Port of the Monitor. + MonitorPort int `json:"monitor_port"` + + // The status of the health monitor. Indicates whether the health monitor is + // operational. + Status string `json:"status"` + + // List of pools that are associated with the health monitor. + Pools []PoolID `json:"pools"` + + // The provisioning status of the monitor. + // This value is ACTIVE, PENDING_* or ERROR. + ProvisioningStatus string `json:"provisioning_status"` +} + +// MonitorPage is the page returned by a pager when traversing over a +// collection of health monitors. +type MonitorPage struct { + pagination.LinkedPageBase +} + +// NextPageURL is invoked when a paginated collection of monitors 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 MonitorPage) NextPageURL() (string, error) { + var s struct { + Links []golangsdk.Link `json:"healthmonitors_links"` + } + + err := r.ExtractInto(&s) + if err != nil { + return "", err + } + + return golangsdk.ExtractNextURL(s.Links) +} + +// IsEmpty checks whether a MonitorPage struct is empty. +func (r MonitorPage) IsEmpty() (bool, error) { + is, err := ExtractMonitors(r) + return len(is) == 0, err +} + +// ExtractMonitors accepts a Page struct, specifically a MonitorPage struct, +// and extracts the elements into a slice of Monitor structs. In other words, +// a generic collection is mapped into a relevant slice. +func ExtractMonitors(r pagination.Page) ([]Monitor, error) { + var s struct { + Monitors []Monitor `json:"healthmonitors"` + } + err := (r.(MonitorPage)).ExtractInto(&s) + return s.Monitors, err +} + +type commonResult struct { + golangsdk.Result +} + +// Extract is a function that accepts a result and extracts a monitor. +func (r commonResult) Extract() (*Monitor, error) { + var s struct { + Monitor *Monitor `json:"healthmonitor"` + } + err := r.ExtractInto(&s) + return s.Monitor, err +} + +// CreateResult represents the result of a create operation. Call its Extract +// method to interpret it as a Monitor. +type CreateResult struct { + commonResult +} + +// GetResult represents the result of a get operation. Call its Extract +// method to interpret it as a Monitor. +type GetResult struct { + commonResult +} + +// UpdateResult represents the result of an update operation. Call its Extract +// method to interpret it as a Monitor. +type UpdateResult struct { + commonResult +} + +// DeleteResult represents the result of a delete operation. Call its +// ExtractErr method to determine if the result succeeded or failed. +type DeleteResult struct { + golangsdk.ErrResult +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/monitors/urls.go b/vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/monitors/urls.go new file mode 100644 index 0000000000..1cbecb17b4 --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/elb/v3/monitors/urls.go @@ -0,0 +1,16 @@ +package monitors + +import "github.com/huaweicloud/golangsdk" + +const ( + rootPath = "elb" + resourcePath = "healthmonitors" +) + +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) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 25699d26fe..2fd9e963e8 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -267,7 +267,7 @@ github.com/hashicorp/terraform-svchost/auth github.com/hashicorp/terraform-svchost/disco # github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d github.com/hashicorp/yamux -# github.com/huaweicloud/golangsdk v0.0.0-20210524113822-7a55f63ba01a +# github.com/huaweicloud/golangsdk v0.0.0-20210525085405-858f9079f00d ## explicit github.com/huaweicloud/golangsdk github.com/huaweicloud/golangsdk/internal @@ -343,6 +343,7 @@ 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/monitors github.com/huaweicloud/golangsdk/openstack/elb/v3/pools github.com/huaweicloud/golangsdk/openstack/eps/v1/enterpriseprojects github.com/huaweicloud/golangsdk/openstack/evs/v2/snapshots