Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

r/aws_batch_compute_environment: Add ec2_configuration #21565

3 changes: 3 additions & 0 deletions .changelog/21565.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_batch_compute_environment: Add `ec2_configuration` argument to `compute_resources` configuration block
```
144 changes: 128 additions & 16 deletions internal/service/batch/compute_environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ func ResourceComputeEnvironment() *schema.Resource {
),

Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Computed: true,
},
"compute_environment_name": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -78,6 +82,30 @@ func ResourceComputeEnvironment() *schema.Resource {
Optional: true,
Computed: true,
},
"ec2_configuration": {
Type: schema.TypeList,
Optional: true,
Computed: true,
ForceNew: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"image_id_override": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ValidateFunc: validation.StringLenBetween(1, 256),
},
"image_type": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringLenBetween(1, 256),
},
},
},
},
"ec2_key_pair": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -164,6 +192,10 @@ func ResourceComputeEnvironment() *schema.Resource {
},
},
},
"ecs_cluster_arn": {
Type: schema.TypeString,
Computed: true,
},
"service_role": {
Type: schema.TypeString,
Optional: true,
Expand All @@ -179,6 +211,14 @@ func ResourceComputeEnvironment() *schema.Resource {
ValidateFunc: validation.StringInSlice(batch.CEState_Values(), true),
Default: batch.CEStateEnabled,
},
"status": {
Type: schema.TypeString,
Computed: true,
},
"status_reason": {
Type: schema.TypeString,
Computed: true,
},
"tags": tftags.TagsSchema(),
"tags_all": tftags.TagsSchemaComputed(),
"type": {
Expand All @@ -190,22 +230,6 @@ func ResourceComputeEnvironment() *schema.Resource {
},
ValidateFunc: validation.StringInSlice(batch.CEType_Values(), true),
},
"arn": {
Type: schema.TypeString,
Computed: true,
},
"ecs_cluster_arn": {
Type: schema.TypeString,
Computed: true,
},
"status": {
Type: schema.TypeString,
Computed: true,
},
"status_reason": {
Type: schema.TypeString,
Computed: true,
},
},
}
}
Expand Down Expand Up @@ -461,6 +485,10 @@ func expandBatchComputeResource(tfMap map[string]interface{}) *batch.ComputeReso
apiObject.DesiredvCpus = aws.Int64(int64(v))
}

if v, ok := tfMap["ec2_configuration"].([]interface{}); ok && len(v) > 0 {
apiObject.Ec2Configuration = expandBatchEc2Configurations(v)
}

if v, ok := tfMap["ec2_key_pair"].(string); ok && v != "" {
apiObject.Ec2KeyPair = aws.String(v)
}
Expand Down Expand Up @@ -514,6 +542,50 @@ func expandBatchComputeResource(tfMap map[string]interface{}) *batch.ComputeReso
return apiObject
}

func expandBatchEc2Configuration(tfMap map[string]interface{}) *batch.Ec2Configuration {
if tfMap == nil {
return nil
}

apiObject := &batch.Ec2Configuration{}

if v, ok := tfMap["image_id_override"].(string); ok && v != "" {
apiObject.ImageIdOverride = aws.String(v)
}

if v, ok := tfMap["image_type"].(string); ok && v != "" {
apiObject.ImageType = aws.String(v)
}

return apiObject
}

func expandBatchEc2Configurations(tfList []interface{}) []*batch.Ec2Configuration {
if len(tfList) == 0 {
return nil
}

var apiObjects []*batch.Ec2Configuration

for _, tfMapRaw := range tfList {
tfMap, ok := tfMapRaw.(map[string]interface{})

if !ok {
continue
}

apiObject := expandBatchEc2Configuration(tfMap)

if apiObject == nil {
continue
}

apiObjects = append(apiObjects, apiObject)
}

return apiObjects
}

func expandBatchLaunchTemplateSpecification(tfMap map[string]interface{}) *batch.LaunchTemplateSpecification {
if tfMap == nil {
return nil
Expand Down Expand Up @@ -555,6 +627,10 @@ func flattenBatchComputeResource(apiObject *batch.ComputeResource) map[string]in
tfMap["desired_vcpus"] = aws.Int64Value(v)
}

if v := apiObject.Ec2Configuration; v != nil {
tfMap["ec2_configuration"] = flattenBatchEc2Configurations(v)
}

if v := apiObject.Ec2KeyPair; v != nil {
tfMap["ec2_key_pair"] = aws.StringValue(v)
}
Expand Down Expand Up @@ -606,6 +682,42 @@ func flattenBatchComputeResource(apiObject *batch.ComputeResource) map[string]in
return tfMap
}

func flattenBatchEc2Configuration(apiObject *batch.Ec2Configuration) map[string]interface{} {
if apiObject == nil {
return nil
}

tfMap := map[string]interface{}{}

if v := apiObject.ImageIdOverride; v != nil {
tfMap["image_id_override"] = aws.StringValue(v)
}

if v := apiObject.ImageType; v != nil {
tfMap["image_type"] = aws.StringValue(v)
}

return tfMap
}

func flattenBatchEc2Configurations(apiObjects []*batch.Ec2Configuration) []interface{} {
if len(apiObjects) == 0 {
return nil
}

var tfList []interface{}

for _, apiObject := range apiObjects {
if apiObject == nil {
continue
}

tfList = append(tfList, flattenBatchEc2Configuration(apiObject))
}

return tfList
}

func flattenBatchLaunchTemplateSpecification(apiObject *batch.LaunchTemplateSpecification) map[string]interface{} {
if apiObject == nil {
return nil
Expand Down
100 changes: 100 additions & 0 deletions internal/service/batch/compute_environment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ func TestAccBatchComputeEnvironment_createEC2(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.allocation_strategy", ""),
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.bid_percentage", "0"),
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.desired_vcpus", "0"),
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.ec2_configuration.#", "1"),
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.ec2_configuration.0.image_type", "ECS_AL2"),
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.ec2_key_pair", ""),
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.image_id", ""),
resource.TestCheckResourceAttrPair(resourceName, "compute_resources.0.instance_role", instanceProfileResourceName, "arn"),
Expand Down Expand Up @@ -953,6 +955,68 @@ func TestAccBatchComputeEnvironment_ComputeResources_maxVCPUs(t *testing.T) {
})
}

func TestAccBatchComputeEnvironment_ec2Configuration(t *testing.T) {
var ce batch.ComputeEnvironmentDetail
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_batch_compute_environment.test"
instanceProfileResourceName := "aws_iam_instance_profile.ecs_instance"
securityGroupResourceName := "aws_security_group.test"
serviceRoleResourceName := "aws_iam_role.batch_service"
spotFleetRoleResourceName := "aws_iam_role.ec2_spot_fleet"
subnetResourceName := "aws_subnet.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t); testAccPreCheck(t) },
ErrorCheck: acctest.ErrorCheck(t, batch.EndpointsID),
Providers: acctest.Providers,
CheckDestroy: testAccCheckBatchComputeEnvironmentDestroy,
Steps: []resource.TestStep{
{
Config: testAccComputeEnvironmentEC2Configuration(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeEnvironmentExists(resourceName, &ce),
acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "batch", fmt.Sprintf("compute-environment/%s", rName)),
resource.TestCheckResourceAttr(resourceName, "compute_environment_name", rName),
resource.TestCheckResourceAttr(resourceName, "compute_environment_name_prefix", ""),
resource.TestCheckResourceAttr(resourceName, "compute_resources.#", "1"),
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.allocation_strategy", ""),
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.bid_percentage", "0"),
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.desired_vcpus", "0"),
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.ec2_key_pair", ""),
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.image_id", ""),
resource.TestCheckResourceAttrPair(resourceName, "compute_resources.0.instance_role", instanceProfileResourceName, "arn"),
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.instance_type.#", "1"),
resource.TestCheckTypeSetElemAttr(resourceName, "compute_resources.0.instance_type.*", "optimal"),
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.ec2_configuration.#", "1"),
resource.TestCheckResourceAttrSet(resourceName, "compute_resources.0.ec2_configuration.0.image_id_override"),
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.ec2_configuration.0.image_type", "ECS_AL2"),
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.max_vcpus", "16"),
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.min_vcpus", "0"),
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.security_group_ids.#", "1"),
resource.TestCheckTypeSetElemAttrPair(resourceName, "compute_resources.0.security_group_ids.*", securityGroupResourceName, "id"),
resource.TestCheckResourceAttrPair(resourceName, "compute_resources.0.spot_iam_fleet_role", spotFleetRoleResourceName, "arn"),
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.subnets.#", "1"),
resource.TestCheckTypeSetElemAttrPair(resourceName, "compute_resources.0.subnets.*", subnetResourceName, "id"),
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.tags.%", "0"),
resource.TestCheckResourceAttr(resourceName, "compute_resources.0.type", "SPOT"),
resource.TestCheckResourceAttrSet(resourceName, "ecs_cluster_arn"),
resource.TestCheckResourceAttrPair(resourceName, "service_role", serviceRoleResourceName, "arn"),
resource.TestCheckResourceAttr(resourceName, "state", "ENABLED"),
resource.TestCheckResourceAttrSet(resourceName, "status"),
resource.TestCheckResourceAttrSet(resourceName, "status_reason"),
resource.TestCheckResourceAttr(resourceName, "tags.%", "0"),
resource.TestCheckResourceAttr(resourceName, "type", "MANAGED"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccBatchComputeEnvironment_launchTemplate(t *testing.T) {
var ce batch.ComputeEnvironmentDetail
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
Expand Down Expand Up @@ -2080,3 +2144,39 @@ resource "aws_batch_compute_environment" "test" {
}
`, rName, tagKey1, tagValue1, tagKey2, tagValue2))
}

