From 7b0ad180957d507ff1070a1a7ea58ecacb80a603 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 21 Feb 2022 21:08:24 +0200 Subject: [PATCH 1/6] opsworks ecs --- .changelog/12495.txt | 3 + internal/provider/provider.go | 33 ++-- .../service/opsworks/ecs_cluster_layer.go | 25 +++ .../opsworks/ecs_cluster_layer_test.go | 150 ++++++++++++++++++ internal/service/opsworks/layers.go | 150 +++++++++++++----- internal/service/opsworks/stack_test.go | 3 +- .../opsworks_ecs_cluster_layer.html.markdown | 68 ++++++++ 7 files changed, 371 insertions(+), 61 deletions(-) create mode 100644 .changelog/12495.txt create mode 100644 internal/service/opsworks/ecs_cluster_layer.go create mode 100644 internal/service/opsworks/ecs_cluster_layer_test.go create mode 100644 website/docs/r/opsworks_ecs_cluster_layer.html.markdown diff --git a/.changelog/12495.txt b/.changelog/12495.txt new file mode 100644 index 00000000000..7f71dacdc30 --- /dev/null +++ b/.changelog/12495.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_opsworks_ecs_cluster_layer +``` \ No newline at end of file diff --git a/internal/provider/provider.go b/internal/provider/provider.go index c8e00839e98..1a648e70418 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -1564,22 +1564,23 @@ func Provider() *schema.Provider { "aws_networkfirewall_resource_policy": networkfirewall.ResourceResourcePolicy(), "aws_networkfirewall_rule_group": networkfirewall.ResourceRuleGroup(), - "aws_opsworks_application": opsworks.ResourceApplication(), - "aws_opsworks_custom_layer": opsworks.ResourceCustomLayer(), - "aws_opsworks_ganglia_layer": opsworks.ResourceGangliaLayer(), - "aws_opsworks_haproxy_layer": opsworks.ResourceHAProxyLayer(), - "aws_opsworks_instance": opsworks.ResourceInstance(), - "aws_opsworks_java_app_layer": opsworks.ResourceJavaAppLayer(), - "aws_opsworks_memcached_layer": opsworks.ResourceMemcachedLayer(), - "aws_opsworks_mysql_layer": opsworks.ResourceMySQLLayer(), - "aws_opsworks_nodejs_app_layer": opsworks.ResourceNodejsAppLayer(), - "aws_opsworks_permission": opsworks.ResourcePermission(), - "aws_opsworks_php_app_layer": opsworks.ResourcePHPAppLayer(), - "aws_opsworks_rails_app_layer": opsworks.ResourceRailsAppLayer(), - "aws_opsworks_rds_db_instance": opsworks.ResourceRDSDBInstance(), - "aws_opsworks_stack": opsworks.ResourceStack(), - "aws_opsworks_static_web_layer": opsworks.ResourceStaticWebLayer(), - "aws_opsworks_user_profile": opsworks.ResourceUserProfile(), + "aws_opsworks_application": opsworks.ResourceApplication(), + "aws_opsworks_custom_layer": opsworks.ResourceCustomLayer(), + "aws_opsworks_ecs_cluster_layer": opsworks.ResourceEcsClusterLayer(), + "aws_opsworks_ganglia_layer": opsworks.ResourceGangliaLayer(), + "aws_opsworks_haproxy_layer": opsworks.ResourceHAProxyLayer(), + "aws_opsworks_instance": opsworks.ResourceInstance(), + "aws_opsworks_java_app_layer": opsworks.ResourceJavaAppLayer(), + "aws_opsworks_memcached_layer": opsworks.ResourceMemcachedLayer(), + "aws_opsworks_mysql_layer": opsworks.ResourceMySQLLayer(), + "aws_opsworks_nodejs_app_layer": opsworks.ResourceNodejsAppLayer(), + "aws_opsworks_permission": opsworks.ResourcePermission(), + "aws_opsworks_php_app_layer": opsworks.ResourcePHPAppLayer(), + "aws_opsworks_rails_app_layer": opsworks.ResourceRailsAppLayer(), + "aws_opsworks_rds_db_instance": opsworks.ResourceRDSDBInstance(), + "aws_opsworks_stack": opsworks.ResourceStack(), + "aws_opsworks_static_web_layer": opsworks.ResourceStaticWebLayer(), + "aws_opsworks_user_profile": opsworks.ResourceUserProfile(), "aws_organizations_account": organizations.ResourceAccount(), "aws_organizations_delegated_administrator": organizations.ResourceDelegatedAdministrator(), diff --git a/internal/service/opsworks/ecs_cluster_layer.go b/internal/service/opsworks/ecs_cluster_layer.go new file mode 100644 index 00000000000..ec7c512068f --- /dev/null +++ b/internal/service/opsworks/ecs_cluster_layer.go @@ -0,0 +1,25 @@ +package opsworks + +import ( + "github.com/aws/aws-sdk-go/service/opsworks" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-aws/internal/verify" +) + +func ResourceEcsClusterLayer() *schema.Resource { + layerType := &opsworksLayerType{ + TypeName: opsworks.LayerTypeEcsCluster, + DefaultLayerName: "Ecs Cluster", + + Attributes: map[string]*opsworksLayerTypeAttribute{ + "ecs_cluster_arn": { + AttrName: opsworks.LayerAttributesKeysEcsClusterArn, + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + }, + } + + return layerType.SchemaResource() +} diff --git a/internal/service/opsworks/ecs_cluster_layer_test.go b/internal/service/opsworks/ecs_cluster_layer_test.go new file mode 100644 index 00000000000..2824bfb18a5 --- /dev/null +++ b/internal/service/opsworks/ecs_cluster_layer_test.go @@ -0,0 +1,150 @@ +package opsworks_test + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/service/opsworks" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" +) + +// These tests assume the existence of predefined Opsworks IAM roles named `aws-opsworks-ec2-role` +// and `aws-opsworks-service-role`. + +func TestAccOpsWorksEcsClusterLayer_basic(t *testing.T) { + var opslayer opsworks.Layer + stackName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_opsworks_ecs_cluster_layer.test" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(opsworks.EndpointsID, t) }, + ErrorCheck: acctest.ErrorCheck(t, opsworks.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckEcsClusterLayerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEcsClusterLayerVPCCreateConfig(stackName), + Check: resource.ComposeTestCheckFunc( + testAccCheckLayerExists(resourceName, &opslayer), + resource.TestCheckResourceAttr(resourceName, "name", stackName)), + }, + }, + }) +} + +func TestAccOpsWorksEcsClusterLayer_tags(t *testing.T) { + var opslayer opsworks.Layer + stackName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_opsworks_ecs_cluster_layer.test" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(opsworks.EndpointsID, t) }, + ErrorCheck: acctest.ErrorCheck(t, opsworks.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckEcsClusterLayerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEcsClusterLayerTags1Config(stackName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckLayerExists(resourceName, &opslayer), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + Config: testAccEcsClusterLayerTags2Config(stackName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckLayerExists(resourceName, &opslayer), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccEcsClusterLayerTags1Config(stackName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckLayerExists(resourceName, &opslayer), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + +func testAccCheckEcsClusterLayerDestroy(s *terraform.State) error { + return testAccCheckLayerDestroy("aws_opsworks_ecs_cluster_layer", s) +} + +func testAccEcsClusterLayerVPCCreateConfig(name string) string { + return testAccStackVPCCreateConfig(name) + + testAccCustomLayerSecurityGroups(name) + + fmt.Sprintf(` +resource "aws_ecs_cluster" "test" { + name = %[1]q +} + +resource "aws_opsworks_ecs_cluster_layer" "test" { + stack_id = aws_opsworks_stack.tf-acc.id + name = %[1]q + ecs_cluster_arn = aws_ecs_cluster.test.arn + + custom_security_group_ids = [ + aws_security_group.tf-ops-acc-layer1.id, + aws_security_group.tf-ops-acc-layer2.id, + ] +} +`, name) +} + +func testAccEcsClusterLayerTags1Config(name, tagKey1, tagValue1 string) string { + return testAccStackVPCCreateConfig(name) + + testAccCustomLayerSecurityGroups(name) + + fmt.Sprintf(` +resource "aws_ecs_cluster" "test" { + name = %[1]q +} + +resource "aws_opsworks_ecs_cluster_layer" "test" { + stack_id = aws_opsworks_stack.tf-acc.id + name = %[1]q + ecs_cluster_arn = aws_ecs_cluster.test.arn + + custom_security_group_ids = [ + aws_security_group.tf-ops-acc-layer1.id, + aws_security_group.tf-ops-acc-layer2.id, + ] + + tags = { + %[2]q = %[3]q + } +} +`, name, tagKey1, tagValue1) +} + +func testAccEcsClusterLayerTags2Config(name, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return testAccStackVPCCreateConfig(name) + + testAccCustomLayerSecurityGroups(name) + + fmt.Sprintf(` +resource "aws_ecs_cluster" "test" { + name = %[1]q +} + +resource "aws_opsworks_ecs_cluster_layer" "test" { + stack_id = aws_opsworks_stack.tf-acc.id + name = %[1]q + ecs_cluster_arn = aws_ecs_cluster.test.arn + + custom_security_group_ids = [ + aws_security_group.tf-ops-acc-layer1.id, + aws_security_group.tf-ops-acc-layer2.id, + ] + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, name, tagKey1, tagValue1, tagKey2, tagValue2) +} diff --git a/internal/service/opsworks/layers.go b/internal/service/opsworks/layers.go index 5a610839e30..7dfaaf809e8 100644 --- a/internal/service/opsworks/layers.go +++ b/internal/service/opsworks/layers.go @@ -30,11 +30,12 @@ import ( // layer resource types, which have names matching aws_opsworks_*_layer . type opsworksLayerTypeAttribute struct { - AttrName string - Type schema.ValueType - Default interface{} - Required bool - WriteOnly bool + AttrName string + Type schema.ValueType + Default interface{} + Required bool + WriteOnly bool + ValidateFunc schema.SchemaValidateFunc } type opsworksLayerType struct { @@ -322,10 +323,11 @@ func (lt *opsworksLayerType) SchemaResource() *schema.Resource { for key, def := range lt.Attributes { resourceSchema[key] = &schema.Schema{ - Type: def.Type, - Default: def.Default, - Required: def.Required, - Optional: !def.Required, + Type: def.Type, + Default: def.Default, + Required: def.Required, + Optional: !def.Required, + ValidateFunc: def.ValidateFunc, } } @@ -495,6 +497,19 @@ func (lt *opsworksLayerType) Create(d *schema.ResourceData, meta interface{}) er log.Printf("[DEBUG] Creating OpsWorks layer: %s", d.Id()) + if v, ok := d.GetOk("ecs_cluster_arn"); ok { + ecsClusterArn := v.(string) + //Need to attach the ECS Cluster to the stack before creating the layer + log.Printf("[DEBUG] Attaching ECS Cluster: %s", ecsClusterArn) + _, err := conn.RegisterEcsCluster(&opsworks.RegisterEcsClusterInput{ + EcsClusterArn: aws.String(ecsClusterArn), + StackId: req.StackId, + }) + if err != nil { + return err + } + } + resp, err := conn.CreateLayer(req) if err != nil { return err @@ -535,40 +550,77 @@ func (lt *opsworksLayerType) Create(d *schema.ResourceData, meta interface{}) er func (lt *opsworksLayerType) Update(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).OpsWorksConn - attributes, err := lt.AttributeMap(d) - if err != nil { - return err - } - req := &opsworks.UpdateLayerInput{ - LayerId: aws.String(d.Id()), - AutoAssignElasticIps: aws.Bool(d.Get("auto_assign_elastic_ips").(bool)), - AutoAssignPublicIps: aws.Bool(d.Get("auto_assign_public_ips").(bool)), - CustomInstanceProfileArn: aws.String(d.Get("custom_instance_profile_arn").(string)), - CustomRecipes: lt.CustomRecipes(d), - CustomSecurityGroupIds: flex.ExpandStringSet(d.Get("custom_security_group_ids").(*schema.Set)), - EnableAutoHealing: aws.Bool(d.Get("auto_healing").(bool)), - InstallUpdatesOnBoot: aws.Bool(d.Get("install_updates_on_boot").(bool)), - LifecycleEventConfiguration: lt.LifecycleEventConfiguration(d), - Name: aws.String(d.Get("name").(string)), - Packages: flex.ExpandStringSet(d.Get("system_packages").(*schema.Set)), - UseEbsOptimizedInstances: aws.Bool(d.Get("use_ebs_optimized_instances").(bool)), - Attributes: attributes, - VolumeConfigurations: lt.VolumeConfigurations(d), - } + if d.HasChangesExcept("ecs_cluster_arn", "elastic_load_balancer", "tags", "tags_all") { + attributes, err := lt.AttributeMap(d) + if err != nil { + return err + } - if v, ok := d.GetOk("cloudwatch_configuration"); ok { - req.CloudWatchLogsConfiguration = expandOpsworksCloudWatchConfig(v.([]interface{})) - } + req := &opsworks.UpdateLayerInput{ + LayerId: aws.String(d.Id()), + AutoAssignElasticIps: aws.Bool(d.Get("auto_assign_elastic_ips").(bool)), + AutoAssignPublicIps: aws.Bool(d.Get("auto_assign_public_ips").(bool)), + CustomInstanceProfileArn: aws.String(d.Get("custom_instance_profile_arn").(string)), + CustomRecipes: lt.CustomRecipes(d), + CustomSecurityGroupIds: flex.ExpandStringSet(d.Get("custom_security_group_ids").(*schema.Set)), + EnableAutoHealing: aws.Bool(d.Get("auto_healing").(bool)), + InstallUpdatesOnBoot: aws.Bool(d.Get("install_updates_on_boot").(bool)), + LifecycleEventConfiguration: lt.LifecycleEventConfiguration(d), + Name: aws.String(d.Get("name").(string)), + Packages: flex.ExpandStringSet(d.Get("system_packages").(*schema.Set)), + UseEbsOptimizedInstances: aws.Bool(d.Get("use_ebs_optimized_instances").(bool)), + Attributes: attributes, + VolumeConfigurations: lt.VolumeConfigurations(d), + } - if lt.CustomShortName { - req.Shortname = aws.String(d.Get("short_name").(string)) - } else { - req.Shortname = aws.String(lt.TypeName) + if v, ok := d.GetOk("cloudwatch_configuration"); ok { + req.CloudWatchLogsConfiguration = expandOpsworksCloudWatchConfig(v.([]interface{})) + } + + if lt.CustomShortName { + req.Shortname = aws.String(d.Get("short_name").(string)) + } else { + req.Shortname = aws.String(lt.TypeName) + } + + req.CustomJson = aws.String(d.Get("custom_json").(string)) + + log.Printf("[DEBUG] Updating OpsWorks layer: %s", d.Id()) + + _, err = conn.UpdateLayer(req) + if err != nil { + return err + } } - req.CustomJson = aws.String(d.Get("custom_json").(string)) + if d.HasChange("ecs_cluster_arn") { + stackID := aws.String(d.Get("stack_id").(string)) + ecso, ecsn := d.GetChange("ecs_cluster_arn") + ecsClusterOld := aws.String(ecso.(string)) + ecsClusterNew := aws.String(ecsn.(string)) - log.Printf("[DEBUG] Updating OpsWorks layer: %s", d.Id()) + if ecsClusterOld != nil && *ecsClusterOld != "" { + log.Printf("[DEBUG] Dettaching ecs cluster: %s", *ecsClusterOld) + _, err := conn.DeregisterEcsCluster(&opsworks.DeregisterEcsClusterInput{ + EcsClusterArn: ecsClusterOld, + }) + + if err != nil { + return err + } + } + + if ecsClusterNew != nil && *ecsClusterNew != "" { + log.Printf("[DEBUG] Attaching ECS Cluster: %s", *ecsClusterNew) + _, err := conn.RegisterEcsCluster(&opsworks.RegisterEcsClusterInput{ + EcsClusterArn: ecsClusterNew, + StackId: stackID, + }) + if err != nil { + return err + } + } + } if d.HasChange("elastic_load_balancer") { lbo, lbn := d.GetChange("elastic_load_balancer") @@ -599,11 +651,6 @@ func (lt *opsworksLayerType) Update(d *schema.ResourceData, meta interface{}) er } } - _, err = conn.UpdateLayer(req) - if err != nil { - return err - } - if d.HasChange("tags_all") { o, n := d.GetChange("tags_all") @@ -626,7 +673,22 @@ func (lt *opsworksLayerType) Delete(d *schema.ResourceData, meta interface{}) er log.Printf("[DEBUG] Deleting OpsWorks layer: %s", d.Id()) _, err := conn.DeleteLayer(req) - return err + if err != nil { + return err + } + + if v, ok := d.GetOk("ecs_cluster_arn"); ok { + ecsClusterArn := v.(string) + log.Printf("[DEBUG] Detaching ECS Cluster: %s", ecsClusterArn) + _, err := conn.DeregisterEcsCluster(&opsworks.DeregisterEcsClusterInput{ + EcsClusterArn: aws.String(ecsClusterArn), + }) + if err != nil { + return err + } + } + + return nil } func (lt *opsworksLayerType) AttributeMap(d *schema.ResourceData) (map[string]*string, error) { diff --git a/internal/service/opsworks/stack_test.go b/internal/service/opsworks/stack_test.go index d2897696615..0e21d3c9a38 100644 --- a/internal/service/opsworks/stack_test.go +++ b/internal/service/opsworks/stack_test.go @@ -1066,7 +1066,8 @@ resource "aws_iam_role_policy" "opsworks_service" { "iam:PassRole", "cloudwatch:GetMetricStatistics", "elasticloadbalancing:*", - "rds:*" + "rds:*", + "ecs:*" ], "Effect": "Allow", "Resource": [ diff --git a/website/docs/r/opsworks_ecs_cluster_layer.html.markdown b/website/docs/r/opsworks_ecs_cluster_layer.html.markdown new file mode 100644 index 00000000000..6eebb661d21 --- /dev/null +++ b/website/docs/r/opsworks_ecs_cluster_layer.html.markdown @@ -0,0 +1,68 @@ +--- +subcategory: "OpsWorks" +layout: "aws" +page_title: "AWS: aws_opsworks_ecs_cluster_layer" +description: |- + Provides an OpsWorks HAProxy layer resource. +--- + +# Resource: aws_opsworks_ecs_cluster_layer + +Provides an OpsWorks ECS Cluster layer resource. + +## Example Usage + +```terraform +resource "aws_opsworks_ecs_cluster_layer" "example" { + stack_id = aws_opsworks_stack.example.id + ecs_cluster_arn = aws_ecs_cluster.example.arn +} +``` + +## Argument Reference + +The following arguments are supported: + +* `stack_id` - (Required) The id of the stack the layer will belong to. +* `ecs_cluster_arn` - (Required) The ECS Cluster ARN of the layer. +* `name` - (Optional) A human-readable name for the layer. +* `auto_assign_elastic_ips` - (Optional) Whether to automatically assign an elastic IP address to the layer's instances. +* `auto_assign_public_ips` - (Optional) For stacks belonging to a VPC, whether to automatically assign a public IP address to each of the layer's instances. +* `custom_instance_profile_arn` - (Optional) The ARN of an IAM profile that will be used for the layer's instances. +* `custom_security_group_ids` - (Optional) Ids for a set of security groups to apply to the layer's instances. +* `auto_healing` - (Optional) Whether to enable auto-healing for the layer. +* `install_updates_on_boot` - (Optional) Whether to install OS and package updates on each instance when it boots. +* `instance_shutdown_timeout` - (Optional) The time, in seconds, that OpsWorks will wait for Chef to complete after triggering the Shutdown event. +* `elastic_load_balancer` - (Optional) Name of an Elastic Load Balancer to attach to this layer +* `drain_elb_on_shutdown` - (Optional) Whether to enable Elastic Load Balancing connection draining. +* `system_packages` - (Optional) Names of a set of system packages to install on the layer's instances. +* `use_ebs_optimized_instances` - (Optional) Whether to use EBS-optimized instances. +* `ebs_volume` - (Optional) `ebs_volume` blocks, as described below, will each create an EBS volume and connect it to the layer's instances. +* `custom_json` - (Optional) Custom JSON attributes to apply to the layer. +* `tags` - (Optional) A mapping of tags to assign to the resource. + +The following extra optional arguments, all lists of Chef recipe names, allow +custom Chef recipes to be applied to layer instances at the five different +lifecycle events, if custom cookbooks are enabled on the layer's stack: + +* `custom_configure_recipes` +* `custom_deploy_recipes` +* `custom_setup_recipes` +* `custom_shutdown_recipes` +* `custom_undeploy_recipes` + +An `ebs_volume` block supports the following arguments: + +* `mount_point` - (Required) The path to mount the EBS volume on the layer's instances. +* `size` - (Required) The size of the volume in gigabytes. +* `number_of_disks` - (Required) The number of disks to use for the EBS volume. +* `raid_level` - (Required) The RAID level to use for the volume. +* `type` - (Optional) The type of volume to create. This may be `standard` (the default), `io1` or `gp2`. +* `iops` - (Optional) For PIOPS volumes, the IOPS per disk. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The id of the layer. +* `arn` - The Amazon Resource Name(ARN) of the layer. \ No newline at end of file From becfc50daa98c4942c4702857721cd23adf715c9 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 21 Feb 2022 21:26:44 +0200 Subject: [PATCH 2/6] error messages + better test --- .../opsworks/ecs_cluster_layer_test.go | 4 +- internal/service/opsworks/layers.go | 38 +++++++++---------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/internal/service/opsworks/ecs_cluster_layer_test.go b/internal/service/opsworks/ecs_cluster_layer_test.go index 2824bfb18a5..de0fae3ffa4 100644 --- a/internal/service/opsworks/ecs_cluster_layer_test.go +++ b/internal/service/opsworks/ecs_cluster_layer_test.go @@ -28,7 +28,9 @@ func TestAccOpsWorksEcsClusterLayer_basic(t *testing.T) { Config: testAccEcsClusterLayerVPCCreateConfig(stackName), Check: resource.ComposeTestCheckFunc( testAccCheckLayerExists(resourceName, &opslayer), - resource.TestCheckResourceAttr(resourceName, "name", stackName)), + resource.TestCheckResourceAttr(resourceName, "name", stackName), + resource.TestCheckResourceAttrPair(resourceName, "ecs_cluster_arn", "aws_ecs_cluster.test", "arn"), + ), }, }, }) diff --git a/internal/service/opsworks/layers.go b/internal/service/opsworks/layers.go index 7dfaaf809e8..d173eae91b3 100644 --- a/internal/service/opsworks/layers.go +++ b/internal/service/opsworks/layers.go @@ -506,13 +506,13 @@ func (lt *opsworksLayerType) Create(d *schema.ResourceData, meta interface{}) er StackId: req.StackId, }) if err != nil { - return err + return fmt.Errorf("error Registering Opsworks Layer ECS Cluster (%s): %w", d.Get("name").(string), err) } } resp, err := conn.CreateLayer(req) if err != nil { - return err + return fmt.Errorf("error Creating Opsworks Layer (%s): %w", d.Get("name").(string), err) } layerId := *resp.LayerId @@ -526,7 +526,7 @@ func (lt *opsworksLayerType) Create(d *schema.ResourceData, meta interface{}) er LayerId: &layerId, }) if err != nil { - return err + return fmt.Errorf("error Attaching Opsworks Layer (%s) load balancer: %w", d.Id(), err) } } @@ -540,7 +540,7 @@ func (lt *opsworksLayerType) Create(d *schema.ResourceData, meta interface{}) er if len(tags) > 0 { if err := UpdateTags(conn, arn, nil, tags); err != nil { - return fmt.Errorf("error updating Opsworks stack (%s) tags: %w", arn, err) + return fmt.Errorf("error updating Opsworks Layer (%s) tags: %w", arn, err) } } @@ -589,7 +589,7 @@ func (lt *opsworksLayerType) Update(d *schema.ResourceData, meta interface{}) er _, err = conn.UpdateLayer(req) if err != nil { - return err + return fmt.Errorf("error updating Opsworks Layer (%s): %w", d.Id(), err) } } @@ -600,24 +600,24 @@ func (lt *opsworksLayerType) Update(d *schema.ResourceData, meta interface{}) er ecsClusterNew := aws.String(ecsn.(string)) if ecsClusterOld != nil && *ecsClusterOld != "" { - log.Printf("[DEBUG] Dettaching ecs cluster: %s", *ecsClusterOld) + log.Printf("[DEBUG] Deregistering ecs cluster: %s", *ecsClusterOld) _, err := conn.DeregisterEcsCluster(&opsworks.DeregisterEcsClusterInput{ EcsClusterArn: ecsClusterOld, }) if err != nil { - return err + return fmt.Errorf("error Deregistering Opsworks Layer ECS Cluster (%s): %w", d.Id(), err) } } if ecsClusterNew != nil && *ecsClusterNew != "" { - log.Printf("[DEBUG] Attaching ECS Cluster: %s", *ecsClusterNew) + log.Printf("[DEBUG] Registering ECS Cluster: %s", *ecsClusterNew) _, err := conn.RegisterEcsCluster(&opsworks.RegisterEcsClusterInput{ EcsClusterArn: ecsClusterNew, StackId: stackID, }) if err != nil { - return err + return fmt.Errorf("error Registering Opsworks Layer ECS Cluster (%s): %w", d.Id(), err) } } } @@ -635,7 +635,7 @@ func (lt *opsworksLayerType) Update(d *schema.ResourceData, meta interface{}) er LayerId: aws.String(d.Id()), }) if err != nil { - return err + return fmt.Errorf("error Dettaching Opsworks Layer (%s) load balancer: %w", d.Id(), err) } } @@ -646,7 +646,7 @@ func (lt *opsworksLayerType) Update(d *schema.ResourceData, meta interface{}) er LayerId: aws.String(d.Id()), }) if err != nil { - return err + return fmt.Errorf("error Attaching Opsworks Layer (%s) load balancer: %w", d.Id(), err) } } } @@ -674,7 +674,7 @@ func (lt *opsworksLayerType) Delete(d *schema.ResourceData, meta interface{}) er _, err := conn.DeleteLayer(req) if err != nil { - return err + return fmt.Errorf("error Deleting Opsworks Layer (%s): %w", d.Id(), err) } if v, ok := d.GetOk("ecs_cluster_arn"); ok { @@ -684,7 +684,7 @@ func (lt *opsworksLayerType) Delete(d *schema.ResourceData, meta interface{}) er EcsClusterArn: aws.String(ecsClusterArn), }) if err != nil { - return err + return fmt.Errorf("error Deregistering Opsworks Layer ECS Cluster (%s): %w", d.Id(), err) } } @@ -850,27 +850,27 @@ func (lt *opsworksLayerType) SetVolumeConfigurations(d *schema.ResourceData, v [ newValue[i] = &data if config.Iops != nil { - data["iops"] = int(*config.Iops) + data["iops"] = aws.Int64Value(config.Iops) } else { data["iops"] = 0 } if config.MountPoint != nil { - data["mount_point"] = *config.MountPoint + data["mount_point"] = aws.StringValue(config.MountPoint) } if config.NumberOfDisks != nil { - data["number_of_disks"] = int(*config.NumberOfDisks) + data["number_of_disks"] = aws.Int64Value(config.NumberOfDisks) } if config.RaidLevel != nil { data["raid_level"] = strconv.Itoa(int(*config.RaidLevel)) } if config.Size != nil { - data["size"] = int(*config.Size) + data["size"] = aws.Int64Value(config.Size) } if config.VolumeType != nil { - data["type"] = *config.VolumeType + data["type"] = aws.StringValue(config.VolumeType) } if config.Encrypted != nil { - data["encrypted"] = *config.Encrypted + data["encrypted"] = aws.BoolValue(config.Encrypted) } } From e5d8e8a4586643e6b832e237a6184b5337f79c3d Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 21 Feb 2022 21:36:38 +0200 Subject: [PATCH 3/6] fmt --- internal/service/opsworks/ecs_cluster_layer_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/opsworks/ecs_cluster_layer_test.go b/internal/service/opsworks/ecs_cluster_layer_test.go index de0fae3ffa4..c6763d122b3 100644 --- a/internal/service/opsworks/ecs_cluster_layer_test.go +++ b/internal/service/opsworks/ecs_cluster_layer_test.go @@ -107,7 +107,7 @@ func testAccEcsClusterLayerTags1Config(name, tagKey1, tagValue1 string) string { resource "aws_ecs_cluster" "test" { name = %[1]q } - + resource "aws_opsworks_ecs_cluster_layer" "test" { stack_id = aws_opsworks_stack.tf-acc.id name = %[1]q From 490d8914eeaaa56227e406375b206cce9dacf449 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 21 Feb 2022 21:36:43 +0200 Subject: [PATCH 4/6] fmt --- internal/service/opsworks/layers.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/service/opsworks/layers.go b/internal/service/opsworks/layers.go index d173eae91b3..51c45ae7690 100644 --- a/internal/service/opsworks/layers.go +++ b/internal/service/opsworks/layers.go @@ -596,13 +596,13 @@ func (lt *opsworksLayerType) Update(d *schema.ResourceData, meta interface{}) er if d.HasChange("ecs_cluster_arn") { stackID := aws.String(d.Get("stack_id").(string)) ecso, ecsn := d.GetChange("ecs_cluster_arn") - ecsClusterOld := aws.String(ecso.(string)) - ecsClusterNew := aws.String(ecsn.(string)) + ecsClusterOld := ecso.(string) + ecsClusterNew := ecsn.(string) - if ecsClusterOld != nil && *ecsClusterOld != "" { - log.Printf("[DEBUG] Deregistering ecs cluster: %s", *ecsClusterOld) + if ecso != nil && ecsClusterOld != "" { + log.Printf("[DEBUG] Deregistering ecs cluster: %s", ecsClusterOld) _, err := conn.DeregisterEcsCluster(&opsworks.DeregisterEcsClusterInput{ - EcsClusterArn: ecsClusterOld, + EcsClusterArn: aws.String(ecsClusterOld), }) if err != nil { @@ -610,10 +610,10 @@ func (lt *opsworksLayerType) Update(d *schema.ResourceData, meta interface{}) er } } - if ecsClusterNew != nil && *ecsClusterNew != "" { - log.Printf("[DEBUG] Registering ECS Cluster: %s", *ecsClusterNew) + if ecsn != nil && ecsClusterNew != "" { + log.Printf("[DEBUG] Registering ECS Cluster: %s", ecsClusterNew) _, err := conn.RegisterEcsCluster(&opsworks.RegisterEcsClusterInput{ - EcsClusterArn: ecsClusterNew, + EcsClusterArn: aws.String(ecsClusterNew), StackId: stackID, }) if err != nil { From 0463123993c275900e872f931b328991b47d2865 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 21 Feb 2022 21:54:48 +0200 Subject: [PATCH 5/6] forcenew --- .../service/opsworks/ecs_cluster_layer.go | 1 + .../opsworks/ecs_cluster_layer_test.go | 4 +-- internal/service/opsworks/layers.go | 33 ++----------------- 3 files changed, 6 insertions(+), 32 deletions(-) diff --git a/internal/service/opsworks/ecs_cluster_layer.go b/internal/service/opsworks/ecs_cluster_layer.go index ec7c512068f..da3b0a7692c 100644 --- a/internal/service/opsworks/ecs_cluster_layer.go +++ b/internal/service/opsworks/ecs_cluster_layer.go @@ -16,6 +16,7 @@ func ResourceEcsClusterLayer() *schema.Resource { AttrName: opsworks.LayerAttributesKeysEcsClusterArn, Type: schema.TypeString, Required: true, + ForceNew: true, ValidateFunc: verify.ValidARN, }, }, diff --git a/internal/service/opsworks/ecs_cluster_layer_test.go b/internal/service/opsworks/ecs_cluster_layer_test.go index c6763d122b3..bdac7172c11 100644 --- a/internal/service/opsworks/ecs_cluster_layer_test.go +++ b/internal/service/opsworks/ecs_cluster_layer_test.go @@ -25,7 +25,7 @@ func TestAccOpsWorksEcsClusterLayer_basic(t *testing.T) { CheckDestroy: testAccCheckEcsClusterLayerDestroy, Steps: []resource.TestStep{ { - Config: testAccEcsClusterLayerVPCCreateConfig(stackName), + Config: testAccEcsClusterLayerBasic(stackName), Check: resource.ComposeTestCheckFunc( testAccCheckLayerExists(resourceName, &opslayer), resource.TestCheckResourceAttr(resourceName, "name", stackName), @@ -79,7 +79,7 @@ func testAccCheckEcsClusterLayerDestroy(s *terraform.State) error { return testAccCheckLayerDestroy("aws_opsworks_ecs_cluster_layer", s) } -func testAccEcsClusterLayerVPCCreateConfig(name string) string { +func testAccEcsClusterLayerBasic(name string) string { return testAccStackVPCCreateConfig(name) + testAccCustomLayerSecurityGroups(name) + fmt.Sprintf(` diff --git a/internal/service/opsworks/layers.go b/internal/service/opsworks/layers.go index 51c45ae7690..efc81202784 100644 --- a/internal/service/opsworks/layers.go +++ b/internal/service/opsworks/layers.go @@ -33,9 +33,10 @@ type opsworksLayerTypeAttribute struct { AttrName string Type schema.ValueType Default interface{} + ForceNew bool Required bool - WriteOnly bool ValidateFunc schema.SchemaValidateFunc + WriteOnly bool } type opsworksLayerType struct { @@ -325,6 +326,7 @@ func (lt *opsworksLayerType) SchemaResource() *schema.Resource { resourceSchema[key] = &schema.Schema{ Type: def.Type, Default: def.Default, + ForceNew: def.ForceNew, Required: def.Required, Optional: !def.Required, ValidateFunc: def.ValidateFunc, @@ -593,35 +595,6 @@ func (lt *opsworksLayerType) Update(d *schema.ResourceData, meta interface{}) er } } - if d.HasChange("ecs_cluster_arn") { - stackID := aws.String(d.Get("stack_id").(string)) - ecso, ecsn := d.GetChange("ecs_cluster_arn") - ecsClusterOld := ecso.(string) - ecsClusterNew := ecsn.(string) - - if ecso != nil && ecsClusterOld != "" { - log.Printf("[DEBUG] Deregistering ecs cluster: %s", ecsClusterOld) - _, err := conn.DeregisterEcsCluster(&opsworks.DeregisterEcsClusterInput{ - EcsClusterArn: aws.String(ecsClusterOld), - }) - - if err != nil { - return fmt.Errorf("error Deregistering Opsworks Layer ECS Cluster (%s): %w", d.Id(), err) - } - } - - if ecsn != nil && ecsClusterNew != "" { - log.Printf("[DEBUG] Registering ECS Cluster: %s", ecsClusterNew) - _, err := conn.RegisterEcsCluster(&opsworks.RegisterEcsClusterInput{ - EcsClusterArn: aws.String(ecsClusterNew), - StackId: stackID, - }) - if err != nil { - return fmt.Errorf("error Registering Opsworks Layer ECS Cluster (%s): %w", d.Id(), err) - } - } - } - if d.HasChange("elastic_load_balancer") { lbo, lbn := d.GetChange("elastic_load_balancer") From 66f683aa0716fa869b4dc429f9ba9b708b86eebd Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 21 Feb 2022 21:57:38 +0200 Subject: [PATCH 6/6] fmt --- internal/service/opsworks/ecs_cluster_layer_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/opsworks/ecs_cluster_layer_test.go b/internal/service/opsworks/ecs_cluster_layer_test.go index bdac7172c11..76255e85c69 100644 --- a/internal/service/opsworks/ecs_cluster_layer_test.go +++ b/internal/service/opsworks/ecs_cluster_layer_test.go @@ -107,7 +107,7 @@ func testAccEcsClusterLayerTags1Config(name, tagKey1, tagValue1 string) string { resource "aws_ecs_cluster" "test" { name = %[1]q } - + resource "aws_opsworks_ecs_cluster_layer" "test" { stack_id = aws_opsworks_stack.tf-acc.id name = %[1]q