From 96b423290f082cb2b734affa4605ce67b93e1fe0 Mon Sep 17 00:00:00 2001 From: Dogers Date: Fri, 21 Feb 2020 23:50:44 +0000 Subject: [PATCH 01/22] Add aws_imagebuilder_component --- aws/data_source_aws_imagebuilder_component.go | 107 ++++++++++ aws/provider.go | 2 + aws/resource_aws_imagebuilder_component.go | 198 ++++++++++++++++++ 3 files changed, 307 insertions(+) create mode 100644 aws/data_source_aws_imagebuilder_component.go create mode 100644 aws/resource_aws_imagebuilder_component.go diff --git a/aws/data_source_aws_imagebuilder_component.go b/aws/data_source_aws_imagebuilder_component.go new file mode 100644 index 00000000000..52416307ec2 --- /dev/null +++ b/aws/data_source_aws_imagebuilder_component.go @@ -0,0 +1,107 @@ +package aws + +import ( + "fmt" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/imagebuilder" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" +) + +func dataSourceAwsImageBuilderComponent() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsImageBuilderComponentRead, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Required: true, + }, + "change_description": { + Type: schema.TypeString, + Computed: true, + }, + "data": { + Type: schema.TypeString, + Computed: true, + }, + "date_created": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "encrypted": { + Type: schema.TypeBool, + Computed: true, + Optional: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "owner": { + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "platform": { + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "tags": tagsSchemaComputed(), + "type": { + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "semantic_version": { + Type: schema.TypeInt, + Computed: true, + Optional: true, + }, + }, + } +} + +func dataSourceAwsImageBuilderComponentRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).imagebuilderconn + + componentArn := d.Get("arn").(string) + + params := &imagebuilder.GetComponentInput{ + ComponentBuildVersionArn: aws.String(componentArn), + } + + resp, err := conn.GetComponent(params) + + if err != nil { + return fmt.Errorf("Error retrieving Component: %s", err) + } + + return componentDescriptionAttributes(d, resp.Component) +} + +func componentDescriptionAttributes(d *schema.ResourceData, component *imagebuilder.Component) error { + d.SetId(*component.Arn) + d.Set("change_description", component.ChangeDescription) + d.Set("data", component.Data) + d.Set("date_created", component.DateCreated) + d.Set("description", component.Description) + d.Set("encrypted", component.Encrypted) + d.Set("kms_key_id", component.KmsKeyId) + d.Set("name", component.Name) + d.Set("owner", component.Owner) + d.Set("platform", component.Platform) + if err := d.Set("tags", keyvaluetags.ImagebuilderKeyValueTags(component.Tags).IgnoreAws().Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + d.Set("type", component.Type) + d.Set("semantic_version", component.Version) + + return nil +} diff --git a/aws/provider.go b/aws/provider.go index f362186ac57..698e1b78a8f 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -254,6 +254,7 @@ func Provider() terraform.ResourceProvider { "aws_iam_role": dataSourceAwsIAMRole(), "aws_iam_server_certificate": dataSourceAwsIAMServerCertificate(), "aws_iam_user": dataSourceAwsIAMUser(), + "aws_imagebuilder_component": dataSourceAwsImageBuilderComponent(), "aws_internet_gateway": dataSourceAwsInternetGateway(), "aws_iot_endpoint": dataSourceAwsIotEndpoint(), "aws_inspector_rules_packages": dataSourceAwsInspectorRulesPackages(), @@ -627,6 +628,7 @@ func Provider() terraform.ResourceProvider { "aws_iam_user_ssh_key": resourceAwsIamUserSshKey(), "aws_iam_user": resourceAwsIamUser(), "aws_iam_user_login_profile": resourceAwsIamUserLoginProfile(), + "aws_imagebuilder_component": resourceAwsImageBuilderComponent(), "aws_inspector_assessment_target": resourceAWSInspectorAssessmentTarget(), "aws_inspector_assessment_template": resourceAWSInspectorAssessmentTemplate(), "aws_inspector_resource_group": resourceAWSInspectorResourceGroup(), diff --git a/aws/resource_aws_imagebuilder_component.go b/aws/resource_aws_imagebuilder_component.go new file mode 100644 index 00000000000..7dd136b612e --- /dev/null +++ b/aws/resource_aws_imagebuilder_component.go @@ -0,0 +1,198 @@ +package aws + +import ( + "errors" + "fmt" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/backup" + "github.com/aws/aws-sdk-go/service/imagebuilder" + "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/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" + "log" +) + +func resourceAwsImageBuilderComponent() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsImageBuilderComponentCreate, + Read: resourceAwsImageBuilderComponentRead, + Update: resourceAwsImageBuilderComponentUpdate, + Delete: resourceAwsImageBuilderComponentDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "change_description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 128), + }, + "data": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 16000), + ConflictsWith: []string{"uri"}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + "kms_key_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 126), + }, + "platform": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{"Windows", "Linux"}, false), + }, + "semantic_version": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 128), + }, + "tags": tagsSchema(), + "uri": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"data"}, + }, + }, + } +} + +func resourceAwsImageBuilderComponentCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).imagebuilderconn + + input := &imagebuilder.CreateComponentInput{ + ClientToken: aws.String(resource.UniqueId()), + Name: aws.String(d.Get("name").(string)), + Platform: aws.String(d.Get("platform").(string)), + SemanticVersion: aws.String(d.Get("semantic_version").(string)), + } + + if v, ok := d.GetOk("change_description"); ok { + input.SetChangeDescription(v.(string)) + } + data, dataok := d.GetOk("data") + if dataok { + input.SetData(data.(string)) + } + if v, ok := d.GetOk("description"); ok { + input.SetDescription(v.(string)) + } + if v, ok := d.GetOk("kms_key_id"); ok { + input.SetKmsKeyId(v.(string)) + } + uri, uriok := d.GetOk("uri") + if uriok { + input.SetUri(uri.(string)) + } + if !uriok && !dataok { + return errors.New("one of data or uri must be set") + } + if v, ok := d.GetOk("tags"); ok { + input.SetTags(keyvaluetags.New(v.(map[string]interface{})).IgnoreAws().ImagebuilderTags()) + } + + log.Printf("[DEBUG] Creating Component: %#v", input) + + resp, err := conn.CreateComponent(input) + if err != nil { + return fmt.Errorf("error creating Component: %s", err) + } + + d.SetId(aws.StringValue(resp.ComponentBuildVersionArn)) + + return resourceAwsImageBuilderComponentRead(d, meta) +} + +func resourceAwsImageBuilderComponentRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).imagebuilderconn + + resp, err := conn.GetComponent(&imagebuilder.GetComponentInput{ + ComponentBuildVersionArn: aws.String(d.Id()), + }) + + if isAWSErr(err, backup.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] Component (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error reading Component (%s): %s", d.Id(), err) + } + + d.Set("arn", resp.Component.Arn) + d.Set("name", resp.Component.Name) + d.Set("semantic_version", resp.Component.Version) + d.Set("change_description", resp.Component.ChangeDescription) + d.Set("data", resp.Component.Data) + d.Set("description", resp.Component.Description) + d.Set("kms_key_id", resp.Component.KmsKeyId) + d.Set("platform", resp.Component.Platform) + + tags, err := keyvaluetags.ImagebuilderListTags(conn, d.Get("arn").(string)) + if err != nil { + return fmt.Errorf("error listing tags for Component (%s): %s", d.Id(), err) + } + if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + + return nil +} + +func resourceAwsImageBuilderComponentUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).imagebuilderconn + + // tags are the only thing we can actually change, everything else is ForceNew + if d.HasChange("tags") { + o, n := d.GetChange("tags") + if err := keyvaluetags.ImagebuilderUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating tags for Component (%s): %s", d.Id(), err) + } + } + + return resourceAwsImageBuilderComponentRead(d, meta) +} + +func resourceAwsImageBuilderComponentDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).imagebuilderconn + + _, err := conn.DeleteComponent(&imagebuilder.DeleteComponentInput{ + ComponentBuildVersionArn: aws.String(d.Id()), + }) + + if isAWSErr(err, imagebuilder.ErrCodeResourceNotFoundException, "") { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting Component (%s): %s", d.Id(), err) + } + + return nil +} From 2d588c2608e7eaed0e05a46478fbd4cfbf594239 Mon Sep 17 00:00:00 2001 From: Dogers Date: Sat, 22 Feb 2020 15:33:39 +0000 Subject: [PATCH 02/22] Add test for data_source_aws_imagebuilder_component --- ..._source_aws_imagebuilder_component_test.go | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 aws/data_source_aws_imagebuilder_component_test.go diff --git a/aws/data_source_aws_imagebuilder_component_test.go b/aws/data_source_aws_imagebuilder_component_test.go new file mode 100644 index 00000000000..4c01aac6ed4 --- /dev/null +++ b/aws/data_source_aws_imagebuilder_component_test.go @@ -0,0 +1,58 @@ +package aws + +import ( + "fmt" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "testing" +) + +func TestAccDataSourceAwsImageBuilderComponent_basic(t *testing.T) { + rName := fmt.Sprintf("tf-ib-comp-test-%s", acctest.RandString(8)) + resourceName := "aws_builder_component.test" + dataSourceName := "data.aws_builder_component.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsImageBuilderComponentConfig(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "semantic_version", resourceName, "semantic_version"), + ), + }, + }, + }) +} + +func testAccDataSourceAwsImageBuilderComponentConfig(name string) string { + return fmt.Sprintf(` +resource "aws_imagebuilder_component" "test" { + name = "%s" + platform = "Linux" + semantic_version = "1.0.1" + + data = < Date: Sat, 22 Feb 2020 22:09:54 +0000 Subject: [PATCH 03/22] Add aws_imagebuilder_infrastructureconfiguration --- ...agebuilder_infrastructure_configuration.go | 136 +++++++ aws/provider.go | 2 + ...agebuilder_infrastructure_configuration.go | 335 ++++++++++++++++++ 3 files changed, 473 insertions(+) create mode 100644 aws/data_source_aws_imagebuilder_infrastructure_configuration.go create mode 100644 aws/resource_aws_imagebuilder_infrastructure_configuration.go diff --git a/aws/data_source_aws_imagebuilder_infrastructure_configuration.go b/aws/data_source_aws_imagebuilder_infrastructure_configuration.go new file mode 100644 index 00000000000..f5ef897e7af --- /dev/null +++ b/aws/data_source_aws_imagebuilder_infrastructure_configuration.go @@ -0,0 +1,136 @@ +package aws + +import ( + "fmt" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/imagebuilder" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" +) + +func dataSourceAwsImageBuilderInfrastructureConfiguration() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsImageBuilderInfrastructureConfigurationRead, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Required: true, + }, + "datecreated": { + Type: schema.TypeString, + Computed: true, + }, + "dateupdated": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "instance_profile_name": { + Type: schema.TypeString, + Computed: true, + }, + "instance_types": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + "key_pair": { + Type: schema.TypeString, + Computed: true, + }, + "logging": { + Type: schema.TypeList, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "s3_logs": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "s3_bucket_name": { + Type: schema.TypeString, + Computed: true, + }, + "s3_key_prefix": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "security_group_ids": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + "sns_topic_arn": { + Type: schema.TypeString, + Computed: true, + }, + "subnet_id": { + Type: schema.TypeString, + Computed: true, + }, + "terminate_instance_on_failure": { + Type: schema.TypeBool, + Computed: true, + }, + "tags": tagsSchema(), + }, + } +} + +func dataSourceAwsImageBuilderInfrastructureConfigurationRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).imagebuilderconn + + componentArn := d.Get("arn").(string) + + params := &imagebuilder.GetInfrastructureConfigurationInput{ + InfrastructureConfigurationArn: aws.String(componentArn), + } + + resp, err := conn.GetInfrastructureConfiguration(params) + + if err != nil { + return fmt.Errorf("Error retrieving Component: %s", err) + } + + return infraconfigDescriptionAttributes(d, resp.InfrastructureConfiguration) +} + +func infraconfigDescriptionAttributes(d *schema.ResourceData, component *imagebuilder.InfrastructureConfiguration) error { + d.SetId(*component.Arn) + d.Set("datecreated", component.DateCreated) + d.Set("dateupdated", component.DateUpdated) + d.Set("date_created", component.DateCreated) + d.Set("description", component.Description) + d.Set("instance_profile_name", component.InstanceProfileName) + d.Set("instance_types", component.InstanceTypes) + d.Set("key_pair", component.KeyPair) + d.Set("logging", component.Logging) + d.Set("name", component.Name) + d.Set("security_group_ids", component.SecurityGroupIds) + d.Set("sns_topic_arn", component.SnsTopicArn) + d.Set("subnet_id", component.SubnetId) + d.Set("terminate_instance_on_failure", component.TerminateInstanceOnFailure) + if err := d.Set("tags", keyvaluetags.ImagebuilderKeyValueTags(component.Tags).IgnoreAws().Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + + return nil +} diff --git a/aws/provider.go b/aws/provider.go index 698e1b78a8f..13c9a568c3c 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -255,6 +255,7 @@ func Provider() terraform.ResourceProvider { "aws_iam_server_certificate": dataSourceAwsIAMServerCertificate(), "aws_iam_user": dataSourceAwsIAMUser(), "aws_imagebuilder_component": dataSourceAwsImageBuilderComponent(), + "aws_imagebuilder_infrastructureconfiguration": dataSourceAwsImageBuilderInfrastructureConfiguration(), "aws_internet_gateway": dataSourceAwsInternetGateway(), "aws_iot_endpoint": dataSourceAwsIotEndpoint(), "aws_inspector_rules_packages": dataSourceAwsInspectorRulesPackages(), @@ -629,6 +630,7 @@ func Provider() terraform.ResourceProvider { "aws_iam_user": resourceAwsIamUser(), "aws_iam_user_login_profile": resourceAwsIamUserLoginProfile(), "aws_imagebuilder_component": resourceAwsImageBuilderComponent(), + "aws_imagebuilder_infrastructureconfiguration": resourceAwsImageBuilderInfrastructureConfiguration(), "aws_inspector_assessment_target": resourceAWSInspectorAssessmentTarget(), "aws_inspector_assessment_template": resourceAWSInspectorAssessmentTemplate(), "aws_inspector_resource_group": resourceAWSInspectorResourceGroup(), diff --git a/aws/resource_aws_imagebuilder_infrastructure_configuration.go b/aws/resource_aws_imagebuilder_infrastructure_configuration.go new file mode 100644 index 00000000000..53557a329ca --- /dev/null +++ b/aws/resource_aws_imagebuilder_infrastructure_configuration.go @@ -0,0 +1,335 @@ +package aws + +import ( + "fmt" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/backup" + "github.com/aws/aws-sdk-go/service/imagebuilder" + "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/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" + "log" +) + +func resourceAwsImageBuilderInfrastructureConfiguration() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsImageBuilderInfrastructureConfigurationCreate, + Read: resourceAwsImageBuilderInfrastructureConfigurationRead, + Update: resourceAwsImageBuilderInfrastructureConfigurationUpdate, + Delete: resourceAwsImageBuilderInfrastructureConfigurationDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "datecreated": { + Type: schema.TypeString, + Computed: true, + }, + "dateupdated": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + "instance_profile_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + "instance_types": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + "key_pair": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + "logging": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "s3_logs": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "s3_bucket_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + "s3_key_prefix": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + Default: "/", + }, + }, + }, + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "security_group_ids": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + "sns_topic_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + "subnet_id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + "terminate_instance_on_failure": { + Type: schema.TypeBool, + Optional: true, + }, + "tags": tagsSchema(), + }, + } +} + +func resourceAwsImageBuilderInfrastructureConfigurationCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).imagebuilderconn + + securityIdSet := d.Get("security_group_ids").(*schema.Set) + securityIds := expandStringList(securityIdSet.List()) + instanceIdSet := d.Get("instance_types").(*schema.Set) + instanceIds := expandStringList(instanceIdSet.List()) + + input := &imagebuilder.CreateInfrastructureConfigurationInput{ + ClientToken: aws.String(resource.UniqueId()), + Name: aws.String(d.Get("name").(string)), + InstanceProfileName: aws.String(d.Get("instance_profile_name").(string)), + SecurityGroupIds: securityIds, + InstanceTypes: instanceIds, + } + + if v, ok := d.GetOk("description"); ok { + input.SetDescription(v.(string)) + } + if v, ok := d.GetOk("key_pair"); ok { + input.SetKeyPair(v.(string)) + } + if v, ok := d.GetOk("logging"); ok { + input.SetLogging(v.(*imagebuilder.Logging)) + } + if v, ok := d.GetOk("sns_topic_arn"); ok { + input.SetSnsTopicArn(v.(string)) + } + if v, ok := d.GetOk("subnet_id"); ok { + input.SetSubnetId(v.(string)) + } + if v, ok := d.GetOk("tags"); ok { + input.SetTags(keyvaluetags.New(v.(map[string]interface{})).IgnoreAws().ImagebuilderTags()) + } + + log.Printf("[DEBUG] Creating Infrastructure Configuration: %#v", input) + + resp, err := conn.CreateInfrastructureConfiguration(input) + if err != nil { + return fmt.Errorf("error creating Component: %s", err) + } + + d.SetId(aws.StringValue(resp.InfrastructureConfigurationArn)) + + return resourceAwsImageBuilderInfrastructureConfigurationRead(d, meta) +} + +func resourceAwsImageBuilderInfrastructureConfigurationRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).imagebuilderconn + + resp, err := conn.GetInfrastructureConfiguration(&imagebuilder.GetInfrastructureConfigurationInput{ + InfrastructureConfigurationArn: aws.String(d.Id()), + }) + + if isAWSErr(err, backup.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] Infrastructure Configuration (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error reading Infrastructure Configuration (%s): %s", d.Id(), err) + } + + d.Set("arn", resp.InfrastructureConfiguration.Arn) + d.Set("datecreated", resp.InfrastructureConfiguration.DateCreated) + d.Set("dateupdated", resp.InfrastructureConfiguration.DateUpdated) + d.Set("description", resp.InfrastructureConfiguration.Description) + d.Set("instance_profile_name", resp.InfrastructureConfiguration.InstanceProfileName) + d.Set("instance_types", resp.InfrastructureConfiguration.InstanceTypes) + d.Set("key_pair", resp.InfrastructureConfiguration.KeyPair) + d.Set("logging", flattenAwsImageBuilderLogsConfig(resp.InfrastructureConfiguration.Logging)) + d.Set("name", resp.InfrastructureConfiguration.Name) + d.Set("security_group_ids", resp.InfrastructureConfiguration.SecurityGroupIds) + d.Set("sns_topic_arn", resp.InfrastructureConfiguration.SnsTopicArn) + d.Set("subnet_id", resp.InfrastructureConfiguration.SubnetId) + d.Set("terminate_instance_on_failure", resp.InfrastructureConfiguration.TerminateInstanceOnFailure) + + tags, err := keyvaluetags.ImagebuilderListTags(conn, d.Get("arn").(string)) + if err != nil { + return fmt.Errorf("error listing tags for Infrastructure Configuration (%s): %s", d.Id(), err) + } + if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + + return nil +} + +func resourceAwsImageBuilderInfrastructureConfigurationUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).imagebuilderconn + + // Despite not being required by the API, if it's not sent then certain things get wiped to null + upd := imagebuilder.UpdateInfrastructureConfigurationInput{ + InfrastructureConfigurationArn: aws.String(d.Id()), + InstanceProfileName: aws.String(d.Get("instance_profile_name").(string)), + Description: aws.String(d.Get("description").(string)), + KeyPair: aws.String(d.Get("key_pair").(string)), + SubnetId: aws.String(d.Get("subnet_id").(string)), + Logging: expandAwsImageBuilderLogsConfig(d), + } + + if d.HasChange("instance_types") { + if attr := d.Get("instance_types").(*schema.Set); attr.Len() > 0 { + upd.InstanceTypes = expandStringList(attr.List()) + } + } + if d.HasChange("instance_profile_name") { + upd.InstanceProfileName = aws.String(d.Get("instance_profile_name").(string)) + } + if v, ok := d.GetOk("security_group_ids"); ok { + if attr := v.(*schema.Set); attr.Len() > 0 { + upd.SecurityGroupIds = expandStringList(attr.List()) + } + } + if d.HasChange("sns_topic_arn") { + upd.SnsTopicArn = aws.String(d.Get("sns_topic_arn").(string)) + } + if d.HasChange("terminate_instance_on_failure") { + upd.TerminateInstanceOnFailure = aws.Bool(d.Get("terminate_instance_on_failure").(bool)) + } + + if d.HasChange("security_group_ids") { + if attr := d.Get("security_group_ids").(*schema.Set); attr.Len() > 0 { + upd.SecurityGroupIds = expandStringList(attr.List()) + } + } + + if d.HasChange("tags") { + o, n := d.GetChange("tags") + if err := keyvaluetags.ImagebuilderUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating tags for Infrastructure Configuration (%s): %s", d.Id(), err) + } + } + + _, err := conn.UpdateInfrastructureConfiguration(&upd) + if err != nil { + return fmt.Errorf("error updating Infrastructure Configuration (%s): %s", d.Id(), err) + } + + return resourceAwsImageBuilderInfrastructureConfigurationRead(d, meta) +} + +func resourceAwsImageBuilderInfrastructureConfigurationDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).imagebuilderconn + + _, err := conn.DeleteInfrastructureConfiguration(&imagebuilder.DeleteInfrastructureConfigurationInput{ + InfrastructureConfigurationArn: aws.String(d.Id()), + }) + + if isAWSErr(err, imagebuilder.ErrCodeResourceNotFoundException, "") { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting Infrastructure Configuration (%s): %s", d.Id(), err) + } + + return nil +} + +func flattenAwsImageBuilderLogsConfig(logsConfig *imagebuilder.Logging) []interface{} { + if logsConfig == nil { + return []interface{}{} + } + + values := map[string]interface{}{} + + // If more logging options are added, add more ifs! + if v := logsConfig.S3Logs; v != nil { + values["s3_logs"] = flattenAwsImageBuilderS3Logs(v) + } + + return []interface{}{values} +} + +func flattenAwsImageBuilderS3Logs(s3LogsConfig *imagebuilder.S3Logs) []interface{} { + values := map[string]interface{}{} + + values["s3_key_prefix"] = aws.StringValue(s3LogsConfig.S3KeyPrefix) + values["s3_bucket_name"] = aws.StringValue(s3LogsConfig.S3BucketName) + + return []interface{}{values} +} + +func expandAwsImageBuilderLogsConfig(d *schema.ResourceData) *imagebuilder.Logging { + logsConfig := &imagebuilder.Logging{} + + if v, ok := d.GetOk("logging"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + configList := v.([]interface{}) + data := configList[0].(map[string]interface{}) + + if v, ok := data["s3_logs"]; ok { + logsConfig.S3Logs = expandAwsImageBuilderS3LogsConfig(v.([]interface{})) + } + } + + return logsConfig +} + +func expandAwsImageBuilderS3LogsConfig(configList []interface{}) *imagebuilder.S3Logs { + if len(configList) == 0 || configList[0] == nil { + return nil + } + + data := configList[0].(map[string]interface{}) + + s3LogsConfig := &imagebuilder.S3Logs{} + + if v, ok := data["s3_bucket_name"]; ok { + s3LogsConfig.S3BucketName = aws.String(v.(string)) + } + if v, ok := data["s3_key_prefix"]; ok { + s3LogsConfig.S3KeyPrefix = aws.String(v.(string)) + } + + return s3LogsConfig +} From 6414616226c2cbcf25f07eb72356cd4362271d38 Mon Sep 17 00:00:00 2001 From: Dogers Date: Tue, 3 Mar 2020 23:21:38 +0000 Subject: [PATCH 04/22] Add aws_imagebuilder_recipe --- ..._aws_imagebuilder_infrastructure_recipe.go | 183 +++++++++ aws/provider.go | 2 + aws/resource_aws_imagebuilder_recipe.go | 352 ++++++++++++++++++ 3 files changed, 537 insertions(+) create mode 100644 aws/data_source_aws_imagebuilder_infrastructure_recipe.go create mode 100644 aws/resource_aws_imagebuilder_recipe.go diff --git a/aws/data_source_aws_imagebuilder_infrastructure_recipe.go b/aws/data_source_aws_imagebuilder_infrastructure_recipe.go new file mode 100644 index 00000000000..7f01bdbde1b --- /dev/null +++ b/aws/data_source_aws_imagebuilder_infrastructure_recipe.go @@ -0,0 +1,183 @@ +package aws + +import ( + "fmt" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/imagebuilder" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" +) + +func dataSourceAwsImageBuilderRecipe() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsImageBuilderRecipeRead, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "block_device_mappings": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "device_name": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + "ebs": { + Type: schema.TypeList, + Required: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "delete_on_termination": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Default: true, + }, + "encrypted": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Default: false, + }, + "iops": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + ValidateFunc: validation.IntBetween(100, 10000), + }, + "kms_key_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validateArn, + }, + "snapshot_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "volume_size": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + ValidateFunc: validation.IntBetween(1, 16000), + }, + "volume_type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + imagebuilder.EbsVolumeTypeStandard, + imagebuilder.EbsVolumeTypeIo1, + imagebuilder.EbsVolumeTypeGp2, + imagebuilder.EbsVolumeTypeSc1, + imagebuilder.EbsVolumeTypeSt1, + }, true), + }, + }, + }, + }, + "no_device": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "virtual_name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + }, + }, + }, + "components": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "datecreated": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 126), + }, + "owner": { + Type: schema.TypeString, + Computed: true, + }, + "parent_image": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 126), + }, + "platform": { + Type: schema.TypeString, + Computed: true, + }, + "semantic_version": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 128), + }, + "tags": tagsSchema(), + }, + + } +} + +func dataSourceAwsImageBuilderRecipeRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).imagebuilderconn + + resp, err := conn.GetImageRecipe(&imagebuilder.GetImageRecipeInput{ + ImageRecipeArn: aws.String(d.Id()), + }) + + if err != nil { + return fmt.Errorf("error reading Recipe (%s): %s", d.Id(), err) + } + + return recipeDescriptionAttributes(d, resp.ImageRecipe) +} + +func recipeDescriptionAttributes(d *schema.ResourceData, imageRecipe *imagebuilder.ImageRecipe) error { + d.SetId(*imageRecipe.Arn) + d.Set("arn", imageRecipe.Arn) + d.Set("block_device_mappings", imageRecipe.BlockDeviceMappings) + d.Set("components", imageRecipe.Components) + d.Set("datecreated", imageRecipe.DateCreated) + d.Set("description", imageRecipe.Description) + d.Set("name", imageRecipe.Name) + d.Set("owner", imageRecipe.Owner) + d.Set("parent_image", imageRecipe.ParentImage) + d.Set("platform", imageRecipe.Platform) + d.Set("semantic_version", imageRecipe.Version) + + if err := d.Set("tags", keyvaluetags.ImagebuilderKeyValueTags(imageRecipe.Tags).IgnoreAws().Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + + return nil +} diff --git a/aws/provider.go b/aws/provider.go index 13c9a568c3c..e2d79985ac2 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -256,6 +256,7 @@ func Provider() terraform.ResourceProvider { "aws_iam_user": dataSourceAwsIAMUser(), "aws_imagebuilder_component": dataSourceAwsImageBuilderComponent(), "aws_imagebuilder_infrastructureconfiguration": dataSourceAwsImageBuilderInfrastructureConfiguration(), + "aws_imagebuilder_recipe": dataSourceAwsImageBuilderRecipe(), "aws_internet_gateway": dataSourceAwsInternetGateway(), "aws_iot_endpoint": dataSourceAwsIotEndpoint(), "aws_inspector_rules_packages": dataSourceAwsInspectorRulesPackages(), @@ -631,6 +632,7 @@ func Provider() terraform.ResourceProvider { "aws_iam_user_login_profile": resourceAwsIamUserLoginProfile(), "aws_imagebuilder_component": resourceAwsImageBuilderComponent(), "aws_imagebuilder_infrastructureconfiguration": resourceAwsImageBuilderInfrastructureConfiguration(), + "aws_imagebuilder_recipe": resourceAwsImageBuilderRecipe(), "aws_inspector_assessment_target": resourceAWSInspectorAssessmentTarget(), "aws_inspector_assessment_template": resourceAWSInspectorAssessmentTemplate(), "aws_inspector_resource_group": resourceAWSInspectorResourceGroup(), diff --git a/aws/resource_aws_imagebuilder_recipe.go b/aws/resource_aws_imagebuilder_recipe.go new file mode 100644 index 00000000000..68297edc9ab --- /dev/null +++ b/aws/resource_aws_imagebuilder_recipe.go @@ -0,0 +1,352 @@ +package aws + +import ( + "fmt" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/backup" + "github.com/aws/aws-sdk-go/service/imagebuilder" + "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/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" + "log" +) + +func resourceAwsImageBuilderRecipe() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsImageBuilderRecipeCreate, + Read: resourceAwsImageBuilderRecipeRead, + Update: resourceAwsImageBuilderRecipeUpdate, + Delete: resourceAwsImageBuilderRecipeDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "block_device_mappings": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "device_name": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + "ebs": { + Type: schema.TypeList, + Required: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "delete_on_termination": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Default: true, + }, + "encrypted": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Default: false, + }, + "iops": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + ValidateFunc: validation.IntBetween(100, 10000), + }, + "kms_key_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validateArn, + }, + "snapshot_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "volume_size": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + ValidateFunc: validation.IntBetween(1, 16000), + }, + "volume_type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + imagebuilder.EbsVolumeTypeStandard, + imagebuilder.EbsVolumeTypeIo1, + imagebuilder.EbsVolumeTypeGp2, + imagebuilder.EbsVolumeTypeSc1, + imagebuilder.EbsVolumeTypeSt1, + }, true), + }, + }, + }, + }, + "no_device": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "virtual_name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + }, + }, + }, + "components": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "datecreated": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 126), + }, + "owner": { + Type: schema.TypeString, + Computed: true, + }, + "parent_image": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 126), + }, + "platform": { + Type: schema.TypeString, + Computed: true, + }, + "semantic_version": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 128), + }, + "tags": tagsSchema(), + }, + } +} + +func resourceAwsImageBuilderRecipeCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).imagebuilderconn + + input := &imagebuilder.CreateImageRecipeInput{ + ClientToken: aws.String(resource.UniqueId()), + Components: expandImageBuilderComponentConfig(d.Get("components").([]interface{})), + Name: aws.String(d.Get("name").(string)), + ParentImage: aws.String(d.Get("parent_image").(string)), + SemanticVersion: aws.String(d.Get("semantic_version").(string)), + BlockDeviceMappings: expandImageBuilderBlockDevices(d), + } + + if v, ok := d.GetOk("description"); ok { + input.SetDescription(v.(string)) + } + if v, ok := d.GetOk("tags"); ok { + input.SetTags(keyvaluetags.New(v.(map[string]interface{})).IgnoreAws().ImagebuilderTags()) + } + + log.Printf("[DEBUG] Creating Recipe: %#v", input) + + resp, err := conn.CreateImageRecipe(input) + if err != nil { + return fmt.Errorf("error creating Recipe: %s", err) + } + + d.SetId(aws.StringValue(resp.ImageRecipeArn)) + + return resourceAwsImageBuilderRecipeRead(d, meta) +} + +func resourceAwsImageBuilderRecipeRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).imagebuilderconn + + resp, err := conn.GetImageRecipe(&imagebuilder.GetImageRecipeInput{ + ImageRecipeArn: aws.String(d.Id()), + }) + + if isAWSErr(err, backup.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] Recipe (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error reading Recipe (%s): %s", d.Id(), err) + } + + d.Set("arn", resp.ImageRecipe.Arn) + d.Set("block_device_mappings", resp.ImageRecipe.BlockDeviceMappings) + d.Set("components", resp.ImageRecipe.Components) + d.Set("description", resp.ImageRecipe.Description) + d.Set("name", resp.ImageRecipe.Name) + d.Set("owner", resp.ImageRecipe.Owner) + d.Set("parent_image", resp.ImageRecipe.ParentImage) + d.Set("platform", resp.ImageRecipe.Platform) + d.Set("semantic_version", resp.ImageRecipe.Version) + + tags, err := keyvaluetags.ImagebuilderListTags(conn, d.Get("arn").(string)) + if err != nil { + return fmt.Errorf("error listing tags for Recipe (%s): %s", d.Id(), err) + } + if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + + return nil +} + +func resourceAwsImageBuilderRecipeUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).imagebuilderconn + + // tags are the only thing we can update! + if d.HasChange("tags") { + o, n := d.GetChange("tags") + if err := keyvaluetags.ImagebuilderUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating tags for Recipe (%s): %s", d.Id(), err) + } + } + + return resourceAwsImageBuilderRecipeRead(d, meta) +} + +func resourceAwsImageBuilderRecipeDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).imagebuilderconn + + _, err := conn.DeleteImageRecipe(&imagebuilder.DeleteImageRecipeInput{ + ImageRecipeArn: aws.String(d.Id()), + }) + + if isAWSErr(err, imagebuilder.ErrCodeResourceNotFoundException, "") { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting Recipe (%s): %s", d.Id(), err) + } + + return nil +} + +func expandImageBuilderComponentConfig(comps []interface{}) []*imagebuilder.ComponentConfiguration { + var configs []*imagebuilder.ComponentConfiguration + + for _, line := range comps { + var arn imagebuilder.ComponentConfiguration + arn.ComponentArn = aws.String(line.(string)) + configs = append(configs, &arn) + } + + return configs +} + +func expandImageBuilderBlockDevices(d *schema.ResourceData) []*imagebuilder.InstanceBlockDeviceMapping { + var bdmres []*imagebuilder.InstanceBlockDeviceMapping + + v, ok := d.GetOk("block_device_mappings") + if !ok { + return bdmres + } + + bdmlist := v.([]interface{}) + + for _, bdm := range bdmlist { + if bdm == nil { + continue + } + blockDeviceMapping := readIBBlockDeviceMappingFromConfig(bdm.(map[string]interface{})) + bdmres = append(bdmres, blockDeviceMapping) + } + + return bdmres +} + +func readIBBlockDeviceMappingFromConfig(bdm map[string]interface{}) *imagebuilder.InstanceBlockDeviceMapping { + blockDeviceMapping := &imagebuilder.InstanceBlockDeviceMapping{} + + if v := bdm["device_name"].(string); v != "" { + blockDeviceMapping.DeviceName = aws.String(v) + } + + if v := bdm["no_device"].(string); v != "" { + blockDeviceMapping.NoDevice = aws.String(v) + } + + if v := bdm["virtual_name"].(string); v != "" { + blockDeviceMapping.VirtualName = aws.String(v) + } + + if v := bdm["ebs"]; len(v.([]interface{})) > 0 { + ebs := v.([]interface{}) + if len(ebs) > 0 && ebs[0] != nil { + ebsData := ebs[0].(map[string]interface{}) + imagebuilderEbsBlockDeviceRequest := readIBEbsBlockDeviceFromConfig(ebsData) + blockDeviceMapping.Ebs = imagebuilderEbsBlockDeviceRequest + } + } + + return blockDeviceMapping +} + +func readIBEbsBlockDeviceFromConfig(ebs map[string]interface{}) *imagebuilder.EbsInstanceBlockDeviceSpecification { + ebsDevice := &imagebuilder.EbsInstanceBlockDeviceSpecification{} + + if v, ok := ebs["delete_on_termination"]; ok { + ebsDevice.DeleteOnTermination = aws.Bool(v.(bool)) + } + + if v, ok := ebs["encrypted"]; ok { + ebsDevice.Encrypted = aws.Bool(v.(bool)) + } + + if v := ebs["iops"].(int); v > 0 { + ebsDevice.Iops = aws.Int64(int64(v)) + } + + if v := ebs["kms_key_id"].(string); v != "" { + ebsDevice.KmsKeyId = aws.String(v) + } + + if v := ebs["snapshot_id"].(string); v != "" { + ebsDevice.SnapshotId = aws.String(v) + } + + if v := ebs["volume_size"]; v != nil { + ebsDevice.VolumeSize = aws.Int64(int64(v.(int))) + } + + if v := ebs["volume_type"].(string); v != "" { + ebsDevice.VolumeType = aws.String(v) + } + + return ebsDevice +} From c29b5da3a2fce4b38c1b55be7dfe81ef69a957d6 Mon Sep 17 00:00:00 2001 From: Dogers Date: Wed, 6 May 2020 23:11:26 +0100 Subject: [PATCH 05/22] Rename to aws_imagebuilder_infrastructure_configuration --- aws/provider.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/provider.go b/aws/provider.go index e2d79985ac2..eb88bdbf17e 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -255,7 +255,7 @@ func Provider() terraform.ResourceProvider { "aws_iam_server_certificate": dataSourceAwsIAMServerCertificate(), "aws_iam_user": dataSourceAwsIAMUser(), "aws_imagebuilder_component": dataSourceAwsImageBuilderComponent(), - "aws_imagebuilder_infrastructureconfiguration": dataSourceAwsImageBuilderInfrastructureConfiguration(), + "aws_imagebuilder_infrastructure_configuration": dataSourceAwsImageBuilderInfrastructureConfiguration(), "aws_imagebuilder_recipe": dataSourceAwsImageBuilderRecipe(), "aws_internet_gateway": dataSourceAwsInternetGateway(), "aws_iot_endpoint": dataSourceAwsIotEndpoint(), @@ -631,7 +631,7 @@ func Provider() terraform.ResourceProvider { "aws_iam_user": resourceAwsIamUser(), "aws_iam_user_login_profile": resourceAwsIamUserLoginProfile(), "aws_imagebuilder_component": resourceAwsImageBuilderComponent(), - "aws_imagebuilder_infrastructureconfiguration": resourceAwsImageBuilderInfrastructureConfiguration(), + "aws_imagebuilder_infrastructure_configuration": resourceAwsImageBuilderInfrastructureConfiguration(), "aws_imagebuilder_recipe": resourceAwsImageBuilderRecipe(), "aws_inspector_assessment_target": resourceAWSInspectorAssessmentTarget(), "aws_inspector_assessment_template": resourceAWSInspectorAssessmentTemplate(), From 8b537672e00f198104d48061cfff69eda06d5f51 Mon Sep 17 00:00:00 2001 From: Dogers Date: Mon, 25 May 2020 19:58:57 +0100 Subject: [PATCH 06/22] Fix issue with infraconfig logging --- aws/resource_aws_imagebuilder_infrastructure_configuration.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/aws/resource_aws_imagebuilder_infrastructure_configuration.go b/aws/resource_aws_imagebuilder_infrastructure_configuration.go index 53557a329ca..f70edd34c55 100644 --- a/aws/resource_aws_imagebuilder_infrastructure_configuration.go +++ b/aws/resource_aws_imagebuilder_infrastructure_configuration.go @@ -129,6 +129,7 @@ func resourceAwsImageBuilderInfrastructureConfigurationCreate(d *schema.Resource InstanceProfileName: aws.String(d.Get("instance_profile_name").(string)), SecurityGroupIds: securityIds, InstanceTypes: instanceIds, + Logging: expandAwsImageBuilderLogsConfig(d), } if v, ok := d.GetOk("description"); ok { @@ -137,9 +138,6 @@ func resourceAwsImageBuilderInfrastructureConfigurationCreate(d *schema.Resource if v, ok := d.GetOk("key_pair"); ok { input.SetKeyPair(v.(string)) } - if v, ok := d.GetOk("logging"); ok { - input.SetLogging(v.(*imagebuilder.Logging)) - } if v, ok := d.GetOk("sns_topic_arn"); ok { input.SetSnsTopicArn(v.(string)) } From 8ce7b6bdfbb94d039abfe59549cb886ebfe8ef9b Mon Sep 17 00:00:00 2001 From: Dogers Date: Mon, 25 May 2020 21:11:37 +0100 Subject: [PATCH 07/22] Fix incorrect MaxItems on res --- aws/data_source_aws_imagebuilder_infrastructure_configuration.go | 1 - 1 file changed, 1 deletion(-) diff --git a/aws/data_source_aws_imagebuilder_infrastructure_configuration.go b/aws/data_source_aws_imagebuilder_infrastructure_configuration.go index f5ef897e7af..28ce8c05a13 100644 --- a/aws/data_source_aws_imagebuilder_infrastructure_configuration.go +++ b/aws/data_source_aws_imagebuilder_infrastructure_configuration.go @@ -46,7 +46,6 @@ func dataSourceAwsImageBuilderInfrastructureConfiguration() *schema.Resource { "logging": { Type: schema.TypeList, Computed: true, - MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "s3_logs": { From fbe7510eff55e27158df90048dc490d9b14cb786 Mon Sep 17 00:00:00 2001 From: Dogers Date: Mon, 25 May 2020 21:10:36 +0100 Subject: [PATCH 08/22] Fix S024 --- ...rce_aws_imagebuilder_infrastructure_recipe.go | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/aws/data_source_aws_imagebuilder_infrastructure_recipe.go b/aws/data_source_aws_imagebuilder_infrastructure_recipe.go index 7f01bdbde1b..1d487ff86a6 100644 --- a/aws/data_source_aws_imagebuilder_infrastructure_recipe.go +++ b/aws/data_source_aws_imagebuilder_infrastructure_recipe.go @@ -21,7 +21,6 @@ func dataSourceAwsImageBuilderRecipe() *schema.Resource { "block_device_mappings": { Type: schema.TypeList, Optional: true, - ForceNew: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "device_name": { @@ -32,48 +31,40 @@ func dataSourceAwsImageBuilderRecipe() *schema.Resource { "ebs": { Type: schema.TypeList, Required: true, - ForceNew: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "delete_on_termination": { Type: schema.TypeBool, Optional: true, - ForceNew: true, Default: true, }, "encrypted": { Type: schema.TypeBool, Optional: true, - ForceNew: true, Default: false, }, "iops": { Type: schema.TypeInt, Optional: true, - ForceNew: true, ValidateFunc: validation.IntBetween(100, 10000), }, "kms_key_id": { Type: schema.TypeString, Optional: true, - ForceNew: true, ValidateFunc: validateArn, }, "snapshot_id": { Type: schema.TypeString, Optional: true, - ForceNew: true, }, "volume_size": { Type: schema.TypeInt, Optional: true, - ForceNew: true, ValidateFunc: validation.IntBetween(1, 16000), }, "volume_type": { Type: schema.TypeString, Optional: true, - ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ imagebuilder.EbsVolumeTypeStandard, imagebuilder.EbsVolumeTypeIo1, @@ -88,12 +79,10 @@ func dataSourceAwsImageBuilderRecipe() *schema.Resource { "no_device": { Type: schema.TypeString, Optional: true, - ForceNew: true, }, "virtual_name": { Type: schema.TypeString, Optional: true, - ForceNew: true, ValidateFunc: validation.StringLenBetween(1, 1024), }, }, @@ -103,7 +92,6 @@ func dataSourceAwsImageBuilderRecipe() *schema.Resource { Type: schema.TypeList, Required: true, MinItems: 1, - ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, }, "datecreated": { @@ -113,13 +101,11 @@ func dataSourceAwsImageBuilderRecipe() *schema.Resource { "description": { Type: schema.TypeString, Optional: true, - ForceNew: true, ValidateFunc: validation.StringLenBetween(1, 1024), }, "name": { Type: schema.TypeString, Required: true, - ForceNew: true, ValidateFunc: validation.StringLenBetween(1, 126), }, "owner": { @@ -129,7 +115,6 @@ func dataSourceAwsImageBuilderRecipe() *schema.Resource { "parent_image": { Type: schema.TypeString, Required: true, - ForceNew: true, ValidateFunc: validation.StringLenBetween(1, 126), }, "platform": { @@ -139,7 +124,6 @@ func dataSourceAwsImageBuilderRecipe() *schema.Resource { "semantic_version": { Type: schema.TypeString, Required: true, - ForceNew: true, ValidateFunc: validation.StringLenBetween(1, 128), }, "tags": tagsSchema(), From 28dfb17a3ac72605a7cb731347899baaf3a9be73 Mon Sep 17 00:00:00 2001 From: Dogers Date: Mon, 25 May 2020 21:12:41 +0100 Subject: [PATCH 09/22] Fix AWSR002 --- aws/data_source_aws_imagebuilder_component.go | 31 ++++++++-------- ...agebuilder_infrastructure_configuration.go | 36 +++++++++---------- ..._aws_imagebuilder_infrastructure_recipe.go | 29 +++++++-------- aws/resource_aws_imagebuilder_component.go | 3 +- ...agebuilder_infrastructure_configuration.go | 3 +- aws/resource_aws_imagebuilder_recipe.go | 3 +- 6 files changed, 50 insertions(+), 55 deletions(-) diff --git a/aws/data_source_aws_imagebuilder_component.go b/aws/data_source_aws_imagebuilder_component.go index 52416307ec2..a265b8aa2d8 100644 --- a/aws/data_source_aws_imagebuilder_component.go +++ b/aws/data_source_aws_imagebuilder_component.go @@ -70,6 +70,7 @@ func dataSourceAwsImageBuilderComponent() *schema.Resource { func dataSourceAwsImageBuilderComponentRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).imagebuilderconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig componentArn := d.Get("arn").(string) @@ -83,25 +84,23 @@ func dataSourceAwsImageBuilderComponentRead(d *schema.ResourceData, meta interfa return fmt.Errorf("Error retrieving Component: %s", err) } - return componentDescriptionAttributes(d, resp.Component) -} + d.SetId(*resp.Component.Arn) -func componentDescriptionAttributes(d *schema.ResourceData, component *imagebuilder.Component) error { - d.SetId(*component.Arn) - d.Set("change_description", component.ChangeDescription) - d.Set("data", component.Data) - d.Set("date_created", component.DateCreated) - d.Set("description", component.Description) - d.Set("encrypted", component.Encrypted) - d.Set("kms_key_id", component.KmsKeyId) - d.Set("name", component.Name) - d.Set("owner", component.Owner) - d.Set("platform", component.Platform) - if err := d.Set("tags", keyvaluetags.ImagebuilderKeyValueTags(component.Tags).IgnoreAws().Map()); err != nil { + if err := d.Set("tags", keyvaluetags.ImagebuilderKeyValueTags(resp.Component.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } - d.Set("type", component.Type) - d.Set("semantic_version", component.Version) + + d.Set("change_description", resp.Component.ChangeDescription) + d.Set("data", resp.Component.Data) + d.Set("date_created", resp.Component.DateCreated) + d.Set("description", resp.Component.Description) + d.Set("encrypted", resp.Component.Encrypted) + d.Set("kms_key_id", resp.Component.KmsKeyId) + d.Set("name", resp.Component.Name) + d.Set("owner", resp.Component.Owner) + d.Set("platform", resp.Component.Platform) + d.Set("type", resp.Component.Type) + d.Set("semantic_version", resp.Component.Version) return nil } diff --git a/aws/data_source_aws_imagebuilder_infrastructure_configuration.go b/aws/data_source_aws_imagebuilder_infrastructure_configuration.go index 28ce8c05a13..96bf7edb050 100644 --- a/aws/data_source_aws_imagebuilder_infrastructure_configuration.go +++ b/aws/data_source_aws_imagebuilder_infrastructure_configuration.go @@ -96,6 +96,7 @@ func dataSourceAwsImageBuilderInfrastructureConfiguration() *schema.Resource { func dataSourceAwsImageBuilderInfrastructureConfigurationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).imagebuilderconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig componentArn := d.Get("arn").(string) @@ -109,27 +110,22 @@ func dataSourceAwsImageBuilderInfrastructureConfigurationRead(d *schema.Resource return fmt.Errorf("Error retrieving Component: %s", err) } - return infraconfigDescriptionAttributes(d, resp.InfrastructureConfiguration) -} - -func infraconfigDescriptionAttributes(d *schema.ResourceData, component *imagebuilder.InfrastructureConfiguration) error { - d.SetId(*component.Arn) - d.Set("datecreated", component.DateCreated) - d.Set("dateupdated", component.DateUpdated) - d.Set("date_created", component.DateCreated) - d.Set("description", component.Description) - d.Set("instance_profile_name", component.InstanceProfileName) - d.Set("instance_types", component.InstanceTypes) - d.Set("key_pair", component.KeyPair) - d.Set("logging", component.Logging) - d.Set("name", component.Name) - d.Set("security_group_ids", component.SecurityGroupIds) - d.Set("sns_topic_arn", component.SnsTopicArn) - d.Set("subnet_id", component.SubnetId) - d.Set("terminate_instance_on_failure", component.TerminateInstanceOnFailure) - if err := d.Set("tags", keyvaluetags.ImagebuilderKeyValueTags(component.Tags).IgnoreAws().Map()); err != nil { + d.SetId(*resp.InfrastructureConfiguration.Arn) + d.Set("datecreated", resp.InfrastructureConfiguration.DateCreated) + d.Set("dateupdated", resp.InfrastructureConfiguration.DateUpdated) + d.Set("date_created", resp.InfrastructureConfiguration.DateCreated) + d.Set("description", resp.InfrastructureConfiguration.Description) + d.Set("instance_profile_name", resp.InfrastructureConfiguration.InstanceProfileName) + d.Set("instance_types", resp.InfrastructureConfiguration.InstanceTypes) + d.Set("key_pair", resp.InfrastructureConfiguration.KeyPair) + d.Set("logging", resp.InfrastructureConfiguration.Logging) + d.Set("name", resp.InfrastructureConfiguration.Name) + d.Set("security_group_ids", resp.InfrastructureConfiguration.SecurityGroupIds) + d.Set("sns_topic_arn", resp.InfrastructureConfiguration.SnsTopicArn) + d.Set("subnet_id", resp.InfrastructureConfiguration.SubnetId) + d.Set("terminate_instance_on_failure", resp.InfrastructureConfiguration.TerminateInstanceOnFailure) + if err := d.Set("tags", keyvaluetags.ImagebuilderKeyValueTags(resp.InfrastructureConfiguration.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } - return nil } diff --git a/aws/data_source_aws_imagebuilder_infrastructure_recipe.go b/aws/data_source_aws_imagebuilder_infrastructure_recipe.go index 1d487ff86a6..c1a334ee118 100644 --- a/aws/data_source_aws_imagebuilder_infrastructure_recipe.go +++ b/aws/data_source_aws_imagebuilder_infrastructure_recipe.go @@ -134,6 +134,7 @@ func dataSourceAwsImageBuilderRecipe() *schema.Resource { func dataSourceAwsImageBuilderRecipeRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).imagebuilderconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig resp, err := conn.GetImageRecipe(&imagebuilder.GetImageRecipeInput{ ImageRecipeArn: aws.String(d.Id()), @@ -143,23 +144,19 @@ func dataSourceAwsImageBuilderRecipeRead(d *schema.ResourceData, meta interface{ return fmt.Errorf("error reading Recipe (%s): %s", d.Id(), err) } - return recipeDescriptionAttributes(d, resp.ImageRecipe) -} - -func recipeDescriptionAttributes(d *schema.ResourceData, imageRecipe *imagebuilder.ImageRecipe) error { - d.SetId(*imageRecipe.Arn) - d.Set("arn", imageRecipe.Arn) - d.Set("block_device_mappings", imageRecipe.BlockDeviceMappings) - d.Set("components", imageRecipe.Components) - d.Set("datecreated", imageRecipe.DateCreated) - d.Set("description", imageRecipe.Description) - d.Set("name", imageRecipe.Name) - d.Set("owner", imageRecipe.Owner) - d.Set("parent_image", imageRecipe.ParentImage) - d.Set("platform", imageRecipe.Platform) - d.Set("semantic_version", imageRecipe.Version) + d.SetId(*resp.ImageRecipe.Arn) + d.Set("arn", resp.ImageRecipe.Arn) + d.Set("block_device_mappings", resp.ImageRecipe.BlockDeviceMappings) + d.Set("components", resp.ImageRecipe.Components) + d.Set("datecreated", resp.ImageRecipe.DateCreated) + d.Set("description", resp.ImageRecipe.Description) + d.Set("name", resp.ImageRecipe.Name) + d.Set("owner", resp.ImageRecipe.Owner) + d.Set("parent_image", resp.ImageRecipe.ParentImage) + d.Set("platform", resp.ImageRecipe.Platform) + d.Set("semantic_version", resp.ImageRecipe.Version) - if err := d.Set("tags", keyvaluetags.ImagebuilderKeyValueTags(imageRecipe.Tags).IgnoreAws().Map()); err != nil { + if err := d.Set("tags", keyvaluetags.ImagebuilderKeyValueTags(resp.ImageRecipe.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } diff --git a/aws/resource_aws_imagebuilder_component.go b/aws/resource_aws_imagebuilder_component.go index 7dd136b612e..e3165965e4f 100644 --- a/aws/resource_aws_imagebuilder_component.go +++ b/aws/resource_aws_imagebuilder_component.go @@ -130,6 +130,7 @@ func resourceAwsImageBuilderComponentCreate(d *schema.ResourceData, meta interfa func resourceAwsImageBuilderComponentRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).imagebuilderconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig resp, err := conn.GetComponent(&imagebuilder.GetComponentInput{ ComponentBuildVersionArn: aws.String(d.Id()), @@ -158,7 +159,7 @@ func resourceAwsImageBuilderComponentRead(d *schema.ResourceData, meta interface if err != nil { return fmt.Errorf("error listing tags for Component (%s): %s", d.Id(), err) } - if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil { + if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } diff --git a/aws/resource_aws_imagebuilder_infrastructure_configuration.go b/aws/resource_aws_imagebuilder_infrastructure_configuration.go index f70edd34c55..c2992579112 100644 --- a/aws/resource_aws_imagebuilder_infrastructure_configuration.go +++ b/aws/resource_aws_imagebuilder_infrastructure_configuration.go @@ -162,6 +162,7 @@ func resourceAwsImageBuilderInfrastructureConfigurationCreate(d *schema.Resource func resourceAwsImageBuilderInfrastructureConfigurationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).imagebuilderconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig resp, err := conn.GetInfrastructureConfiguration(&imagebuilder.GetInfrastructureConfigurationInput{ InfrastructureConfigurationArn: aws.String(d.Id()), @@ -195,7 +196,7 @@ func resourceAwsImageBuilderInfrastructureConfigurationRead(d *schema.ResourceDa if err != nil { return fmt.Errorf("error listing tags for Infrastructure Configuration (%s): %s", d.Id(), err) } - if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil { + if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } diff --git a/aws/resource_aws_imagebuilder_recipe.go b/aws/resource_aws_imagebuilder_recipe.go index 68297edc9ab..17844c33076 100644 --- a/aws/resource_aws_imagebuilder_recipe.go +++ b/aws/resource_aws_imagebuilder_recipe.go @@ -189,6 +189,7 @@ func resourceAwsImageBuilderRecipeCreate(d *schema.ResourceData, meta interface{ func resourceAwsImageBuilderRecipeRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).imagebuilderconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig resp, err := conn.GetImageRecipe(&imagebuilder.GetImageRecipeInput{ ImageRecipeArn: aws.String(d.Id()), @@ -218,7 +219,7 @@ func resourceAwsImageBuilderRecipeRead(d *schema.ResourceData, meta interface{}) if err != nil { return fmt.Errorf("error listing tags for Recipe (%s): %s", d.Id(), err) } - if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil { + if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } From 507fe429fb7ef5249030b29aff7722833a67b723 Mon Sep 17 00:00:00 2001 From: Dogers Date: Mon, 25 May 2020 21:33:29 +0100 Subject: [PATCH 10/22] Fix linting --- aws/data_source_aws_imagebuilder_component_test.go | 2 +- aws/data_source_aws_imagebuilder_infrastructure_recipe.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/aws/data_source_aws_imagebuilder_component_test.go b/aws/data_source_aws_imagebuilder_component_test.go index 4c01aac6ed4..a367d642d1d 100644 --- a/aws/data_source_aws_imagebuilder_component_test.go +++ b/aws/data_source_aws_imagebuilder_component_test.go @@ -55,4 +55,4 @@ data "aws_builder_component" "test" { arn = "arn:aws:imagebuilder:eu-west-1:116147290797:component/test/1.0.1/1" } `, name) -} \ No newline at end of file +} diff --git a/aws/data_source_aws_imagebuilder_infrastructure_recipe.go b/aws/data_source_aws_imagebuilder_infrastructure_recipe.go index c1a334ee118..02d9b9cd89e 100644 --- a/aws/data_source_aws_imagebuilder_infrastructure_recipe.go +++ b/aws/data_source_aws_imagebuilder_infrastructure_recipe.go @@ -128,7 +128,6 @@ func dataSourceAwsImageBuilderRecipe() *schema.Resource { }, "tags": tagsSchema(), }, - } } From ca89e2b38c3e645388da6035e11b22a66aef2864 Mon Sep 17 00:00:00 2001 From: Jakub Kania Date: Mon, 13 Jul 2020 00:51:25 +0200 Subject: [PATCH 11/22] [#11084] Fix the imagebuilder resource, add test and docs # Conflicts: # aws/provider.go --- ...agebuilder_infrastructure_configuration.go | 48 ++- ...ilder_infrastructure_configuration_test.go | 355 ++++++++++++++++++ website/allowed-subcategories.txt | 1 + website/aws.erb | 14 + ...infrastructure_configuration.html.markdown | 77 ++++ 5 files changed, 476 insertions(+), 19 deletions(-) create mode 100644 aws/resource_aws_imagebuilder_infrastructure_configuration_test.go create mode 100644 website/docs/r/imagebuilder_infrastructure_configuration.html.markdown diff --git a/aws/resource_aws_imagebuilder_infrastructure_configuration.go b/aws/resource_aws_imagebuilder_infrastructure_configuration.go index c2992579112..5eed4f1c8a8 100644 --- a/aws/resource_aws_imagebuilder_infrastructure_configuration.go +++ b/aws/resource_aws_imagebuilder_infrastructure_configuration.go @@ -27,11 +27,11 @@ func resourceAwsImageBuilderInfrastructureConfiguration() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "datecreated": { + "date_created": { Type: schema.TypeString, Computed: true, }, - "dateupdated": { + "date_updated": { Type: schema.TypeString, Computed: true, }, @@ -109,6 +109,7 @@ func resourceAwsImageBuilderInfrastructureConfiguration() *schema.Resource { "terminate_instance_on_failure": { Type: schema.TypeBool, Optional: true, + Default: false, }, "tags": tagsSchema(), }, @@ -179,8 +180,8 @@ func resourceAwsImageBuilderInfrastructureConfigurationRead(d *schema.ResourceDa } d.Set("arn", resp.InfrastructureConfiguration.Arn) - d.Set("datecreated", resp.InfrastructureConfiguration.DateCreated) - d.Set("dateupdated", resp.InfrastructureConfiguration.DateUpdated) + d.Set("date_created", resp.InfrastructureConfiguration.DateCreated) + d.Set("date_updated", resp.InfrastructureConfiguration.DateUpdated) d.Set("description", resp.InfrastructureConfiguration.Description) d.Set("instance_profile_name", resp.InfrastructureConfiguration.InstanceProfileName) d.Set("instance_types", resp.InfrastructureConfiguration.InstanceTypes) @@ -210,30 +211,41 @@ func resourceAwsImageBuilderInfrastructureConfigurationUpdate(d *schema.Resource upd := imagebuilder.UpdateInfrastructureConfigurationInput{ InfrastructureConfigurationArn: aws.String(d.Id()), InstanceProfileName: aws.String(d.Get("instance_profile_name").(string)), - Description: aws.String(d.Get("description").(string)), - KeyPair: aws.String(d.Get("key_pair").(string)), - SubnetId: aws.String(d.Get("subnet_id").(string)), Logging: expandAwsImageBuilderLogsConfig(d), } - if d.HasChange("instance_types") { - if attr := d.Get("instance_types").(*schema.Set); attr.Len() > 0 { - upd.InstanceTypes = expandStringList(attr.List()) - } + if description, ok := d.GetOk("description"); ok { + upd.Description = aws.String(description.(string)) + } + + if key_pair, ok := d.GetOk("key_pair"); ok { + upd.KeyPair = aws.String(key_pair.(string)) + } + + if subnet_id, ok := d.GetOk("subnet_id"); ok { + upd.SubnetId = aws.String(subnet_id.(string)) + } + + if attr := d.Get("instance_types").(*schema.Set); attr.Len() > 0 { + upd.InstanceTypes = expandStringList(attr.List()) } + if d.HasChange("instance_profile_name") { upd.InstanceProfileName = aws.String(d.Get("instance_profile_name").(string)) } + if v, ok := d.GetOk("security_group_ids"); ok { if attr := v.(*schema.Set); attr.Len() > 0 { upd.SecurityGroupIds = expandStringList(attr.List()) } } - if d.HasChange("sns_topic_arn") { - upd.SnsTopicArn = aws.String(d.Get("sns_topic_arn").(string)) + + if sns_topic_arn, ok := d.GetOk("sns_topic_arn"); ok { + upd.SnsTopicArn = aws.String(sns_topic_arn.(string)) } - if d.HasChange("terminate_instance_on_failure") { - upd.TerminateInstanceOnFailure = aws.Bool(d.Get("terminate_instance_on_failure").(bool)) + + if terminate_instance_on_failure, ok := d.GetOk("terminate_instance_on_failure"); ok { + upd.TerminateInstanceOnFailure = aws.Bool(terminate_instance_on_failure.(bool)) } if d.HasChange("security_group_ids") { @@ -276,16 +288,14 @@ func resourceAwsImageBuilderInfrastructureConfigurationDelete(d *schema.Resource } func flattenAwsImageBuilderLogsConfig(logsConfig *imagebuilder.Logging) []interface{} { - if logsConfig == nil { + if logsConfig == nil || logsConfig.S3Logs == nil { return []interface{}{} } values := map[string]interface{}{} // If more logging options are added, add more ifs! - if v := logsConfig.S3Logs; v != nil { - values["s3_logs"] = flattenAwsImageBuilderS3Logs(v) - } + values["s3_logs"] = flattenAwsImageBuilderS3Logs(logsConfig.S3Logs) return []interface{}{values} } diff --git a/aws/resource_aws_imagebuilder_infrastructure_configuration_test.go b/aws/resource_aws_imagebuilder_infrastructure_configuration_test.go new file mode 100644 index 00000000000..2d9958b9fa1 --- /dev/null +++ b/aws/resource_aws_imagebuilder_infrastructure_configuration_test.go @@ -0,0 +1,355 @@ +package aws + +import ( + "errors" + "fmt" + "github.com/aws/aws-sdk-go/aws/awserr" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/imagebuilder" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +//Check the minimal configuration +func TestAccAWSImageBuilderInfrastructureConfiguration_basic(t *testing.T) { + var conf imagebuilder.InfrastructureConfiguration + RandomString := fmt.Sprintf("tf-test-%d", acctest.RandInt()) + resourceName := "aws_imagebuilder_infrastructure_configuration.test" + resource.ParallelTest(t, resource.TestCase{ + IDRefreshName: resourceName, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSImageBuilderInfrastructureConfigurationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSImageBuilderInfrastructureConfiguration_basic(RandomString), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSImageBuilderInfrastructureConfigurationExist(resourceName, &conf), + resource.TestCheckResourceAttrSet(resourceName, "instance_profile_name"), + resource.TestCheckResourceAttrSet(resourceName, "name"), + ), + }, + }, + }) +} + +//Check the configuration with everything +func TestAccAWSImageBuilderInfrastructureConfiguration_advanced(t *testing.T) { + var conf imagebuilder.InfrastructureConfiguration + RandomString := fmt.Sprintf("tf-test-%d", acctest.RandInt()) + resourceName := "aws_imagebuilder_infrastructure_configuration.test" + + resource.ParallelTest(t, resource.TestCase{ + IDRefreshName: resourceName, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSImageBuilderInfrastructureConfigurationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSImageBuilderInfrastructureConfiguration_advanced(RandomString), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSImageBuilderInfrastructureConfigurationExist(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "instance_profile_name", RandomString), + resource.TestCheckResourceAttr(resourceName, "name", RandomString), + resource.TestCheckResourceAttr(resourceName, "description", "example desc"), + resource.TestCheckResourceAttr(resourceName, "key_pair", RandomString), + resource.TestCheckResourceAttrSet(resourceName, "sns_topic_arn"), + resource.TestCheckResourceAttrSet(resourceName, "subnet_id"), + resource.TestCheckResourceAttr(resourceName, "terminate_instance_on_failure", "false"), + resource.TestCheckResourceAttr(resourceName, "security_group_ids.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_types.#", "1"), + resource.TestCheckResourceAttr(resourceName, "logging.0.s3_logs.0.s3_bucket_name", RandomString), + resource.TestCheckResourceAttr(resourceName, "logging.0.s3_logs.0.s3_key_prefix", "logs"), + ), + }, + }, + }) +} + +//Test the tags work +func TestAccAWSImageBuilderInfrastructureConfiguration_tags(t *testing.T) { + var conf imagebuilder.InfrastructureConfiguration + RandomString := fmt.Sprintf("tf-test-%d", acctest.RandInt()) + resourceName := "aws_imagebuilder_infrastructure_configuration.test" + + resource.ParallelTest(t, resource.TestCase{ + IDRefreshName: resourceName, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSImageBuilderInfrastructureConfigurationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSImageBuilderInfrastructureConfiguration_tags1(RandomString), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSImageBuilderInfrastructureConfigurationExist(resourceName, &conf), + resource.TestCheckResourceAttrSet(resourceName, "instance_profile_name"), + resource.TestCheckResourceAttrSet(resourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + ), + }, + { + Config: testAccAWSImageBuilderInfrastructureConfiguration_tags2(RandomString), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSImageBuilderInfrastructureConfigurationExist(resourceName, &conf), + resource.TestCheckResourceAttrSet(resourceName, "instance_profile_name"), + resource.TestCheckResourceAttrSet(resourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + ), + }, + }, + }) +} + +func testAccCheckAWSImageBuilderInfrastructureConfigurationExist(n string, res *imagebuilder.InfrastructureConfiguration) 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 errors.New("No ImageBuilderInfrastructureConfiguration ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).imagebuilderconn + + resp, err := conn.GetInfrastructureConfiguration(&imagebuilder.GetInfrastructureConfigurationInput{ + InfrastructureConfigurationArn: aws.String(rs.Primary.Attributes["arn"]), + }) + + if err != nil { + return err + } + + if resp == nil || resp.InfrastructureConfiguration == nil { + return fmt.Errorf("Infrastructure configuration (%s) not found", rs.Primary.Attributes["name"]) + } + *res = *resp.InfrastructureConfiguration + return nil + } +} + +func testAccCheckAWSImageBuilderInfrastructureConfigurationDestroy(s *terraform.State) error { + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_imagebuilder_infrastructure_configuration" { + continue + } + + conn := testAccProvider.Meta().(*AWSClient).imagebuilderconn + + resp, err := conn.GetInfrastructureConfiguration(&imagebuilder.GetInfrastructureConfigurationInput{ + InfrastructureConfigurationArn: aws.String(rs.Primary.Attributes["arn"]), + }) + + if err == nil { + if resp.InfrastructureConfiguration != nil { + return fmt.Errorf("ImageBuilderInfrastructureConfiguration %q still exists", rs.Primary.ID) + } + } + + // Verify the error + if awsErr, ok := err.(awserr.Error); ok { + if awsErr.Code() == "ResourceNotFoundException" { + return nil + } + } + return err + } + + return nil +} + +func testAccAWSImageBuilderInfrastructureConfiguration_basic(ConfigurationName string) string { + return fmt.Sprintf(` + +resource "aws_imagebuilder_infrastructure_configuration" "test" { + instance_profile_name = aws_iam_instance_profile.test_profile.name + name = "%[1]s" +} + +resource "aws_iam_instance_profile" "test_profile" { + name = "%[1]s" + role = aws_iam_role.role.name +} + +resource "aws_iam_role" "role" { + name = "%[1]s" + path = "/" + + assume_role_policy = < +
  • + Image Builder + +
  • +
  • IoT
  • -
  • - Image Builder - -
  • -
  • IoT