func testAccComputeEnvironmentEC2Configuration(rName string) string {
return acctest.ConfigCompose(
testAccComputeEnvironmentBaseConfig(rName),
acctest.ConfigLatestAmazonLinuxHvmEbsAmi(),
fmt.Sprintf(`
resource "aws_batch_compute_environment" "test" {
compute_environment_name = %[1]q

compute_resources {
instance_role = aws_iam_instance_profile.ecs_instance.arn
instance_type = ["optimal"]
ec2_configuration {
image_id_override = data.aws_ami.amzn-ami-minimal-hvm-ebs.id
image_type = "ECS_AL2"
}

max_vcpus = 16
min_vcpus = 0

security_group_ids = [
aws_security_group.test.id
]
spot_iam_fleet_role = aws_iam_role.ec2_spot_fleet.arn
subnets = [
aws_subnet.test.id
]
type = "SPOT"
}

service_role = aws_iam_role.batch_service.arn
type = "MANAGED"
depends_on = [aws_iam_role_policy_attachment.batch_service]
}
`, rName))
}
10 changes: 9 additions & 1 deletion website/docs/r/batch_compute_environment.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,9 @@ resource "aws_batch_compute_environment" "sample" {
* `allocation_strategy` - (Optional) The allocation strategy to use for the compute resource in case not enough instances of the best fitting instance type can be allocated. Valid items are `BEST_FIT_PROGRESSIVE`, `SPOT_CAPACITY_OPTIMIZED` or `BEST_FIT`. Defaults to `BEST_FIT`. See [AWS docs](https://docs.aws.amazon.com/batch/latest/userguide/allocation-strategies.html) for details. This parameter isn't applicable to jobs running on Fargate resources, and shouldn't be specified.
* `bid_percentage` - (Optional) Integer of minimum percentage that a Spot Instance price must be when compared with the On-Demand price for that instance type before instances are launched. For example, if your bid percentage is 20% (`20`), then the Spot price must be below 20% of the current On-Demand price for that EC2 instance. This parameter is required for SPOT compute environments. This parameter isn't applicable to jobs running on Fargate resources, and shouldn't be specified.
* `desired_vcpus` - (Optional) The desired number of EC2 vCPUS in the compute environment. This parameter isn't applicable to jobs running on Fargate resources, and shouldn't be specified.
* `ec2_configuration` - (Optional) Provides information used to select Amazon Machine Images (AMIs) for EC2 instances in the compute environment. If Ec2Configuration isn't specified, the default is ECS_AL2. This parameter isn't applicable to jobs that are running on Fargate resources, and shouldn't be specified.
* `ec2_key_pair` - (Optional) The EC2 key pair that is used for instances launched in the compute environment. This parameter isn't applicable to jobs running on Fargate resources, and shouldn't be specified.
* `image_id` - (Optional) The Amazon Machine Image (AMI) ID used for instances launched in the compute environment. This parameter isn't applicable to jobs running on Fargate resources, and shouldn't be specified.
* `image_id` - (Optional) The Amazon Machine Image (AMI) ID used for instances launched in the compute environment. This parameter isn't applicable to jobs running on Fargate resources, and shouldn't be specified. (Deprecated, use [`image_id_override`](#image_id_override) instead)
* `instance_role` - (Optional) The Amazon ECS instance role applied to Amazon EC2 instances in a compute environment. This parameter isn't applicable to jobs running on Fargate resources, and shouldn't be specified.
* `instance_type` - (Optional) A list of instance types that may be launched. This parameter isn't applicable to jobs running on Fargate resources, and shouldn't be specified.
* `launch_template` - (Optional) The launch template to use for your compute resources. See details below. This parameter isn't applicable to jobs running on Fargate resources, and shouldn't be specified.
Expand All @@ -178,6 +179,13 @@ resource "aws_batch_compute_environment" "sample" {
* `tags` - (Optional) Key-value pair tags to be applied to resources that are launched in the compute environment. This parameter isn't applicable to jobs running on Fargate resources, and shouldn't be specified.
* `type` - (Required) The type of compute environment. Valid items are `EC2`, `SPOT`, `FARGATE` or `FARGATE_SPOT`.

### ec2_configuration

`ec2_configuration` supports the following:

* `image_id_override` - (Optional) The AMI ID used for instances launched in the compute environment that match the image type. This setting overrides the [`image_id` argument](#image_id) in the `compute_resourcess block.
* `image_type` - (Optional) The image type to match with the instance type to select an AMI. If the `image_id_override` parameter isn't specified, then a recent [Amazon ECS-optimized Amazon Linux 2 AMI](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-optimized_AMI.html#al2ami) (`ECS_AL2`) is used.

### launch_template

`launch_template` supports the following:
Expand Down