diff --git a/aws/resource_aws_codebuild_project.go b/aws/resource_aws_codebuild_project.go index 32745251606..3283511ef52 100644 --- a/aws/resource_aws_codebuild_project.go +++ b/aws/resource_aws_codebuild_project.go @@ -179,6 +179,31 @@ func resourceAwsCodeBuildProject() *schema.Resource { ValidateFunc: validateAwsCodeBuildTimeout, }, "tags": tagsSchema(), + "vpc_config": { + Type: schema.TypeSet, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "vpc_id": { + Type: schema.TypeString, + Required: true, + }, + "subnets": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + MaxItems: 16, + }, + "security_group_ids": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + MaxItems: 5, + }, + }, + }, + }, }, } } @@ -213,6 +238,11 @@ func resourceAwsCodeBuildProjectCreate(d *schema.ResourceData, meta interface{}) params.TimeoutInMinutes = aws.Int64(int64(v.(int))) } + if _, ok := d.GetOk("vpc_config"); ok { + vpcConfig := expandVpcConfig(d) + params.VpcConfig = vpcConfig + } + if v, ok := d.GetOk("tags"); ok { params.Tags = tagsFromMapCodeBuild(v.(map[string]interface{})) } @@ -228,6 +258,10 @@ func resourceAwsCodeBuildProjectCreate(d *schema.ResourceData, meta interface{}) return resource.RetryableError(err) } + if isAWSErr(err, "InvalidInputException", "Not authorized to perform DescribeSecurityGroups") { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) } @@ -324,6 +358,29 @@ func expandProjectEnvironment(d *schema.ResourceData) *codebuild.ProjectEnvironm return projectEnv } +func expandVpcConfig(d *schema.ResourceData) *codebuild.VpcConfig { + configs := d.Get("vpc_config").(*schema.Set).List() + data := configs[0].(map[string]interface{}) + + vpcConfig := codebuild.VpcConfig{ + VpcId: aws.String(data["vpc_id"].(string)), + } + + var vpcConfigSubnets []*string + for _, v := range data["subnets"].([]interface{}) { + vpcConfigSubnets = append(vpcConfigSubnets, aws.String(v.(string))) + } + vpcConfig.Subnets = vpcConfigSubnets + + var vpcSecurityGroupIds []*string + for _, s := range data["security_group_ids"].([]interface{}) { + vpcSecurityGroupIds = append(vpcSecurityGroupIds, aws.String(s.(string))) + } + vpcConfig.SecurityGroupIds = vpcSecurityGroupIds + + return &vpcConfig +} + func expandProjectSource(d *schema.ResourceData) codebuild.ProjectSource { configs := d.Get("source").(*schema.Set).List() projectSource := codebuild.ProjectSource{} @@ -390,6 +447,10 @@ func resourceAwsCodeBuildProjectRead(d *schema.ResourceData, meta interface{}) e return err } + if err := d.Set("vpc_config", schema.NewSet(resourceAwsCodeBuildVpcConfigHash, flattenAwsCodebuildVpcConfig(project.VpcConfig))); err != nil { + return err + } + d.Set("description", project.Description) d.Set("encryption_key", project.EncryptionKey) d.Set("name", project.Name) @@ -425,6 +486,11 @@ func resourceAwsCodeBuildProjectUpdate(d *schema.ResourceData, meta interface{}) params.Artifacts = &projectArtifacts } + if d.HasChange("vpc_config") { + vpcConfig := expandVpcConfig(d) + params.VpcConfig = vpcConfig + } + if d.HasChange("description") { params.Description = aws.String(d.Get("description").(string)) } @@ -556,6 +622,26 @@ func flattenAwsCodebuildProjectSource(source *codebuild.ProjectSource) *schema.S } +func flattenAwsCodebuildVpcConfig(vpcConfig *codebuild.VpcConfig) []interface{} { + values := map[string]interface{}{} + + values["vpc_id"] = *vpcConfig.VpcId + + var subnets []string + for _, s := range vpcConfig.Subnets { + subnets = append(subnets, *s) + } + values["subnets"] = subnets + + var securityGroupIds []string + for _, s := range vpcConfig.SecurityGroupIds { + securityGroupIds = append(securityGroupIds, *s) + } + values["security_group_ids"] = securityGroupIds + + return []interface{}{values} +} + func resourceAwsCodeBuildProjectArtifactsHash(v interface{}) int { var buf bytes.Buffer m := v.(map[string]interface{}) @@ -567,6 +653,25 @@ func resourceAwsCodeBuildProjectArtifactsHash(v interface{}) int { return hashcode.String(buf.String()) } +func resourceAwsCodeBuildVpcConfigHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + + buf.WriteString(fmt.Sprintf("%s-", m["vpc_id"].(string))) + + for _, s := range m["subnets"].([]string) { + buf.WriteString(fmt.Sprintf("%s-", s)) + } + + if m["security_group_ids"] != nil { + for _, s := range m["security_group_ids"].([]string) { + buf.WriteString(fmt.Sprintf("%s-", s)) + } + } + + return hashcode.String(buf.String()) +} + func resourceAwsCodeBuildProjectEnvironmentHash(v interface{}) int { var buf bytes.Buffer m := v.(map[string]interface{}) diff --git a/aws/resource_aws_codebuild_project_test.go b/aws/resource_aws_codebuild_project_test.go index e79e49a8ff2..91215648dac 100644 --- a/aws/resource_aws_codebuild_project_test.go +++ b/aws/resource_aws_codebuild_project_test.go @@ -324,6 +324,19 @@ func testAccCheckAWSCodeBuildProjectDestroy(s *terraform.State) error { func testAccAWSCodeBuildProjectConfig_basic(rName string) string { return fmt.Sprintf(` +resource "aws_vpc" "codebuild_vpc" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "codebuild_subnet" { + vpc_id = "${aws_vpc.codebuild_vpc.id}" + cidr_block = "10.0.0.0/24" +} + +resource "aws_security_group" "codebuild_security_group" { + vpc_id = "${aws_vpc.codebuild_vpc.id}" +} + resource "aws_iam_role" "codebuild_role" { name = "codebuild-role-%s" assume_role_policy = <