diff --git a/docs/data-sources/as_lifecycle_hooks.md b/docs/data-sources/as_lifecycle_hooks.md new file mode 100644 index 0000000000..49665cfc6e --- /dev/null +++ b/docs/data-sources/as_lifecycle_hooks.md @@ -0,0 +1,64 @@ +--- +subcategory: "Auto Scaling" +--- + +# huaweicloud_as_lifecycle_hooks + +Use this data source to get a list of AS scaling lifecycle hooks within HuaweiCloud. + +## Example Usage + +```hcl +variable "scaling_group_id" {} + +data "huaweicloud_as_lifecycle_hooks" "test" { + scaling_group_id = var.scaling_group_id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Optional, String) Specifies the region in which to query the data source. + If omitted, the provider-level region will be used. + +* `scaling_group_id` - (Required, String) Specifies the AS scaling group ID. + +* `name` - (Optional, String) Specifies the lifecycle hook name. + +* `type` - (Optional, String) Specifies the lifecycle hook type. The valid values are as follows: + + **ADD**: The hook suspends the instance when the instance is started. + + **REMOVE**: The hook suspends the instance when the instance is terminated. + +* `default_result` - (Optional, String) Specifies the default lifecycle hook callback action. This action is + performed when the timeout duration expires. The valid values are **ABANDON** and **CONTINUE**, defaults to **ABANDON**. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The data source ID. + +* `lifecycle_hooks` - All AS scaling lifecycle hooks that match the filter parameters. + The [lifecycle_hooks](#attrblock_lifecycle_hooks) structure is documented below. + + +The `lifecycle_hooks` block supports: + +* `name` - The lifecycle hook name. + +* `type` - The lifecycle hook type. + +* `default_result` - The default lifecycle hook callback action. + +* `timeout` - The lifecycle hook timeout duration in the unit of second. + +* `notification_topic_urn` - The unique URN of the notification topic in SMN. + +* `notification_topic_name` - The topic name of notification topic in SMN. + +* `notification_message` - The customized notification. After a notification object is configured, + the SMN service sends your customized notification to the object. + +* `created_at` - The creation time of the lifecycle hooks. diff --git a/huaweicloud/provider.go b/huaweicloud/provider.go index 9f0e13a7e9..66668f99c9 100644 --- a/huaweicloud/provider.go +++ b/huaweicloud/provider.go @@ -396,10 +396,11 @@ func Provider() *schema.Provider { "huaweicloud_apig_environments": apig.DataSourceEnvironments(), "huaweicloud_apig_groups": apig.DataSourceGroups(), - "huaweicloud_as_configurations": as.DataSourceASConfigurations(), - "huaweicloud_as_groups": as.DataSourceASGroups(), - "huaweicloud_as_activity_logs": as.DataSourceActivityLogs(), - "huaweicloud_as_policies": as.DataSourceASPolicies(), + "huaweicloud_as_configurations": as.DataSourceASConfigurations(), + "huaweicloud_as_groups": as.DataSourceASGroups(), + "huaweicloud_as_activity_logs": as.DataSourceActivityLogs(), + "huaweicloud_as_policies": as.DataSourceASPolicies(), + "huaweicloud_as_lifecycle_hooks": as.DataSourceLifeCycleHooks(), "huaweicloud_account": DataSourceAccount(), "huaweicloud_availability_zones": DataSourceAvailabilityZones(), diff --git a/huaweicloud/services/acceptance/as/data_source_huaweicloud_as_lifecycle_hooks_test.go b/huaweicloud/services/acceptance/as/data_source_huaweicloud_as_lifecycle_hooks_test.go new file mode 100644 index 0000000000..8704b7409f --- /dev/null +++ b/huaweicloud/services/acceptance/as/data_source_huaweicloud_as_lifecycle_hooks_test.go @@ -0,0 +1,126 @@ +package as + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance" +) + +func TestAccDataSourceLifecycleHooks_basic(t *testing.T) { + var ( + dataSourceName = "data.huaweicloud_as_lifecycle_hooks.test" + dc = acceptance.InitDataSourceCheck(dataSourceName) + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acceptance.TestAccPreCheck(t) + acceptance.TestAccPreCheckASScalingGroupID(t) + }, + ProviderFactories: acceptance.TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccLifecycleHooks_basic(), + Check: resource.ComposeTestCheckFunc( + dc.CheckResourceExists(), + resource.TestCheckResourceAttrSet(dataSourceName, "scaling_group_id"), + resource.TestCheckOutput("name_filter_is_useful", "true"), + resource.TestCheckOutput("type_filter_is_useful", "true"), + resource.TestCheckOutput("default_result_filter_is_useful", "true"), + ), + }, + }, + }) +} + +func testAccLifecycleHooks_basic() string { + rName := acceptance.RandomAccResourceName() + return fmt.Sprintf(` +%[1]s + +resource "huaweicloud_as_lifecycle_hook" "test1" { + name = "%[2]s1" + type = "ADD" + default_result = "ABANDON" + scaling_group_id = huaweicloud_as_group.acc_as_group.id + notification_topic_urn = huaweicloud_smn_topic.test.topic_urn + notification_message = "This is a test message" +} + +resource "huaweicloud_as_lifecycle_hook" "test2" { + name = "%[2]s2" + type = "REMOVE" + default_result = "CONTINUE" + scaling_group_id = huaweicloud_as_group.acc_as_group.id + notification_topic_urn = huaweicloud_smn_topic.test.topic_urn + notification_message = "This is a test message" +} + +resource "huaweicloud_as_lifecycle_hook" "test3" { + name = "%[2]s3" + type = "ADD" + default_result = "CONTINUE" + scaling_group_id = huaweicloud_as_group.acc_as_group.id + notification_topic_urn = huaweicloud_smn_topic.test.topic_urn + notification_message = "This is a test message" +} + +data "huaweicloud_as_lifecycle_hooks" "test" { + depends_on = [ + huaweicloud_as_lifecycle_hook.test1, + huaweicloud_as_lifecycle_hook.test2, + huaweicloud_as_lifecycle_hook.test3, + ] + + scaling_group_id = huaweicloud_as_group.acc_as_group.id +} + +locals { + name = data.huaweicloud_as_lifecycle_hooks.test.lifecycle_hooks[0].name +} + +data "huaweicloud_as_lifecycle_hooks" "filter_by_name" { + scaling_group_id = huaweicloud_as_group.acc_as_group.id + name = local.name +} + +output "name_filter_is_useful" { + value = length(data.huaweicloud_as_lifecycle_hooks.filter_by_name.lifecycle_hooks) > 0 && alltrue( + [for v in data.huaweicloud_as_lifecycle_hooks.filter_by_name.lifecycle_hooks[*].name : v == local.name] + ) +} + +locals { + type = data.huaweicloud_as_lifecycle_hooks.test.lifecycle_hooks[0].type +} + +data "huaweicloud_as_lifecycle_hooks" "filter_by_type" { + scaling_group_id = huaweicloud_as_group.acc_as_group.id + type = local.type +} + +output "type_filter_is_useful" { + value = length(data.huaweicloud_as_lifecycle_hooks.filter_by_type.lifecycle_hooks) >= 0 && alltrue( + [for v in data.huaweicloud_as_lifecycle_hooks.filter_by_type.lifecycle_hooks[*].type : v == local.type] + ) +} + +locals { + default_result = data.huaweicloud_as_lifecycle_hooks.test.lifecycle_hooks[0].default_result +} + +data "huaweicloud_as_lifecycle_hooks" "filter_by_default_result" { + scaling_group_id = huaweicloud_as_group.acc_as_group.id + default_result = local.default_result +} + +output "default_result_filter_is_useful" { + value = length(data.huaweicloud_as_lifecycle_hooks.filter_by_default_result.lifecycle_hooks) > 0 && alltrue( + [for v in data.huaweicloud_as_lifecycle_hooks.filter_by_default_result.lifecycle_hooks[*].default_result : v == local.default_result] + ) +} +`, testASLifecycleHook_base(rName), rName) +} diff --git a/huaweicloud/services/as/data_source_huaweicloud_as_lifecycle_hooks.go b/huaweicloud/services/as/data_source_huaweicloud_as_lifecycle_hooks.go new file mode 100644 index 0000000000..14b6b0dd40 --- /dev/null +++ b/huaweicloud/services/as/data_source_huaweicloud_as_lifecycle_hooks.go @@ -0,0 +1,160 @@ +package as + +import ( + "context" + "fmt" + + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/chnsz/golangsdk/openstack/autoscaling/v1/lifecyclehooks" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/common" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" +) + +var convertHookTypeMap = map[string]string{ + "INSTANCE_LAUNCHING": "ADD", + "INSTANCE_TERMINATING": "REMOVE", +} + +// API: AS GET /autoscaling-api/v1/{project_id}/scaling_lifecycle_hook/{scaling_group_id}/list +func DataSourceLifeCycleHooks() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceLifeCycleHooksRead, + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Optional: true, + }, + "scaling_group_id": { + Type: schema.TypeString, + Required: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + "type": { + Type: schema.TypeString, + Optional: true, + }, + "default_result": { + Type: schema.TypeString, + Optional: true, + }, + "lifecycle_hooks": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + "default_result": { + Type: schema.TypeString, + Computed: true, + }, + "timeout": { + Type: schema.TypeInt, + Computed: true, + }, + "notification_topic_urn": { + Type: schema.TypeString, + Computed: true, + }, + "notification_topic_name": { + Type: schema.TypeString, + Computed: true, + }, + "notification_message": { + Type: schema.TypeString, + Computed: true, + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceLifeCycleHooksRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cfg := meta.(*config.Config) + region := cfg.GetRegion(d) + + client, err := cfg.AutoscalingV1Client(region) + if err != nil { + return diag.Errorf("error creating AS v1 client: %s", err) + } + + groupID := d.Get("scaling_group_id").(string) + + lifecycleHookList, err := lifecyclehooks.List(client, groupID).Extract() + if err != nil { + return common.CheckDeletedDiag(d, err, "AS lifecycle hooks") + } + + lifecycleHooks, err := flattenLifecycleHooks(d, lifecycleHookList) + if err != nil { + return diag.FromErr(err) + } + + randUUID, err := uuid.GenerateUUID() + if err != nil { + return diag.Errorf("unable to generate ID: %s", err) + } + d.SetId(randUUID) + + mErr := multierror.Append(nil, + d.Set("region", region), + d.Set("lifecycle_hooks", lifecycleHooks), + ) + if mErr.ErrorOrNil() != nil { + return diag.Errorf("error saving lifecycle hooks data source fields: %s", mErr) + } + + return nil +} + +func flattenLifecycleHooks(d *schema.ResourceData, hooks *[]lifecyclehooks.Hook) ([]map[string]interface{}, error) { + rst := make([]map[string]interface{}, 0, len(*hooks)) + for _, hook := range *hooks { + if val, ok := d.GetOk("name"); ok && val.(string) != hook.Name { + continue + } + if val, ok := d.GetOk("type"); ok && val.(string) != hook.Type { + continue + } + if val, ok := d.GetOk("default_result"); ok && val.(string) != hook.DefaultResult { + continue + } + + hookType, ok := convertHookTypeMap[hook.Type] + if !ok { + return nil, fmt.Errorf("lifecycle hook type (%s) is not in the map (%#v)", hook.Type, convertHookTypeMap) + } + lifecycleHookMap := map[string]interface{}{ + "name": hook.Name, + "type": hookType, + "default_result": hook.DefaultResult, + "timeout": hook.Timeout, + "notification_topic_urn": hook.NotificationTopicURN, + "notification_topic_name": hook.NotificationTopicName, + "notification_message": hook.NotificationMetadata, + "created_at": hook.CreateTime, + } + rst = append(rst, lifecycleHookMap) + } + return rst, nil +}