From a50c27c7ae1b68c6e6bebc26cf31c9970ae60609 Mon Sep 17 00:00:00 2001 From: Ryo Takaishi Date: Thu, 6 Jun 2024 17:28:39 +0900 Subject: [PATCH 01/26] add ecs_properties --- internal/service/batch/ecs_properties.go | 727 ++++++++++++++++++ internal/service/batch/job_definition.go | 475 +++++++++++- internal/service/batch/job_definition_test.go | 196 +++++ 3 files changed, 1395 insertions(+), 3 deletions(-) create mode 100644 internal/service/batch/ecs_properties.go diff --git a/internal/service/batch/ecs_properties.go b/internal/service/batch/ecs_properties.go new file mode 100644 index 00000000000..0311b7e13c0 --- /dev/null +++ b/internal/service/batch/ecs_properties.go @@ -0,0 +1,727 @@ +package batch + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/batch" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-aws/internal/flex" +) + +const ( + IpcModeHost = "host" + IpcModeTask = "task" + IpcModeNone = "none" + PicModeHost = "host" + PicModeTask = "task" +) + +func IpcMode_Values() []string { + return []string{IpcModeHost, IpcModeTask, IpcModeNone} +} + +func PidMode_Values() []string { + return []string{PicModeHost, PicModeTask} +} + +func expandECSTaskProperties(taskPropsMap map[string]interface{}) *batch.EcsTaskProperties { + taskProps := &batch.EcsTaskProperties{} + + if v, ok := taskPropsMap["containers"]; ok { + containers := v.([]interface{}) + taskProps.Containers = expandEcsTaskContainers(containers) + } + + if v, ok := taskPropsMap["ephemeral_storage"].(*schema.Set); ok && v.Len() > 0 { + ephemeralStorage := &batch.EphemeralStorage{} + for _, e := range v.List() { + if v, ok := e.(map[string]interface{})["size_in_gib"].(int); ok { + ephemeralStorage.SizeInGiB = aws.Int64(int64(v)) + } + } + taskProps.EphemeralStorage = ephemeralStorage + } + + if v, ok := taskPropsMap["execution_role_arn"].(string); ok && v != "" { + taskProps.ExecutionRoleArn = aws.String(v) + } + + if v, ok := taskPropsMap["ipc_mode"].(string); ok && v != "" { + taskProps.IpcMode = aws.String(v) + } + + if v, ok := taskPropsMap["network_configuration"].([]interface{}); ok && len(v) > 0 { + networkConfig := &batch.NetworkConfiguration{} + if v, ok := v[0].(map[string]interface{})["assign_public_ip"].(string); ok && v != "" { + networkConfig.AssignPublicIp = aws.String(v) + } + taskProps.NetworkConfiguration = networkConfig + } + + if v, ok := taskPropsMap["pid_mode"].(string); ok && v != "" { + taskProps.PidMode = aws.String(v) + } + + if v, ok := taskPropsMap["platform_version"].(string); ok && v != "" { + taskProps.PlatformVersion = aws.String(v) + } + + if v, ok := taskPropsMap["runtime_platform"].(*schema.Set); ok && v.Len() > 0 { + runtimePlatform := &batch.RuntimePlatform{} + for _, r := range v.List() { + if v, ok := r.(map[string]interface{})["cpu_architecture"].(string); ok && v != "" { + runtimePlatform.CpuArchitecture = aws.String(v) + } + if v, ok := r.(map[string]interface{})["operation_system_family"].(string); ok && v != "" { + runtimePlatform.OperatingSystemFamily = aws.String(v) + } + } + taskProps.RuntimePlatform = runtimePlatform + } + + if v, ok := taskPropsMap["task_role_arn"].(string); ok && v != "" { + taskProps.TaskRoleArn = aws.String(v) + } + + //volumes + if v, ok := taskPropsMap["volumes"].(*schema.Set); ok && v.Len() > 0 { + volumes := []*batch.Volume{} + for _, vol := range v.List() { + volume := &batch.Volume{} + + if v, ok := vol.(map[string]interface{})["efs_volume_configuration"].(map[string]interface{}); ok && len(v) > 0 { + efs := &batch.EFSVolumeConfiguration{} + if v, ok := v["file_system_id"].(string); ok && v != "" { + efs.FileSystemId = aws.String(v) + } + + if v, ok := v["authorization_config"].(map[string]interface{}); ok && len(v) > 0 { + authConfig := &batch.EFSAuthorizationConfig{} + if v, ok := v["access_point_id"].(string); ok && v != "" { + authConfig.AccessPointId = aws.String(v) + } + if v, ok := v["iam"].(string); ok && v != "" { + authConfig.Iam = aws.String(v) + } + efs.AuthorizationConfig = authConfig + } + + if v, ok := v["root_directory"].(string); ok && v != "" { + efs.RootDirectory = aws.String(v) + } + if v, ok := v["transit_encryption"].(string); ok && v != "" { + efs.TransitEncryption = aws.String(v) + } + if v, ok := v["transit_encryption_port"].(int); ok { + efs.TransitEncryptionPort = aws.Int64(int64(v)) + } + } + + if v, ok := vol.(map[string]interface{})["host"].(map[string]interface{}); ok && len(v) > 0 { + host := &batch.Host{} + if v, ok := v["source_path"].(string); ok && v != "" { + host.SourcePath = aws.String(v) + } + volume.Host = host + } + if v, ok := vol.(map[string]interface{})["name"].(string); ok && v != "" { + volume.Name = aws.String(v) + } + } + + taskProps.Volumes = volumes + } + + return taskProps +} + +func flattenECSProperties(ecsProperties *batch.EcsProperties) []interface{} { + var ecsPropertiesList []interface{} + if ecsProperties == nil { + return ecsPropertiesList + } + if v := ecsProperties.TaskProperties; v != nil { + ecsPropertiesList = append(ecsPropertiesList, map[string]interface{}{ + "task_properties": flattenECSTaskProperties(v[0]), + }) + } + return ecsPropertiesList +} + +func flattenECSTaskProperties(taskProperties *batch.EcsTaskProperties) (tfList []interface{}) { + tfMap := make(map[string]interface{}, 0) + + if v := taskProperties.Containers; v != nil { + tfMap["containers"] = flattenEcsTaskContainers(v) + } + + if v := taskProperties.EphemeralStorage; v != nil { + ephemeralMap := make(map[string]interface{}, 0) + if v := taskProperties.EphemeralStorage.SizeInGiB; v != nil { + ephemeralMap["size_in_gib"] = aws.Int64Value(v) + } + tfMap["ephemeral_storage"] = []interface{}{ephemeralMap} + } + + if v := taskProperties.ExecutionRoleArn; v != nil { + tfMap["execution_role_arn"] = aws.StringValue(v) + } + + if v := taskProperties.IpcMode; v != nil { + tfMap["ipc_mode"] = aws.StringValue(v) + } + + if v := taskProperties.NetworkConfiguration; v != nil { + networkMap := make(map[string]interface{}, 0) + if v := taskProperties.NetworkConfiguration.AssignPublicIp; v != nil { + networkMap["assign_public_ip"] = aws.StringValue(v) + } + tfMap["network_configuration"] = []interface{}{networkMap} + } + + if v := taskProperties.PidMode; v != nil { + tfMap["pid_mode"] = aws.StringValue(v) + } + + if v := taskProperties.PlatformVersion; v != nil { + tfMap["platform_version"] = aws.StringValue(v) + } + + if v := taskProperties.RuntimePlatform; v != nil { + runtimeMap := make(map[string]interface{}, 0) + if v := taskProperties.RuntimePlatform.CpuArchitecture; v != nil { + runtimeMap["cpu_architecture"] = aws.StringValue(v) + } + if v := taskProperties.RuntimePlatform.OperatingSystemFamily; v != nil { + runtimeMap["operation_system_family"] = aws.StringValue(v) + } + tfMap["runtime_platform"] = []interface{}{runtimeMap} + } + + if v := taskProperties.TaskRoleArn; v != nil { + tfMap["task_role_arn"] = aws.StringValue(v) + } + + if v := taskProperties.Volumes; v != nil { + tfMap["volumes"] = flattenEcsTaskVolumes(v) + } + + return append(tfList, tfMap) +} + +func flattenEcsTaskContainers(containers []*batch.TaskContainerProperties) (tfList []interface{}) { + for _, container := range containers { + tfMap := make(map[string]interface{}, 0) + + if v := container.Image; v != nil { + tfMap["image"] = aws.StringValue(v) + } + + if v := container.Command; v != nil { + tfMap["command"] = flex.FlattenStringList(v) + } + + if v := container.DependsOn; v != nil { + tfList := make([]interface{}, 0) + for _, dep := range v { + depMap := make(map[string]interface{}, 0) + if v := dep.Condition; v != nil { + depMap["condition"] = aws.StringValue(v) + } + if v := dep.ContainerName; v != nil { + depMap["container_name"] = aws.StringValue(v) + } + tfList = append(tfList, depMap) + } + tfMap["depends_on"] = tfList + } + + if v := container.Environment; v != nil { + tfList := make([]interface{}, 0) + for _, env := range v { + envMap := make(map[string]interface{}, 0) + if v := env.Name; v != nil { + envMap["name"] = aws.StringValue(v) + } + if v := env.Value; v != nil { + envMap["value"] = aws.StringValue(v) + } + tfList = append(tfList, envMap) + } + tfMap["environment"] = tfList + } + + if v := container.Essential; v != nil { + tfMap["essential"] = aws.BoolValue(v) + } + + if v := container.LinuxParameters; v != nil { + linuxMap := make(map[string]interface{}, 0) + + if v := v.Devices; v != nil { + tfList := make([]interface{}, 0) + for _, dev := range v { + devMap := make(map[string]interface{}, 0) + if v := dev.ContainerPath; v != nil { + devMap["container_path"] = aws.StringValue(v) + } + if v := dev.HostPath; v != nil { + devMap["host_path"] = aws.StringValue(v) + } + if v := dev.Permissions; v != nil { + devMap["permissions"] = flex.FlattenStringList(v) + } + tfList = append(tfList, devMap) + } + linuxMap["devices"] = tfList + } + + if v := v.InitProcessEnabled; v != nil { + linuxMap["init_process_enabled"] = aws.BoolValue(v) + } + + if v := v.MaxSwap; v != nil { + linuxMap["max_swap"] = aws.Int64Value(v) + } + + if v := v.SharedMemorySize; v != nil { + linuxMap["shared_memory_size"] = aws.Int64Value(v) + } + + if v := v.Swappiness; v != nil { + linuxMap["swappiness"] = aws.Int64Value(v) + } + + if v := v.Tmpfs; v != nil { + tfList := make([]interface{}, 0) + for _, tmp := range v { + tmpMap := make(map[string]interface{}, 0) + if v := tmp.ContainerPath; v != nil { + tmpMap["container_path"] = aws.StringValue(v) + } + if v := tmp.Size; v != nil { + tmpMap["size"] = aws.Int64Value(v) + } + if v := tmp.MountOptions; v != nil { + tmpMap["mount_options"] = flex.FlattenStringList(v) + } + tfList = append(tfList, tmpMap) + } + linuxMap["tmpfs"] = tfList + } + + tfMap["linux_parameters"] = linuxMap + } + + if v := container.LogConfiguration; v != nil { + tfList := make([]interface{}, 0) + logMap := make(map[string]interface{}, 0) + if v := v.LogDriver; v != nil { + logMap["log_driver"] = aws.StringValue(v) + } + if v := v.Options; v != nil { + logMap["options"] = v + } + if v := v.SecretOptions; v != nil { + tfList := make([]interface{}, 0) + for _, secret := range v { + secretMap := make(map[string]interface{}, 0) + if v := secret.Name; v != nil { + secretMap["name"] = aws.StringValue(v) + } + if v := secret.ValueFrom; v != nil { + secretMap["value_from"] = aws.StringValue(v) + } + tfList = append(tfList, secretMap) + } + logMap["secret_options"] = tfList + } + tfList = append(tfList, logMap) + tfMap["log_configuration"] = tfList + } + + if v := container.MountPoints; v != nil { + tfList := make([]interface{}, 0) + for _, mp := range v { + mpMap := make(map[string]interface{}, 0) + if v := mp.ContainerPath; v != nil { + mpMap["container_path"] = aws.StringValue(v) + } + if v := mp.ReadOnly; v != nil { + mpMap["read_only"] = aws.BoolValue(v) + } + if v := mp.SourceVolume; v != nil { + mpMap["source_volume"] = aws.StringValue(v) + } + tfList = append(tfList, mpMap) + } + tfMap["mount_points"] = tfList + } + + if v := container.Name; v != nil { + tfMap["name"] = aws.StringValue(v) + } + + if v := container.Privileged; v != nil { + tfMap["privileged"] = aws.BoolValue(v) + } + + if v := container.ReadonlyRootFilesystem; v != nil { + tfMap["readonly_root_filesystem"] = aws.BoolValue(v) + } + + if v := container.RepositoryCredentials; v != nil { + tfList := make([]interface{}, 0) + repoMap := make(map[string]interface{}, 0) + if v := v.CredentialsParameter; v != nil { + repoMap["credentials_parameter"] = aws.StringValue(v) + } + tfList = append(tfList, repoMap) + tfMap["repository_credentials"] = tfList + } + + if v := container.ResourceRequirements; v != nil { + tfList := make([]interface{}, 0) + for _, req := range v { + reqMap := make(map[string]interface{}, 0) + if v := req.Type; v != nil { + reqMap["type"] = aws.StringValue(v) + } + if v := req.Value; v != nil { + reqMap["value"] = aws.StringValue(v) + } + tfList = append(tfList, reqMap) + } + tfMap["resource_requirements"] = tfList + } + + if v := container.Secrets; v != nil { + tfList := make([]interface{}, 0) + for _, secret := range v { + secretMap := make(map[string]interface{}, 0) + if v := secret.Name; v != nil { + secretMap["name"] = aws.StringValue(v) + } + if v := secret.ValueFrom; v != nil { + secretMap["value_from"] = aws.StringValue(v) + } + tfList = append(tfList, secretMap) + } + tfMap["secrets"] = tfList + } + + if v := container.Ulimits; v != nil { + tfList := make([]interface{}, 0) + for _, ulimit := range v { + ulimitMap := make(map[string]interface{}, 0) + if v := ulimit.HardLimit; v != nil { + ulimitMap["hard_limit"] = aws.Int64Value(v) + } + if v := ulimit.Name; v != nil { + ulimitMap["name"] = aws.StringValue(v) + } + if v := ulimit.SoftLimit; v != nil { + ulimitMap["soft_limit"] = aws.Int64Value(v) + } + tfList = append(tfList, ulimitMap) + } + tfMap["ulimits"] = tfList + } + + if v := container.User; v != nil { + tfMap["user"] = aws.StringValue(v) + } + + tfList = append(tfList, tfMap) + } + + return tfList +} + +func expandEcsTaskContainers(containers []interface{}) []*batch.TaskContainerProperties { + var result []*batch.TaskContainerProperties + + for _, v := range containers { + containerMap := v.(map[string]interface{}) + container := &batch.TaskContainerProperties{} + + if v, ok := containerMap["image"]; ok { + container.Image = aws.String(v.(string)) + } + + if v, ok := containerMap["command"]; ok { + container.Command = flex.ExpandStringList(v.([]interface{})) + } + + if v, ok := containerMap["depends_on"].(*schema.Set); ok && v.Len() > 0 { + deps := []*batch.TaskContainerDependency{} + for _, d := range v.List() { + dep := &batch.TaskContainerDependency{} + if v, ok := d.(map[string]interface{})["condition"].(string); ok && v != "" { + dep.Condition = aws.String(v) + } + if v, ok := d.(map[string]interface{})["container_name"].(string); ok && v != "" { + dep.ContainerName = aws.String(v) + } + deps = append(deps, dep) + } + container.DependsOn = deps + } + + if v, ok := containerMap["environment"].(*schema.Set); ok && v.Len() > 0 { + envs := []*batch.KeyValuePair{} + for _, e := range v.List() { + env := &batch.KeyValuePair{} + if v, ok := e.(map[string]interface{})["name"].(string); ok && v != "" { + env.Name = aws.String(v) + } + if v, ok := e.(map[string]interface{})["value"].(string); ok && v != "" { + env.Value = aws.String(v) + } + envs = append(envs, env) + } + container.Environment = envs + } + + if v, ok := containerMap["essential"]; ok { + container.Essential = aws.Bool(v.(bool)) + } + + if v, ok := containerMap["linux_parameters"].(map[string]interface{}); ok { + param := &batch.LinuxParameters{} + + if v, ok := v["devices"].(*schema.Set); ok && v.Len() > 0 { + devices := []*batch.Device{} + for _, d := range v.List() { + device := &batch.Device{} + if v, ok := d.(map[string]interface{})["container_path"].(string); ok && v != "" { + device.ContainerPath = aws.String(v) + } + if v, ok := d.(map[string]interface{})["host_path"].(string); ok && v != "" { + device.HostPath = aws.String(v) + } + if v, ok := d.(map[string]interface{})["permissions"].(*schema.Set); ok && v.Len() > 0 { + permissions := []*string{} + for _, p := range v.List() { + permissions = append(permissions, aws.String(p.(string))) + } + device.Permissions = permissions + } + devices = append(devices, device) + } + param.Devices = devices + } + + if v, ok := v["init_process_enabled"].(bool); ok { + param.InitProcessEnabled = aws.Bool(v) + } + + if v, ok := v["max_swap"].(int); ok { + param.MaxSwap = aws.Int64(int64(v)) + } + + if v, ok := v["shared_memory_size"].(int); ok { + param.SharedMemorySize = aws.Int64(int64(v)) + } + + if v, ok := v["swappiness"].(int); ok { + param.Swappiness = aws.Int64(int64(v)) + } + + if v, ok := v["tmpfs"].(*schema.Set); ok && v.Len() > 0 { + tmpfs := []*batch.Tmpfs{} + for _, t := range v.List() { + tmp := &batch.Tmpfs{} + if v, ok := t.(map[string]interface{})["container_path"].(string); ok && v != "" { + tmp.ContainerPath = aws.String(v) + } + if v, ok := t.(map[string]interface{})["size"].(int); ok { + tmp.Size = aws.Int64(int64(v)) + } + if v, ok := t.(map[string]interface{})["mount_options"]; ok { + tmp.MountOptions = flex.ExpandStringList(v.([]interface{})) + } + tmpfs = append(tmpfs, tmp) + } + param.Tmpfs = tmpfs + } + + container.LinuxParameters = param + } + + if v, ok := containerMap["log_configuration"].([]interface{}); ok && len(v) > 0 { + logConfig := &batch.LogConfiguration{} + + raw := v[0].(map[string]interface{}) + + if v, ok := raw["log_driver"].(string); ok && v != "" { + logConfig.LogDriver = aws.String(v) + } + if v, ok := raw["options"].(map[string]interface{}); ok && len(v) > 0 { + logConfig.Options = flex.ExpandStringMap(v) + } + + if v, ok := raw["secret_options"].([]interface{}); ok && len(v) > 0 { + secretOptions := []*batch.Secret{} + for _, s := range v { + secret := &batch.Secret{} + if v, ok := s.(map[string]interface{})["name"].(string); ok && v != "" { + secret.Name = aws.String(v) + } + if v, ok := s.(map[string]interface{})["value_from"].(string); ok && v != "" { + secret.ValueFrom = aws.String(v) + } + secretOptions = append(secretOptions, secret) + } + logConfig.SecretOptions = secretOptions + } + + container.LogConfiguration = logConfig + } + + if v, ok := containerMap["mount_points"].(*schema.Set); ok && v.Len() > 0 { + mountPoints := []*batch.MountPoint{} + for _, mp := range v.List() { + mountPoint := &batch.MountPoint{} + if v, ok := mp.(map[string]interface{})["container_path"].(string); ok && v != "" { + mountPoint.ContainerPath = aws.String(v) + } + if v, ok := mp.(map[string]interface{})["read_only"].(bool); ok { + mountPoint.ReadOnly = aws.Bool(v) + } + if v, ok := mp.(map[string]interface{})["source_volume"].(string); ok && v != "" { + mountPoint.SourceVolume = aws.String(v) + } + mountPoints = append(mountPoints, mountPoint) + } + container.MountPoints = mountPoints + } + + if v, ok := containerMap["name"]; ok && v != "" { + container.Name = aws.String(v.(string)) + } + + if v, ok := containerMap["privileged"].(bool); ok { + container.Privileged = aws.Bool(v) + } + + if v, ok := containerMap["readonly_root_filesystem"].(bool); ok { + container.ReadonlyRootFilesystem = aws.Bool(v) + } + + if v, ok := containerMap["repository_credentials"].([]interface{}); ok && len(v) > 0 { + repoCreds := &batch.RepositoryCredentials{} + if v, ok := v[0].(map[string]interface{})["credentials_parameter"].(string); ok && v != "" { + repoCreds.CredentialsParameter = aws.String(v) + } + container.RepositoryCredentials = repoCreds + } + + if v, ok := containerMap["resource_requirements"].(*schema.Set); ok && v.Len() > 0 { + resources := []*batch.ResourceRequirement{} + for _, r := range v.List() { + resource := &batch.ResourceRequirement{} + if v, ok := r.(map[string]interface{})["type"].(string); ok && v != "" { + resource.Type = aws.String(v) + } + if v, ok := r.(map[string]interface{})["value"].(string); ok && v != "" { + resource.Value = aws.String(v) + } + resources = append(resources, resource) + } + container.ResourceRequirements = resources + } + + if v, ok := containerMap["secrets"].(*schema.Set); ok && v.Len() > 0 { + secrets := []*batch.Secret{} + for _, s := range v.List() { + secret := &batch.Secret{} + if v, ok := s.(map[string]interface{})["name"].(string); ok && v != "" { + secret.Name = aws.String(v) + } + if v, ok := s.(map[string]interface{})["value_from"].(string); ok && v != "" { + secret.ValueFrom = aws.String(v) + } + secrets = append(secrets, secret) + } + container.Secrets = secrets + } + + if v, ok := containerMap["ulimits"].(*schema.Set); ok && v.Len() > 0 { + ulimits := []*batch.Ulimit{} + for _, u := range v.List() { + ulimit := &batch.Ulimit{} + if v, ok := u.(map[string]interface{})["hard_limit"].(int); ok { + ulimit.HardLimit = aws.Int64(int64(v)) + } + if v, ok := u.(map[string]interface{})["name"].(string); ok && v != "" { + ulimit.Name = aws.String(v) + } + if v, ok := u.(map[string]interface{})["soft_limit"].(int); ok { + ulimit.SoftLimit = aws.Int64(int64(v)) + } + ulimits = append(ulimits, ulimit) + } + container.Ulimits = ulimits + } + + if v, ok := containerMap["user"].(string); ok && v != "" { + container.User = aws.String(v) + } + + result = append(result, container) + } + + return result +} + +func flattenEcsTaskVolumes(volumes []*batch.Volume) (tfList []interface{}) { + for _, volume := range volumes { + tfMap := make(map[string]interface{}, 0) + + if v := volume.EfsVolumeConfiguration; v != nil { + efsMap := make(map[string]interface{}, 0) + if v := volume.EfsVolumeConfiguration.FileSystemId; v != nil { + efsMap["file_system_id"] = aws.StringValue(v) + } + + if v := volume.EfsVolumeConfiguration.AuthorizationConfig; v != nil { + authMap := make(map[string]interface{}, 0) + if v := volume.EfsVolumeConfiguration.AuthorizationConfig.AccessPointId; v != nil { + authMap["access_point_id"] = aws.StringValue(v) + } + if v := volume.EfsVolumeConfiguration.AuthorizationConfig.Iam; v != nil { + authMap["iam"] = aws.StringValue(v) + } + efsMap["authorization_config"] = authMap + } + + if v := volume.EfsVolumeConfiguration.RootDirectory; v != nil { + efsMap["root_directory"] = aws.StringValue(v) + } + if v := volume.EfsVolumeConfiguration.TransitEncryption; v != nil { + efsMap["transit_encryption"] = aws.StringValue(v) + } + + if v := volume.EfsVolumeConfiguration.TransitEncryptionPort; v != nil { + efsMap["transit_encryption_port"] = aws.Int64Value(v) + } + tfMap["efs_volume_configuration"] = efsMap + } + + if v := volume.Host; v != nil { + hostMap := make(map[string]interface{}, 0) + if v := volume.Host.SourcePath; v != nil { + hostMap["source_path"] = aws.StringValue(v) + } + tfMap["host"] = hostMap + } + + if v := volume.Name; v != nil { + tfMap["name"] = aws.StringValue(v) + } + + tfList = append(tfList, tfMap) + } + + return tfList +} diff --git a/internal/service/batch/job_definition.go b/internal/service/batch/job_definition.go index b9ca6438358..1cbc214d7a8 100644 --- a/internal/service/batch/job_definition.go +++ b/internal/service/batch/job_definition.go @@ -60,7 +60,7 @@ func ResourceJobDefinition() *schema.Resource { "container_properties": { Type: schema.TypeString, Optional: true, - ConflictsWith: []string{"eks_properties", "node_properties"}, + ConflictsWith: []string{"eks_properties", "ecs_properties", "node_properties"}, StateFunc: func(v interface{}) string { json, _ := structure.NormalizeJsonString(v) return json @@ -89,7 +89,7 @@ func ResourceJobDefinition() *schema.Resource { "node_properties": { Type: schema.TypeString, Optional: true, - ConflictsWith: []string{"container_properties", "eks_properties"}, + ConflictsWith: []string{"container_properties", "eks_properties", "ecs_properties"}, StateFunc: func(v interface{}) string { json, _ := structure.NormalizeJsonString(v) return json @@ -105,7 +105,7 @@ func ResourceJobDefinition() *schema.Resource { Type: schema.TypeList, MaxItems: 1, Optional: true, - ConflictsWith: []string{"container_properties", "node_properties"}, + ConflictsWith: []string{"container_properties", "node_properties", "ecs_properties"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "pod_properties": { @@ -327,6 +327,414 @@ func ResourceJobDefinition() *schema.Resource { }, }, + "ecs_properties": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + ConflictsWith: []string{"container_properties", "node_properties", "eks_properties"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "task_properties": { + Type: schema.TypeList, + MaxItems: 1, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "containers": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "image": { + Type: schema.TypeString, + Required: true, + }, + "command": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "depends_on": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "condition": { + Type: schema.TypeString, + Optional: true, + }, + "container_name": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "environment": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "essential": { + Type: schema.TypeBool, + Optional: true, + }, + "linux_parameters": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "devices": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "host_path": { + Type: schema.TypeString, + Required: true, + }, + "container_path": { + Type: schema.TypeString, + Required: true, + }, + "permissions": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "init_process_enabled": { + Type: schema.TypeBool, + Optional: true, + }, + "max_swap": { + Type: schema.TypeInt, + Optional: true, + }, + "shared_memory_size": { + Type: schema.TypeInt, + Optional: true, + }, + "swappiness": { + Type: schema.TypeInt, + Optional: true, + }, + "tmpfs": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "container_path": { + Type: schema.TypeString, + Required: true, + }, + "size": { + Type: schema.TypeInt, + Required: true, + }, + "mount_options": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + }, + }, + "log_configuration": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "log_driver": { + Type: schema.TypeString, + Required: true, + }, + "options": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "secret_options": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "value_from": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + }, + }, + "mount_points": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "container_path": { + Type: schema.TypeString, + Optional: true, + }, + "read_only": { + Type: schema.TypeBool, + Optional: true, + }, + "source_volume": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + "privileged": { + Type: schema.TypeBool, + Optional: true, + }, + "readonly_root_filesystem": { + Type: schema.TypeBool, + Optional: true, + }, + "repository_credentials": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "credentials_parameter": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "resource_requirements": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "secrets": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "value_from": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "ulimits": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hard_limit": { + Type: schema.TypeInt, + Required: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + }, + "soft_limit": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + "user": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "ephemeral_storage": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "size_in_gib": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + "execution_role_arn": { + Type: schema.TypeString, + Optional: true, + }, + "ipc_mode": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(IpcMode_Values(), false), + }, + "network_configuration": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "assign_public_ip": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "pid_mode": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(PidMode_Values(), false), + }, + "platform_version": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "runtime_platform": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cpu_architecture": { + Type: schema.TypeString, + Optional: true, + }, + "operating_system_family": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "task_role_arn": { + Type: schema.TypeString, + Optional: true, + }, + "volumes": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "efs_volume_configuration": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "file_system_id": { + Type: schema.TypeString, + Required: true, + }, + "authorization_config": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "access_point_id": { + Type: schema.TypeString, + Optional: true, + }, + "iam": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "root_directory": { + Type: schema.TypeString, + Optional: true, + }, + "transit_encryption": { + Type: schema.TypeString, + Optional: true, + }, + "transit_encryption_port": { + Type: schema.TypeInt, + Optional: true, + }, + }, + }, + }, + "host": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "source_path": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + names.AttrParameters: { Type: schema.TypeMap, Optional: true, @@ -521,6 +929,34 @@ func needsJobDefUpdate(d *schema.ResourceDiff) bool { return !reflect.DeepEqual(oeks, neks) } + if d.HasChange("ecs_properties") { + o, n := d.GetChange("ecs_properties") + if len(o.([]interface{})) == 0 && len(n.([]interface{})) == 0 { + return false + } + + if d.Get(names.AttrType).(string) != batch.JobDefinitionTypeContainer { + return false + } + + var oecs, necs *batch.EcsTaskProperties + if len(o.([]interface{})) > 0 { + oProps := o.([]interface{})[0].(map[string]interface{}) + if otaskProps, ok := oProps["task_properties"].([]interface{}); ok && len(otaskProps) > 0 { + oecs = expandECSTaskProperties(otaskProps[0].(map[string]interface{})) + } + } + + if len(n.([]interface{})) > 0 { + nProps := n.([]interface{})[0].(map[string]interface{}) + if ntaskProps, ok := nProps["task_properties"].([]interface{}); ok && len(ntaskProps) > 0 { + necs = expandECSTaskProperties(ntaskProps[0].(map[string]interface{})) + } + } + + return !reflect.DeepEqual(oecs, necs) + } + if d.HasChange("retry_strategy") { o, n := d.GetChange("retry_strategy") if len(o.([]interface{})) == 0 && len(n.([]interface{})) == 0 { @@ -615,6 +1051,20 @@ func resourceJobDefinitionCreate(ctx context.Context, d *schema.ResourceData, me } } } + + if v, ok := d.GetOk("ecs_properties"); ok && len(v.([]interface{})) > 0 { + ecsProps := v.([]interface{})[0].(map[string]interface{}) + if taskProps, ok := ecsProps["task_properties"].([]interface{}); ok && len(taskProps) > 0 { + if aws.StringValue(input.Type) == batch.JobDefinitionTypeContainer { + props := expandECSTaskProperties(taskProps[0].(map[string]interface{})) + input.EcsProperties = &batch.EcsProperties{ + TaskProperties: []*batch.EcsTaskProperties{ + props, + }, + } + } + } + } } if jobDefinitionType == batch.JobDefinitionTypeMultinode { @@ -624,6 +1074,9 @@ func resourceJobDefinitionCreate(ctx context.Context, d *schema.ResourceData, me if v, ok := d.GetOk("eks_properties"); ok && v != nil { return sdkdiag.AppendErrorf(diags, "No `eks_properties` can be specified when `type` is %q", jobDefinitionType) } + if v, ok := d.GetOk("ecs_properties"); ok && v != nil { + return sdkdiag.AppendErrorf(diags, "No `ecs_properties` can be specified when `type` is %q", jobDefinitionType) + } if v, ok := d.GetOk("node_properties"); ok { props, err := expandJobNodeProperties(v.(string)) @@ -703,6 +1156,10 @@ func resourceJobDefinitionRead(ctx context.Context, d *schema.ResourceData, meta return sdkdiag.AppendErrorf(diags, "setting eks_properties: %s", err) } + if err := d.Set("ecs_properties", flattenECSProperties(jobDefinition.EcsProperties)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting ecs_properties: %s", err) + } + d.Set(names.AttrName, jobDefinition.JobDefinitionName) nodeProperties, err := flattenNodeProperties(jobDefinition.NodeProperties) @@ -778,6 +1235,18 @@ func resourceJobDefinitionUpdate(ctx context.Context, d *schema.ResourceData, me } } + if v, ok := d.GetOk("ecs_properties"); ok { + ecsProps := v.([]interface{})[0].(map[string]interface{}) + if taskProps, ok := ecsProps["task_properties"].([]interface{}); ok && len(taskProps) > 0 { + props := expandECSTaskProperties(taskProps[0].(map[string]interface{})) + input.EcsProperties = &batch.EcsProperties{ + TaskProperties: []*batch.EcsTaskProperties{ + props, + }, + } + } + } + if v, ok := d.GetOk("node_properties"); ok { props, err := expandJobNodeProperties(v.(string)) if err != nil { diff --git a/internal/service/batch/job_definition_test.go b/internal/service/batch/job_definition_test.go index 972a9a8d063..668fb24c8a1 100644 --- a/internal/service/batch/job_definition_test.go +++ b/internal/service/batch/job_definition_test.go @@ -842,6 +842,82 @@ func TestAccBatchJobDefinition_EKSProperties_update(t *testing.T) { }) } +func TestAccBatchJobDefinition_ECSProperties_basic(t *testing.T) { + ctx := acctest.Context(t) + var jd batch.JobDefinition + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_batch_job_definition.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.BatchServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckJobDefinitionDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccJobDefinitionConfig_ECSProperties_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckJobDefinitionExists(ctx, resourceName, &jd), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.#", "1"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.image", "public.ecr.aws/amazonlinux/amazonlinux:1"), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), + resource.TestCheckResourceAttr(resourceName, names.AttrType, "container"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "deregister_on_new_revision", + }, + }, + }, + }) +} + +func TestAccBatchJobDefinition_ECSProperties_update(t *testing.T) { + ctx := acctest.Context(t) + var jd batch.JobDefinition + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_batch_job_definition.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.BatchServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckJobDefinitionDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccJobDefinitionConfig_ECSProperties_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckJobDefinitionExists(ctx, resourceName, &jd), + ), + }, + { + Config: testAccJobDefinitionConfig_ECSProperties_advancedUpdate(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckJobDefinitionExists(ctx, resourceName, &jd), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.#", "1"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.environment.#", "1"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.environment.0.name", "test"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.environment.0.value", "Environment Variable"), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), + resource.TestCheckResourceAttr(resourceName, names.AttrType, "container"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "deregister_on_new_revision", + }, + }, + }, + }) +} + func TestAccBatchJobDefinition_createTypeContainerWithNodeProperties(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -1680,6 +1756,126 @@ resource "aws_batch_job_definition" "test" { `, rName) } +func testAccJobDefinitionConfig_ECSProperties_basic(rName string) string { + return fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_iam_role" "ecs_task_execution_role" { + name = %[1]q + assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json +} + +data "aws_iam_policy_document" "assume_role_policy" { + statement { + actions = ["sts:AssumeRole"] + + principals { + type = "Service" + identifiers = ["ecs-tasks.amazonaws.com"] + } + } +} + +resource "aws_iam_role_policy_attachment" "ecs_task_execution_role_policy" { + role = aws_iam_role.ecs_task_execution_role.name + policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" +} + +resource "aws_batch_job_definition" "test" { + name = %[1]q + type = "container" + platform_capabilities = ["FARGATE"] + ecs_properties { + task_properties { + execution_role_arn = aws_iam_role.ecs_task_execution_role.arn + containers { + essential = true + image = "public.ecr.aws/amazonlinux/amazonlinux:1" + command = [ + "sleep", + "60" + ] + resource_requirements { + value = "1.0" + type = "VCPU" + } + resource_requirements { + value = "2048" + type = "MEMORY" + } + log_configuration { + log_driver = "awslogs" + options = { + awslogs-group = %[1]q + awslogs-region = "ap-northeast-1" + awslogs-stream-prefix = "ecs" + } + } + } + } + } +} +`, rName) +} + +func testAccJobDefinitionConfig_ECSProperties_advancedUpdate(rName string) string { + return fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_iam_role" "ecs_task_execution_role" { + name = %[1]q + assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json +} + +data "aws_iam_policy_document" "assume_role_policy" { + statement { + actions = ["sts:AssumeRole"] + + principals { + type = "Service" + identifiers = ["ecs-tasks.amazonaws.com"] + } + } +} + +resource "aws_iam_role_policy_attachment" "ecs_task_execution_role_policy" { + role = aws_iam_role.ecs_task_execution_role.name + policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" +} + +resource "aws_batch_job_definition" "test" { + name = %[1]q + type = "container" + platform_capabilities = ["FARGATE"] + ecs_properties { + task_properties { + execution_role_arn = aws_iam_role.ecs_task_execution_role.arn + containers { + essential = true + image = "public.ecr.aws/amazonlinux/amazonlinux:1" + command = [ + "sleep", + "60" + ] + resource_requirements { + value = "1.0" + type = "VCPU" + } + resource_requirements { + value = "2048" + type = "MEMORY" + } + environment { + name = "test" + value = "Environment Variable" + } + } + } + } +} +`, rName) +} + func testAccJobDefinitionConfig_createTypeContainerWithNodeProperties(rName string) string { return fmt.Sprintf(` resource "aws_batch_job_definition" "test" { From 7f0c036ab1608745870c47dc13f01002ef407274 Mon Sep 17 00:00:00 2001 From: Ryo Takaishi Date: Thu, 6 Jun 2024 17:28:56 +0900 Subject: [PATCH 02/26] update doc --- .../docs/r/batch_job_definition.html.markdown | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) diff --git a/website/docs/r/batch_job_definition.html.markdown b/website/docs/r/batch_job_definition.html.markdown index cc2af1d03a4..d76c37a517f 100644 --- a/website/docs/r/batch_job_definition.html.markdown +++ b/website/docs/r/batch_job_definition.html.markdown @@ -134,6 +134,40 @@ resource "aws_batch_job_definition" "test" { } ``` +### Job Definitionn of type EKS + +```terraform +resource "aws_batch_job_definition" "test" { + name = " tf_test_batch_job_definition_ecs" + type = "container" + ecs_properties { + task_properties { + host_network = true + containers { + essential = true + image = "public.ecr.aws/amazonlinux/amazonlinux:1" + command = [ + "sleep", + "60" + ] + resource_requirements { + value = "1.0" + type = "VCPU" + } + resource_requirements { + value = "2048" + type = "MEMORY" + } + environment { + name = "test" + value = "Environment Variable" + } + } + } + } +} +``` + ### Fargate Platform Capability ```terraform @@ -256,6 +290,146 @@ The following arguments are optional: * `secret_name` - The name of the secret. The name must be allowed as a DNS subdomain name. * `optional` - (Optional) Specifies whether the secret or the secret's keys must be defined. +### `ecs_properties` + +* `task_properties` - The properties of the Amazon ECS task definition on a job. See [`task_properties`](#task_properties) below. + +### `task_properties` + +* `containers` - The properties of the container. See [containers](#ecs_containers) below. +* `ephemeral_storage` - (Optional) The ephemeral storage settings for the task. See [ephemeral_storage](#ephemeral_storage) below. +* `execution_role_arn` - (Optional) The Amazon Resource Name (ARN) of the IAM role that the AWS Batch can assume. +* `ipc_mode` - (Optional) The IPC resource namespace to use for container in the task. The valid values are `host`, `task`, or `none`. +* `network_configuration` - (Optional) The network configuration for the Amazon ECS task. See [network_configuration](#network_configuration) below. +* `pic_mode` - (Optional) The process namespace to use for the container in the task. The valid values are `host` or `task`. +* `platform_version` - (Optional) The platform version on which to run your task. If one is not specified, the LATEST platform version is used by default. +* `runtime_platform` - (Optional) The compute environment architecture for AWS Batch job on Fargate. See [runtime_platform](#runtime_platform) below. +* `task_role_arn` - The Amazon Resource Name (ARN) of the IAM role that the Amazon ECS task.. +* `volume` - (Optional) The volumes to mount on the container in the task. See [volume](#volume) below. + +### `containers` + +* `image` - The image used to start the container. +* `command` - (Optional) The command that's passed to the container. +* `depends_on` - (Optional) The properties of containers that this container depends on. See [depends_on](#depends_on) below. +* `environment` - (Optional) The environment variables to pass to a container. See [environment](#environment) below. +* `essential` - (Optional) The parameter this container is essential or not. +* `linux_parameters` - (Optional) Linux-specific modifications that are applied to the container. See [linux_parameters](#linux_parameters) below. +* `log_configuration` - (Optional) The log configuration specification for the container. See [log_configuration](#log_configuration) below. +* `mount_points` - (Optional) The mount points for data volumes in your container. See [mount_points](#mount_points) below. +* `name` - (Optional) The name of the container. +* `privileged` - (Optional) When this parameter is true, the container is given elevated privileges on the host container instance. +* `readonly_root_filesystem` - (Optional) When this parameter is true, the container is given read-only access to its root file system. +* `repository_credentials` - (Optional) The private repository authentication credentials to use. See [repository_credentials](#repository_credentials) below. +* `resource_requirements` - (Optional) The type and amount of resources to assign to a container. The supported resources include `GPU`, `MEMORY`, and `VCPU`. See [resource_requirements](#resource_requirements) below. +* `secrets` - (Optional) The secrets to pass to the container. See [secrets](#secrets) below. +* `ulimits` - (Optional) A list of `ulimits` to set in the container. This parameter maps to `Ulimits` in the Create a container section of the Docker Remote API and the --ulimit option to docker run. See [ulimits](#ulimits) below. +* `user` - (Optional) The user to use inside the container. This parameter maps to User in the Create a container section of the Docker Remote API and the --user option to docker run. + +### `depends_on` + +* `container_name` - The name of a container in the task definition to depend on. +* `condition` - The dependency condition of the dependent container. The valid values are `START`, `COMPLETE`, `SUCCESS`, and `HEALTHY`. + +### `environment` + +* `name` - The name of the environment variable. +* `value` - The value of the environment variable. + +### `linux_parameters` + +* `devices` - (Optional) Any host devices to expose to the container. This parameter maps to Devices in the Create a container section of the Docker Remote API and the --device option to docker run. See [devices](#devices) below. +* `init_process_enabled` - (Optional) Whether the init process is enabled in the container. This parameter maps to `init` in the Create a container section of the Docker Remote API and the --init option to docker run. +* `max_swap` - (Optional) The total amount of swap memory (in MiB) a container can use. This parameter will be translated to the --memory-swap option to docker run where the value would be the sum of the container memory plus the maxSwap value. +* `shared_memory_size` - (Optional) The value for the size (in MiB) of the `/dev/shm` volume. This parameter maps to `ShmSize` in the Create a container section of the Docker Remote API and the --shm-size option to docker run. +* `swappiness` - (Optional) This allows you to tune a container's memory swappiness behavior. A swappiness value is a percentage from `0` to `100`. +* `tmpfs` - (Optional) The container path, mount options, and size (in MiB) of a tmpfs mount. This parameter maps to `Tmpfs` in the Create a container section of the Docker Remote API and the --tmpfs option to docker run. See [tmpfs](#tmpfs) below. + +### `devices` + +* `host_path` - The path for the device on the host. +* `container_path` - The path inside the container at which to expose the host device. +* `permissions` - The explicit permissions to provide to the container for the device. By default, the container has permissions for `read`, `write`, and `mknod` for the device. + +### `tmpfs` + +* `container_path` - The absolute file path in the container where the tmpfs volume is mounted. +* `size` - The size (in MiB) of the tmpfs volume. +* `mount_options` - (Optional) The list of tmpfs volume mount options. + +### `log_configuration` + +* `log_driver` - The log driver to use for the container. The valid values listed for this parameter are log drivers that the Amazon ECS container agent can communicate with by default. +* `options` - The configuration options to send to the log driver. This parameter requires a map of key-value pairs. +* `secret_options` - The secrets to pass to the log configuration. See [secret_options](#secret_options) below. + +### `secret_options` + +* `name` - The name of the secret. +* `value_from` - The value to assign to the secret. + +### `mount_points` + +* `container_path` - The path in the container at which to mount the host volume. +* `read_only` - If this value is `true`, the container has read-only access to the volume. If this value is `false`, then the container can write to the volume. The default value is `false`. +* `source_volume` - The name of the volume to mount. + +### `repository_credentials` + +* `credentials_parameter` - The Amazon Resource Name (ARN) or name of the secret in Secrets Manager that stores the private repository authentication credentials. + +### `resource_requirements` + +* `type` - The type of resource to assign to a container. The supported resources include `GPU`, `MEMORY`, and `VCPU`. +* `value` - The value for the specified resource type. + +### `secrets` + +* `name` - The name of the secret. +* `value_from` - The value to assign to the secret. + +### `ulimits` + +* `hard_limit` - The hard limit for the ulimit type. +* `name` - The type of the ulimit. For valid values, see the [ulimit](https://docs.docker.com/engine/reference/run/#ulimit) documentation. +* `soft_limit` - The soft limit for the ulimit type. + +### `ephemeral_storage` + +* `size_in_gib` - The size (in GiB) of the ephemeral storage volume. + +### `network_configuration` + +* `assign_public_ip` - (Optional) Assign a public IP address to the Amazon ECS task. The default value is `DISABLED`. + +### `runtime_platform` + +* `cpu_architecture` - The CPU architecture to use for the task. The valid values are `X86_64` and `ARM64`. +* `operating_system_family` - The operating system family to use for the task. The valid values are `LINUX` and `WINDOWS`. + +### `volume` + +* `efs_volume_configuration` - (Optional) The Amazon Elastic File System (Amazon EFS) volume configuration to use for the Amazon ECS task. See [efs_volume_configuration](#efs_volume_configuration) below. +* `host` - (Optional) The host volume configuration to use for the Amazon ECS task. See [host](#host) below. +* `name` - The name of the volume. + +### `efs_volume_configuration` + +* `file_system_id` - The Amazon EFS file system ID to use. +* `authorization_config` - (Optional) The authorization configuration details for the Amazon EFS file system. See [authorization_config](#authorization_config) below. +* `root_directory` - (Optional) The root directory to mount to the Amazon ECS task. +* `transit_encryption` - (Optional) Whether to enable encryption for Amazon EFS data in transit between the Amazon ECS host and the Amazon EFS server. The default value is `ENABLED`. +* `transit_encryption_port` - (Optional) The port to use when sending encrypted data between the Amazon ECS host and the Amazon EFS server. The default value is `PORT_443`. + +### `authorization_config` + +* `access_point_id` - The Amazon EFS access point ID to use. +* `iam` - The Amazon EFS authorization method to use. + +### `host` + +* `source_path` - The path on the host container instance that's presented to the container. If this parameter is empty, then the Docker daemon has assigned a host path for you. + ### `retry_strategy` * `attempts` - (Optional) The number of times to move a job to the `RUNNABLE` status. You may specify between `1` and `10` attempts. From 4fab4ef7cbf44343dad3f394a0759becd53e5a40 Mon Sep 17 00:00:00 2001 From: Ryo Takaishi Date: Fri, 7 Jun 2024 14:32:03 +0900 Subject: [PATCH 03/26] updated go.mod # Conflicts: # tools/tfsdk2fw/go.mod # tools/tfsdk2fw/go.sum --- tools/tfsdk2fw/go.mod | 20 ++++++++++---------- tools/tfsdk2fw/go.sum | 10 ++++++++++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/tools/tfsdk2fw/go.mod b/tools/tfsdk2fw/go.mod index f6e8ddfa40b..2d691f2df00 100644 --- a/tools/tfsdk2fw/go.mod +++ b/tools/tfsdk2fw/go.mod @@ -18,13 +18,13 @@ require ( github.com/agext/levenshtein v1.2.3 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/armon/go-radix v1.0.0 // indirect - github.com/aws/aws-sdk-go v1.53.15 // indirect + github.com/aws/aws-sdk-go v1.53.18 // indirect github.com/aws/aws-sdk-go-v2 v1.27.1 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 // indirect github.com/aws/aws-sdk-go-v2/config v1.27.17 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.17 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.4 // indirect - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.22 // indirect + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.23 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.8 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.8 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect @@ -57,7 +57,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/chimesdkmediapipelines v1.15.10 // indirect github.com/aws/aws-sdk-go-v2/service/chimesdkvoice v1.15.5 // indirect github.com/aws/aws-sdk-go-v2/service/cleanrooms v1.12.5 // indirect - github.com/aws/aws-sdk-go-v2/service/cloud9 v1.24.9 // indirect + github.com/aws/aws-sdk-go-v2/service/cloud9 v1.24.10 // indirect github.com/aws/aws-sdk-go-v2/service/cloudcontrol v1.18.9 // indirect github.com/aws/aws-sdk-go-v2/service/cloudformation v1.51.2 // indirect github.com/aws/aws-sdk-go-v2/service/cloudfront v1.36.5 // indirect @@ -97,7 +97,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/docdbelastic v1.9.8 // indirect github.com/aws/aws-sdk-go-v2/service/drs v1.26.5 // indirect github.com/aws/aws-sdk-go-v2/service/dynamodb v1.32.7 // indirect - github.com/aws/aws-sdk-go-v2/service/ec2 v1.162.1 // indirect + github.com/aws/aws-sdk-go-v2/service/ec2 v1.163.0 // indirect github.com/aws/aws-sdk-go-v2/service/ecr v1.28.4 // indirect github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.9 // indirect github.com/aws/aws-sdk-go-v2/service/ecs v1.41.12 // indirect @@ -114,11 +114,11 @@ require ( github.com/aws/aws-sdk-go-v2/service/fis v1.24.7 // indirect github.com/aws/aws-sdk-go-v2/service/fms v1.33.6 // indirect github.com/aws/aws-sdk-go-v2/service/glacier v1.22.9 // indirect - github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.23.6 // indirect + github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.24.0 // indirect github.com/aws/aws-sdk-go-v2/service/groundstation v1.27.5 // indirect github.com/aws/aws-sdk-go-v2/service/healthlake v1.24.5 // indirect github.com/aws/aws-sdk-go-v2/service/iam v1.32.5 // indirect - github.com/aws/aws-sdk-go-v2/service/identitystore v1.23.10 // indirect + github.com/aws/aws-sdk-go-v2/service/identitystore v1.23.11 // indirect github.com/aws/aws-sdk-go-v2/service/inspector2 v1.26.5 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.10 // indirect @@ -154,14 +154,14 @@ require ( github.com/aws/aws-sdk-go-v2/service/osis v1.9.2 // indirect github.com/aws/aws-sdk-go-v2/service/paymentcryptography v1.10.5 // indirect github.com/aws/aws-sdk-go-v2/service/pcaconnectorad v1.5.9 // indirect - github.com/aws/aws-sdk-go-v2/service/pipes v1.11.9 // indirect + github.com/aws/aws-sdk-go-v2/service/pipes v1.12.0 // indirect github.com/aws/aws-sdk-go-v2/service/polly v1.40.4 // indirect github.com/aws/aws-sdk-go-v2/service/pricing v1.28.6 // indirect github.com/aws/aws-sdk-go-v2/service/qbusiness v1.6.5 // indirect github.com/aws/aws-sdk-go-v2/service/qldb v1.21.9 // indirect github.com/aws/aws-sdk-go-v2/service/ram v1.25.9 // indirect github.com/aws/aws-sdk-go-v2/service/rbin v1.16.9 // indirect - github.com/aws/aws-sdk-go-v2/service/rds v1.79.4 // indirect + github.com/aws/aws-sdk-go-v2/service/rds v1.79.5 // indirect github.com/aws/aws-sdk-go-v2/service/redshift v1.44.5 // indirect github.com/aws/aws-sdk-go-v2/service/redshiftdata v1.25.9 // indirect github.com/aws/aws-sdk-go-v2/service/redshiftserverless v1.18.6 // indirect @@ -173,7 +173,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/route53 v1.40.9 // indirect github.com/aws/aws-sdk-go-v2/service/route53domains v1.23.9 // indirect github.com/aws/aws-sdk-go-v2/service/route53profiles v1.0.6 // indirect - github.com/aws/aws-sdk-go-v2/service/s3 v1.54.4 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.55.0 // indirect github.com/aws/aws-sdk-go-v2/service/s3control v1.44.12 // indirect github.com/aws/aws-sdk-go-v2/service/scheduler v1.8.9 // indirect github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.29.2 // indirect @@ -201,7 +201,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/transcribe v1.37.5 // indirect github.com/aws/aws-sdk-go-v2/service/transfer v1.48.2 // indirect github.com/aws/aws-sdk-go-v2/service/verifiedpermissions v1.14.4 // indirect - github.com/aws/aws-sdk-go-v2/service/vpclattice v1.8.4 // indirect + github.com/aws/aws-sdk-go-v2/service/vpclattice v1.8.5 // indirect github.com/aws/aws-sdk-go-v2/service/waf v1.20.9 // indirect github.com/aws/aws-sdk-go-v2/service/wafregional v1.21.9 // indirect github.com/aws/aws-sdk-go-v2/service/wafv2 v1.49.2 // indirect diff --git a/tools/tfsdk2fw/go.sum b/tools/tfsdk2fw/go.sum index ccf268bb268..da679d7d760 100644 --- a/tools/tfsdk2fw/go.sum +++ b/tools/tfsdk2fw/go.sum @@ -24,6 +24,7 @@ github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aws/aws-sdk-go v1.53.15 h1:FtZmkg7xM8RfP2oY6p7xdKBYrRgkITk9yve2QV7N938= github.com/aws/aws-sdk-go v1.53.15/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go v1.53.18/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/aws/aws-sdk-go-v2 v1.27.1 h1:xypCL2owhog46iFxBKKpBcw+bPTX/RJzwNj8uSilENw= github.com/aws/aws-sdk-go-v2 v1.27.1/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 h1:x6xsQXGSmW6frevwDA+vi/wqhp1ct18mVXYN08/93to= @@ -36,6 +37,7 @@ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.4 h1:0cSfTYYL9qiRcdi4Dvz+8s3 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.4/go.mod h1:Wjn5O9eS7uSi7vlPKt/v0MLTncANn9EMmoDvnzJli6o= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.22 h1:1CO+m67soQzw6hfkfSS0hQzS/o05bCswr+gQfBfQgLQ= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.22/go.mod h1:XUetvjVEuGFl1ABsTZ/5tufz0WXT+MpR9qcMnEJm0dw= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.23/go.mod h1:8KSZ0CibxgOaPk28CFL4DGBdGrscHJr8FuxB+jnJBaM= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.8 h1:RnLB7p6aaFMRfyQkD6ckxR7myCC9SABIqSz4czYUUbU= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.8/go.mod h1:XH7dQJd+56wEbP1I4e4Duo+QhSMxNArE8VP7NuUOTeM= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.8 h1:jzApk2f58L9yW9q1GEab3BMMFWUkkiZhyrRUtbwUbKU= @@ -102,6 +104,7 @@ github.com/aws/aws-sdk-go-v2/service/cleanrooms v1.12.5 h1:uvhcW2IT6YYT+ueDRrXJG github.com/aws/aws-sdk-go-v2/service/cleanrooms v1.12.5/go.mod h1:AbquvPv3vI71Yj+Masu3krIsULx29rHAQLJqxGBfK/0= github.com/aws/aws-sdk-go-v2/service/cloud9 v1.24.9 h1:H6/x6Wkdk4Nnss4Rxp7LzdPhWXOvvdZ5jlSckhVnZ9c= github.com/aws/aws-sdk-go-v2/service/cloud9 v1.24.9/go.mod h1:+5URMBuBHX0x6MgcfOUrCRGmlRkQwbRu0SaNT8hseBw= +github.com/aws/aws-sdk-go-v2/service/cloud9 v1.24.10/go.mod h1:+5URMBuBHX0x6MgcfOUrCRGmlRkQwbRu0SaNT8hseBw= github.com/aws/aws-sdk-go-v2/service/cloudcontrol v1.18.9 h1:Wp1QFv8uyNpwPXSI/a6TRkIR0CiT+Fa60s5vVTsFdXM= github.com/aws/aws-sdk-go-v2/service/cloudcontrol v1.18.9/go.mod h1:pFrHzOZRN/EfWL7ygk9ELdQHqRGERgOgP03OLIOlQV4= github.com/aws/aws-sdk-go-v2/service/cloudformation v1.51.2 h1:FBc+xcfqpBzYl6WWIBk3AB9d/oc6r2sn/mYPnuORCFI= @@ -182,6 +185,7 @@ github.com/aws/aws-sdk-go-v2/service/dynamodb v1.32.7 h1:Y0pFOzMrx/c6mVswi99Y9Um github.com/aws/aws-sdk-go-v2/service/dynamodb v1.32.7/go.mod h1:CYR+43Fe0qazBzSTrIwSK7uYdYVf958kwGF+EQgQqhw= github.com/aws/aws-sdk-go-v2/service/ec2 v1.162.1 h1:2ZzpXgkh4qmsexltvLVIaC4+HdN3oe6OWK6Upc4Qz/0= github.com/aws/aws-sdk-go-v2/service/ec2 v1.162.1/go.mod h1:eu3DWRK5GBq4hjCr7nAbnQiHSan5RJ6ue3qQVp5PJs0= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.163.0/go.mod h1:eu3DWRK5GBq4hjCr7nAbnQiHSan5RJ6ue3qQVp5PJs0= github.com/aws/aws-sdk-go-v2/service/ecr v1.28.4 h1:nEnhbD8rfT+XGoD5ETf81uIVYZMFigG0XpnsTlreJmQ= github.com/aws/aws-sdk-go-v2/service/ecr v1.28.4/go.mod h1:ZjUXU9PCqBZaGjYVamdzpY1gIHdiyKHNRdjQV5V/iO8= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.9 h1:+GMe2/1NW21VksHgdEWOqWOcxly7eIq+l19KTQQyU6M= @@ -216,6 +220,7 @@ github.com/aws/aws-sdk-go-v2/service/glacier v1.22.9 h1:VEV/9IVykgeCD76wE+MRvSB8 github.com/aws/aws-sdk-go-v2/service/glacier v1.22.9/go.mod h1:YhA4aSfqiqBGagXxuT6jf8zQ79Yb3abiZpdtRiIljpY= github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.23.6 h1:/4Ha4fN6d/onv04rPmKVxShhJj3FVKFa3sfc5ZX3bCQ= github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.23.6/go.mod h1:45UdEiD/JbcgBVwcLZZd752sAutrndMdvNop/3js2oI= +github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.24.0/go.mod h1:45UdEiD/JbcgBVwcLZZd752sAutrndMdvNop/3js2oI= github.com/aws/aws-sdk-go-v2/service/groundstation v1.27.5 h1:mNgrkKH+6B1dtbkzSVA8qf9fR9lMg+mUEYUBNnWeWyU= github.com/aws/aws-sdk-go-v2/service/groundstation v1.27.5/go.mod h1:a8x2abmJoP3bGTTsX2LYIIyj4tMKLG8ophLxHBF6utM= github.com/aws/aws-sdk-go-v2/service/healthlake v1.24.5 h1:3BYfEzrCaDWyUOMDypGp6GyFYl3xYbAU88LQr4cTj4k= @@ -224,6 +229,7 @@ github.com/aws/aws-sdk-go-v2/service/iam v1.32.5 h1:G2judWqHbm2bDrmJPj9W0nD3Pv8+ github.com/aws/aws-sdk-go-v2/service/iam v1.32.5/go.mod h1:RorjhuicJ7tEwun17BEeD//1JiPdvxPv15KOa9BKxS8= github.com/aws/aws-sdk-go-v2/service/identitystore v1.23.10 h1:us6r5qB7SsyYfkYa+XGk3f1cJneKlRwyFxM2tkcHcKY= github.com/aws/aws-sdk-go-v2/service/identitystore v1.23.10/go.mod h1:h4eA/XwjtoO5dN6BVpOaBSOH6hUFM+PFWmAnx9wBkMg= +github.com/aws/aws-sdk-go-v2/service/identitystore v1.23.11/go.mod h1:h4eA/XwjtoO5dN6BVpOaBSOH6hUFM+PFWmAnx9wBkMg= github.com/aws/aws-sdk-go-v2/service/inspector2 v1.26.5 h1:UJUc+S6kAAivhWluw7+DGZe2o9VzVPD0LvyUgj62htA= github.com/aws/aws-sdk-go-v2/service/inspector2 v1.26.5/go.mod h1:Z0WGPJQcCcl40bqyYxr/iDvyR0MPqsQr930PESO6TcU= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs= @@ -296,6 +302,7 @@ github.com/aws/aws-sdk-go-v2/service/pcaconnectorad v1.5.9 h1:QPql+y5eUPyl1zwNzA github.com/aws/aws-sdk-go-v2/service/pcaconnectorad v1.5.9/go.mod h1:o0HMAgq53gq6tTads00hLRkmMOGoKCLHFBso4h0tYgQ= github.com/aws/aws-sdk-go-v2/service/pipes v1.11.9 h1:ycYYoWyMNdMeLnsRu4T//ESfCnsyu1ZpkpptMHsUsPY= github.com/aws/aws-sdk-go-v2/service/pipes v1.11.9/go.mod h1:F1oziwLahHIwsEHNgfAyTyDUEk3dSZAwtROItYF57rI= +github.com/aws/aws-sdk-go-v2/service/pipes v1.12.0/go.mod h1:F1oziwLahHIwsEHNgfAyTyDUEk3dSZAwtROItYF57rI= github.com/aws/aws-sdk-go-v2/service/polly v1.40.4 h1:MdwzWOjcnpC/HR5KmQ3erH8pjOmpfpLZrFffCJsD2mo= github.com/aws/aws-sdk-go-v2/service/polly v1.40.4/go.mod h1:PkYl8zbU1ejBMEjhVq4BspshPoZxGs3iWBgyY6tC5lE= github.com/aws/aws-sdk-go-v2/service/pricing v1.28.6 h1:Uy0mLx8tU+pMGxpupTw32FWDq1gz3xzCmGeFC5Mvq8s= @@ -310,6 +317,7 @@ github.com/aws/aws-sdk-go-v2/service/rbin v1.16.9 h1:ri7dGQymqVmJgZoUS7B6DVmJsvu github.com/aws/aws-sdk-go-v2/service/rbin v1.16.9/go.mod h1:jkgY6w+/RUUITe2tbJXM88NUsmldDmWk8T5Svd2BtFg= github.com/aws/aws-sdk-go-v2/service/rds v1.79.4 h1:+HYiMm/uR/M5LkESJ/QtQTUVPI1uj+HTBsmv2aH74FU= github.com/aws/aws-sdk-go-v2/service/rds v1.79.4/go.mod h1:esGFn2z+QNa/XcjHevnddtp3RiFQ9/pzHbjl0rgYqDE= +github.com/aws/aws-sdk-go-v2/service/rds v1.79.5/go.mod h1:esGFn2z+QNa/XcjHevnddtp3RiFQ9/pzHbjl0rgYqDE= github.com/aws/aws-sdk-go-v2/service/redshift v1.44.5 h1:6We8HAXf96XNvFZBwMNwbngkfbBmsChtYhfEX1AoznM= github.com/aws/aws-sdk-go-v2/service/redshift v1.44.5/go.mod h1:fy1q/fTBBHtQp4RIk6RNczpmBxaFDFbqkk4e/2pNlqs= github.com/aws/aws-sdk-go-v2/service/redshiftdata v1.25.9 h1:vc2DTUPVAF5SzxcFYYi4RnBPUGxg75lXK9+DV/h5fzo= @@ -334,6 +342,7 @@ github.com/aws/aws-sdk-go-v2/service/route53profiles v1.0.6 h1:QFfTnmxuNj9paWYSb github.com/aws/aws-sdk-go-v2/service/route53profiles v1.0.6/go.mod h1:0xv+lDKL+fzQ9KcTJqd9KrJvqTLs7/DTzr3lwD1b6Tc= github.com/aws/aws-sdk-go-v2/service/s3 v1.54.4 h1:4p9SCdZBO0PdEXLTF2fcQuxOEkEiqPQpK824cP2VKRo= github.com/aws/aws-sdk-go-v2/service/s3 v1.54.4/go.mod h1:oSkRFuHVWmUY4Ssk16ErGzBqvYEbvORJFzFXzWhTB2s= +github.com/aws/aws-sdk-go-v2/service/s3 v1.55.0/go.mod h1:oSkRFuHVWmUY4Ssk16ErGzBqvYEbvORJFzFXzWhTB2s= github.com/aws/aws-sdk-go-v2/service/s3control v1.44.12 h1:6F6JIv06AIJR7p+w9xjVYMVxkbNFBydg7eMcy/oP/r4= github.com/aws/aws-sdk-go-v2/service/s3control v1.44.12/go.mod h1:vWJVDhTPJgkpHRjz/MMMVvqoAupZ1W9emLj5cfnkPzs= github.com/aws/aws-sdk-go-v2/service/scheduler v1.8.9 h1:NH6WgOHc0dQlnKWUqVxHsfNC/ZVce94GSSMLBYBb5Rg= @@ -390,6 +399,7 @@ github.com/aws/aws-sdk-go-v2/service/verifiedpermissions v1.14.4 h1:5yPsNHtcI318 github.com/aws/aws-sdk-go-v2/service/verifiedpermissions v1.14.4/go.mod h1:pZyatQ35/jfUHq/41SfoKSaMkgAeePqNq1uezJMMSTI= github.com/aws/aws-sdk-go-v2/service/vpclattice v1.8.4 h1:EZJYKV3ryDGZ/s9HZq0xYIcfuhLZlyl9tt6Uv6BdiM8= github.com/aws/aws-sdk-go-v2/service/vpclattice v1.8.4/go.mod h1:2ow7cCSfYs1y759REZl7zlwbGpGKfo5B4DyAMIBjlyI= +github.com/aws/aws-sdk-go-v2/service/vpclattice v1.8.5/go.mod h1:2ow7cCSfYs1y759REZl7zlwbGpGKfo5B4DyAMIBjlyI= github.com/aws/aws-sdk-go-v2/service/waf v1.20.9 h1:5Y2yPlzL6GqM9gjY0EMi+lORXC+PHQvCibyGsPflHwU= github.com/aws/aws-sdk-go-v2/service/waf v1.20.9/go.mod h1:k/V6ngGarlLnH14pLvkWM/7YGJQXrAHSxbYh9FD53kI= github.com/aws/aws-sdk-go-v2/service/wafregional v1.21.9 h1:KgHX+2rtn9kw2on2nly6Tz5iOtpH0ix/oPoYZzSysGQ= From dbeb7864094629b46d36b4defd216e90b3667eee Mon Sep 17 00:00:00 2001 From: Ryo Takaishi Date: Fri, 7 Jun 2024 14:21:37 +0900 Subject: [PATCH 04/26] add validations --- internal/service/batch/ecs_properties.go | 50 +++++++++++++++++++++--- internal/service/batch/job_definition.go | 25 +++++++----- 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/internal/service/batch/ecs_properties.go b/internal/service/batch/ecs_properties.go index 0311b7e13c0..dec199936bc 100644 --- a/internal/service/batch/ecs_properties.go +++ b/internal/service/batch/ecs_properties.go @@ -8,11 +8,25 @@ import ( ) const ( - IpcModeHost = "host" - IpcModeTask = "task" - IpcModeNone = "none" - PicModeHost = "host" - PicModeTask = "task" + IpcModeHost = "host" + IpcModeTask = "task" + IpcModeNone = "none" + PicModeHost = "host" + PicModeTask = "task" + ResourceRequirementTypeGPU = "GPU" + ResourceRequirementTypeVCPU = "VCPU" + ResourceRequirementTypeMEMORY = "MEMORY" + RunTimePlatFormCpuArchX86_64 = "X86_64" + RunTimePlatFormCpuArchARM64 = "ARM64" + RunTimePlatformOSFamilyLinux = "LINUX" + RunTimePlatformOSFamilyWindowsServer2019Core = "WINDOWS_SERVER_2019_CORE" + RunTimePlatformOSFamilyWindowsServer2019Full = "WINDOWS_SERVER_2019_FULL" + RunTimePlatformOSFamilyWindowsServer2022Core = "WINDOWS_SERVER_2022_CORE" + RunTimePlatformOSFamilyWindowsServer2022Full = "WINDOWS_SERVER_2022_FULL" + EFSVolumeTransitEncryptionEnabled = "ENABLED" + EFSVolumeTransitEncryptionDisabled = "DISABLED" + NetworkConfigurationAssignPublicIpEnabled = "ENABLED" + NetworkConfigurationAssignPublicIpDisabled = "DISABLED" ) func IpcMode_Values() []string { @@ -23,6 +37,32 @@ func PidMode_Values() []string { return []string{PicModeHost, PicModeTask} } +func ResourceRequirementType_Values() []string { + return []string{ResourceRequirementTypeGPU, ResourceRequirementTypeVCPU, ResourceRequirementTypeMEMORY} +} + +func RunTimePlatFormCpuArch_Values() []string { + return []string{RunTimePlatFormCpuArchX86_64, RunTimePlatFormCpuArchARM64} +} + +func RunTimePlatformOSFamily_Values() []string { + return []string{ + RunTimePlatformOSFamilyLinux, + RunTimePlatformOSFamilyWindowsServer2019Core, + RunTimePlatformOSFamilyWindowsServer2019Full, + RunTimePlatformOSFamilyWindowsServer2022Core, + RunTimePlatformOSFamilyWindowsServer2022Full, + } +} + +func EFSVolumeTransitEncryption_Values() []string { + return []string{EFSVolumeTransitEncryptionEnabled, EFSVolumeTransitEncryptionDisabled} +} + +func NetworkConfigurationAssignPublicIp_Values() []string { + return []string{NetworkConfigurationAssignPublicIpEnabled, NetworkConfigurationAssignPublicIpDisabled} +} + func expandECSTaskProperties(taskPropsMap map[string]interface{}) *batch.EcsTaskProperties { taskProps := &batch.EcsTaskProperties{} diff --git a/internal/service/batch/job_definition.go b/internal/service/batch/job_definition.go index 1cbc214d7a8..f48638cf5ed 100644 --- a/internal/service/batch/job_definition.go +++ b/internal/service/batch/job_definition.go @@ -542,8 +542,9 @@ func ResourceJobDefinition() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "type": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(ResourceRequirementType_Values(), false), }, "value": { Type: schema.TypeString, @@ -624,8 +625,9 @@ func ResourceJobDefinition() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "assign_public_ip": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(NetworkConfigurationAssignPublicIp_Values(), false), }, }, }, @@ -647,12 +649,14 @@ func ResourceJobDefinition() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "cpu_architecture": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(RunTimePlatFormCpuArch_Values(), false), }, "operating_system_family": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(RunTimePlatformOSFamily_Values(), false), }, }, }, @@ -698,8 +702,9 @@ func ResourceJobDefinition() *schema.Resource { Optional: true, }, "transit_encryption": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(EFSVolumeTransitEncryption_Values(), false), }, "transit_encryption_port": { Type: schema.TypeInt, From 01b85709054d4fcc68d51412a831446c4ec689c9 Mon Sep 17 00:00:00 2001 From: Ryo Takaishi Date: Fri, 7 Jun 2024 14:36:14 +0900 Subject: [PATCH 05/26] fmt --- internal/service/cur/service_package.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/cur/service_package.go b/internal/service/cur/service_package.go index c642d641a1c..95d5d45ae6f 100644 --- a/internal/service/cur/service_package.go +++ b/internal/service/cur/service_package.go @@ -16,12 +16,12 @@ func (p *servicePackage) NewClient(ctx context.Context, config map[string]any) ( cfg := *(config["aws_sdkv2_config"].(*aws.Config)) return costandusagereportservice.NewFromConfig(cfg, func(o *costandusagereportservice.Options) { - if config["partition"].(string) == names.StandardPartitionID { + if config["partition"].(string) == names.StandardPartitionID { // AWS Cost and Usage Reports is only available in AWS Commercial us-east-1 Region. // https://docs.aws.amazon.com/general/latest/gr/billing.html. o.Region = names.USEast1RegionID } - + if endpoint := config[names.AttrEndpoint].(string); endpoint != "" { tflog.Debug(ctx, "setting endpoint", map[string]any{ "tf_aws.endpoint": endpoint, From 790687de151b15f0c80e78b113b0dc2bc883a7a5 Mon Sep 17 00:00:00 2001 From: Ryo Takaishi Date: Fri, 7 Jun 2024 15:20:55 +0900 Subject: [PATCH 06/26] add properties to test --- internal/service/batch/job_definition_test.go | 127 +++++++++++++++--- 1 file changed, 105 insertions(+), 22 deletions(-) diff --git a/internal/service/batch/job_definition_test.go b/internal/service/batch/job_definition_test.go index 668fb24c8a1..5b7a518308d 100644 --- a/internal/service/batch/job_definition_test.go +++ b/internal/service/batch/job_definition_test.go @@ -858,8 +858,29 @@ func TestAccBatchJobDefinition_ECSProperties_basic(t *testing.T) { Config: testAccJobDefinitionConfig_ECSProperties_basic(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckJobDefinitionExists(ctx, resourceName, &jd), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.#", "1"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.#", "2"), resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.image", "public.ecr.aws/amazonlinux/amazonlinux:1"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.command.#", "2"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.command.0", "sleep"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.command.1", "60"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.depends_on.0.container_name", "container_b"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.depends_on.0.condition", "COMPLETE"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.secrets.0.name", "TEST"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.secrets.0.value_from", "DUMMY"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.environment.0.name", "test"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.environment.0.value", "Environment Variable"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.log_configuration.0.log_driver", "awslogs"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.log_configuration.0.options.awslogs-group", rName), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.log_configuration.0.options.awslogs-region", "ap-northeast-1"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.log_configuration.0.options.awslogs-stream-prefix", "ecs"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.name", "container_a"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.privileged", "false"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.readonly_root_filesystem", "false"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.resource_requirements.0.type", "MEMORY"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.resource_requirements.0.value", "2048"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.resource_requirements.1.type", "VCPU"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.resource_requirements.1.value", "1.0"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.1.name", "container_b"), resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), resource.TestCheckResourceAttr(resourceName, names.AttrType, "container"), ), @@ -898,10 +919,12 @@ func TestAccBatchJobDefinition_ECSProperties_update(t *testing.T) { Config: testAccJobDefinitionConfig_ECSProperties_advancedUpdate(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckJobDefinitionExists(ctx, resourceName, &jd), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.#", "1"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.environment.#", "1"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.#", "2"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.environment.#", "2"), resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.environment.0.name", "test"), resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.environment.0.value", "Environment Variable"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.environment.1.name", "test2"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.environment.1.value", "Environment Variable 2"), resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), resource.TestCheckResourceAttr(resourceName, names.AttrType, "container"), ), @@ -1789,20 +1812,21 @@ resource "aws_batch_job_definition" "test" { task_properties { execution_role_arn = aws_iam_role.ecs_task_execution_role.arn containers { - essential = true image = "public.ecr.aws/amazonlinux/amazonlinux:1" - command = [ - "sleep", - "60" - ] - resource_requirements { - value = "1.0" - type = "VCPU" + command = ["sleep", "60"] + depends_on { + container_name = "container_b" + condition = "COMPLETE" } - resource_requirements { - value = "2048" - type = "MEMORY" + secrets { + name = "TEST" + value_from = "DUMMY" } + environment { + name = "test" + value = "Environment Variable" + } + essential = true log_configuration { log_driver = "awslogs" options = { @@ -1811,6 +1835,31 @@ resource "aws_batch_job_definition" "test" { awslogs-stream-prefix = "ecs" } } + name = "container_a" + privileged = false + readonly_root_filesystem = false + resource_requirements { + value = "1.0" + type = "VCPU" + } + resource_requirements { + value = "2048" + type = "MEMORY" + } + } + + containers { + image = "public.ecr.aws/amazonlinux/amazonlinux:1" + command = ["sleep", "360"] + name = "container_b" + resource_requirements { + value = "1.0" + type = "VCPU" + } + resource_requirements { + value = "2048" + type = "MEMORY" + } } } } @@ -1851,12 +1900,36 @@ resource "aws_batch_job_definition" "test" { task_properties { execution_role_arn = aws_iam_role.ecs_task_execution_role.arn containers { - essential = true image = "public.ecr.aws/amazonlinux/amazonlinux:1" - command = [ - "sleep", - "60" - ] + command = ["sleep", "60"] + depends_on { + container_name = "container_b" + condition = "COMPLETE" + } + secrets { + name = "TEST" + value_from = "DUMMY" + } + environment { + name = "test" + value = "Environment Variable" + } + environment { + name = "test2" + value = "Environment Variable 2" + } + essential = true + log_configuration { + log_driver = "awslogs" + options = { + awslogs-group = %[1]q + awslogs-region = "ap-northeast-1" + awslogs-stream-prefix = "ecs" + } + } + name = "container_a" + privileged = false + readonly_root_filesystem = false resource_requirements { value = "1.0" type = "VCPU" @@ -1865,9 +1938,19 @@ resource "aws_batch_job_definition" "test" { value = "2048" type = "MEMORY" } - environment { - name = "test" - value = "Environment Variable" + } + + containers { + image = "public.ecr.aws/amazonlinux/amazonlinux:1" + command = ["sleep", "360"] + name = "container_b" + resource_requirements { + value = "1.0" + type = "VCPU" + } + resource_requirements { + value = "2048" + type = "MEMORY" } } } From 79255d47af6233099df51828f8ecc54efd441448 Mon Sep 17 00:00:00 2001 From: Ryo Takaishi Date: Fri, 7 Jun 2024 15:33:30 +0900 Subject: [PATCH 07/26] add changelog --- .changelog/37871.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/37871.txt diff --git a/.changelog/37871.txt b/.changelog/37871.txt new file mode 100644 index 00000000000..cb771957b3b --- /dev/null +++ b/.changelog/37871.txt @@ -0,0 +1,3 @@ +`release-note:enhancement +resource/aws_batch_job_definition: Adds ability to define `ecs_properties` +``` From 4cf8e6e2edcfbc1eca7c836d862c8f924d67c118 Mon Sep 17 00:00:00 2001 From: Ryo Takaishi Date: Sun, 30 Jun 2024 13:48:32 +0900 Subject: [PATCH 08/26] fix: volumes not volume --- website/docs/r/batch_job_definition.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/batch_job_definition.html.markdown b/website/docs/r/batch_job_definition.html.markdown index d76c37a517f..12877a212eb 100644 --- a/website/docs/r/batch_job_definition.html.markdown +++ b/website/docs/r/batch_job_definition.html.markdown @@ -305,7 +305,7 @@ The following arguments are optional: * `platform_version` - (Optional) The platform version on which to run your task. If one is not specified, the LATEST platform version is used by default. * `runtime_platform` - (Optional) The compute environment architecture for AWS Batch job on Fargate. See [runtime_platform](#runtime_platform) below. * `task_role_arn` - The Amazon Resource Name (ARN) of the IAM role that the Amazon ECS task.. -* `volume` - (Optional) The volumes to mount on the container in the task. See [volume](#volume) below. +* `volumes` - (Optional) The volumes to mount on the container in the task. See [volumes](#volumes) below. ### `containers` From 6a966d7f6a9f6e3c0bcad71d82e61e4cb22fe9fa Mon Sep 17 00:00:00 2001 From: Ryo Takaishi Date: Sun, 30 Jun 2024 13:51:00 +0900 Subject: [PATCH 09/26] fix: typo --- internal/service/batch/ecs_properties.go | 6 +++--- website/docs/r/batch_job_definition.html.markdown | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/service/batch/ecs_properties.go b/internal/service/batch/ecs_properties.go index dec199936bc..7be3943f8bf 100644 --- a/internal/service/batch/ecs_properties.go +++ b/internal/service/batch/ecs_properties.go @@ -11,8 +11,8 @@ const ( IpcModeHost = "host" IpcModeTask = "task" IpcModeNone = "none" - PicModeHost = "host" - PicModeTask = "task" + PidModeHost = "host" + PidModeTask = "task" ResourceRequirementTypeGPU = "GPU" ResourceRequirementTypeVCPU = "VCPU" ResourceRequirementTypeMEMORY = "MEMORY" @@ -34,7 +34,7 @@ func IpcMode_Values() []string { } func PidMode_Values() []string { - return []string{PicModeHost, PicModeTask} + return []string{PidModeHost, PidModeTask} } func ResourceRequirementType_Values() []string { diff --git a/website/docs/r/batch_job_definition.html.markdown b/website/docs/r/batch_job_definition.html.markdown index 12877a212eb..a3d35ccceab 100644 --- a/website/docs/r/batch_job_definition.html.markdown +++ b/website/docs/r/batch_job_definition.html.markdown @@ -301,7 +301,7 @@ The following arguments are optional: * `execution_role_arn` - (Optional) The Amazon Resource Name (ARN) of the IAM role that the AWS Batch can assume. * `ipc_mode` - (Optional) The IPC resource namespace to use for container in the task. The valid values are `host`, `task`, or `none`. * `network_configuration` - (Optional) The network configuration for the Amazon ECS task. See [network_configuration](#network_configuration) below. -* `pic_mode` - (Optional) The process namespace to use for the container in the task. The valid values are `host` or `task`. +* `pid_mode` - (Optional) The process namespace to use for the container in the task. The valid values are `host` or `task`. * `platform_version` - (Optional) The platform version on which to run your task. If one is not specified, the LATEST platform version is used by default. * `runtime_platform` - (Optional) The compute environment architecture for AWS Batch job on Fargate. See [runtime_platform](#runtime_platform) below. * `task_role_arn` - The Amazon Resource Name (ARN) of the IAM role that the Amazon ECS task.. From 320085f325f146ae17fdc361c8a5e01de5ab8cee Mon Sep 17 00:00:00 2001 From: Ryo Takaishi Date: Sun, 30 Jun 2024 13:57:21 +0900 Subject: [PATCH 10/26] fix: section title --- website/docs/r/batch_job_definition.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/batch_job_definition.html.markdown b/website/docs/r/batch_job_definition.html.markdown index a3d35ccceab..cc936a171b9 100644 --- a/website/docs/r/batch_job_definition.html.markdown +++ b/website/docs/r/batch_job_definition.html.markdown @@ -134,7 +134,7 @@ resource "aws_batch_job_definition" "test" { } ``` -### Job Definitionn of type EKS +### Job Definition of type container using `ecs_properties` ```terraform resource "aws_batch_job_definition" "test" { From e90348c15176b284619438a3af227caec5ed34d4 Mon Sep 17 00:00:00 2001 From: Ryo Takaishi Date: Sun, 30 Jun 2024 14:02:01 +0900 Subject: [PATCH 11/26] fix: containers has a list of container. --- website/docs/r/batch_job_definition.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/batch_job_definition.html.markdown b/website/docs/r/batch_job_definition.html.markdown index cc936a171b9..449b4f58aeb 100644 --- a/website/docs/r/batch_job_definition.html.markdown +++ b/website/docs/r/batch_job_definition.html.markdown @@ -296,7 +296,7 @@ The following arguments are optional: ### `task_properties` -* `containers` - The properties of the container. See [containers](#ecs_containers) below. +* `containers` - A list of containers. See [containers](#ecs_containers) below. * `ephemeral_storage` - (Optional) The ephemeral storage settings for the task. See [ephemeral_storage](#ephemeral_storage) below. * `execution_role_arn` - (Optional) The Amazon Resource Name (ARN) of the IAM role that the AWS Batch can assume. * `ipc_mode` - (Optional) The IPC resource namespace to use for container in the task. The valid values are `host`, `task`, or `none`. From 10a4475ef5711adc94412978f3fc428e4f641758 Mon Sep 17 00:00:00 2001 From: Ryo Takaishi Date: Thu, 4 Jul 2024 21:39:29 +0900 Subject: [PATCH 12/26] chore: use container instead of containers because task_properties can more than two containers. --- internal/service/batch/ecs_properties.go | 4 +- internal/service/batch/job_definition.go | 2 +- internal/service/batch/job_definition_test.go | 66 +++++++++---------- .../docs/r/batch_job_definition.html.markdown | 2 +- 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/internal/service/batch/ecs_properties.go b/internal/service/batch/ecs_properties.go index 7be3943f8bf..10b5d9aab02 100644 --- a/internal/service/batch/ecs_properties.go +++ b/internal/service/batch/ecs_properties.go @@ -66,7 +66,7 @@ func NetworkConfigurationAssignPublicIp_Values() []string { func expandECSTaskProperties(taskPropsMap map[string]interface{}) *batch.EcsTaskProperties { taskProps := &batch.EcsTaskProperties{} - if v, ok := taskPropsMap["containers"]; ok { + if v, ok := taskPropsMap["container"]; ok { containers := v.([]interface{}) taskProps.Containers = expandEcsTaskContainers(containers) } @@ -191,7 +191,7 @@ func flattenECSTaskProperties(taskProperties *batch.EcsTaskProperties) (tfList [ tfMap := make(map[string]interface{}, 0) if v := taskProperties.Containers; v != nil { - tfMap["containers"] = flattenEcsTaskContainers(v) + tfMap["container"] = flattenEcsTaskContainers(v) } if v := taskProperties.EphemeralStorage; v != nil { diff --git a/internal/service/batch/job_definition.go b/internal/service/batch/job_definition.go index f48638cf5ed..b37409e30be 100644 --- a/internal/service/batch/job_definition.go +++ b/internal/service/batch/job_definition.go @@ -340,7 +340,7 @@ func ResourceJobDefinition() *schema.Resource { Required: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "containers": { + "container": { Type: schema.TypeList, Required: true, Elem: &schema.Resource{ diff --git a/internal/service/batch/job_definition_test.go b/internal/service/batch/job_definition_test.go index 5b7a518308d..a1fc1b852cc 100644 --- a/internal/service/batch/job_definition_test.go +++ b/internal/service/batch/job_definition_test.go @@ -858,29 +858,29 @@ func TestAccBatchJobDefinition_ECSProperties_basic(t *testing.T) { Config: testAccJobDefinitionConfig_ECSProperties_basic(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckJobDefinitionExists(ctx, resourceName, &jd), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.#", "2"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.image", "public.ecr.aws/amazonlinux/amazonlinux:1"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.command.#", "2"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.command.0", "sleep"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.command.1", "60"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.depends_on.0.container_name", "container_b"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.depends_on.0.condition", "COMPLETE"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.secrets.0.name", "TEST"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.secrets.0.value_from", "DUMMY"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.environment.0.name", "test"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.environment.0.value", "Environment Variable"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.log_configuration.0.log_driver", "awslogs"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.log_configuration.0.options.awslogs-group", rName), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.log_configuration.0.options.awslogs-region", "ap-northeast-1"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.log_configuration.0.options.awslogs-stream-prefix", "ecs"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.name", "container_a"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.privileged", "false"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.readonly_root_filesystem", "false"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.resource_requirements.0.type", "MEMORY"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.resource_requirements.0.value", "2048"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.resource_requirements.1.type", "VCPU"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.resource_requirements.1.value", "1.0"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.1.name", "container_b"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.#", "2"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.image", "public.ecr.aws/amazonlinux/amazonlinux:1"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.command.#", "2"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.command.0", "sleep"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.command.1", "60"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.depends_on.0.container_name", "container_b"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.depends_on.0.condition", "COMPLETE"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.secrets.0.name", "TEST"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.secrets.0.value_from", "DUMMY"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.environment.0.name", "test"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.environment.0.value", "Environment Variable"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.log_configuration.0.log_driver", "awslogs"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.log_configuration.0.options.awslogs-group", rName), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.log_configuration.0.options.awslogs-region", "ap-northeast-1"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.log_configuration.0.options.awslogs-stream-prefix", "ecs"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.name", "container_a"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.privileged", "false"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.readonly_root_filesystem", "false"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.resource_requirements.0.type", "MEMORY"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.resource_requirements.0.value", "2048"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.resource_requirements.1.type", "VCPU"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.resource_requirements.1.value", "1.0"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.1.name", "container_b"), resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), resource.TestCheckResourceAttr(resourceName, names.AttrType, "container"), ), @@ -919,12 +919,12 @@ func TestAccBatchJobDefinition_ECSProperties_update(t *testing.T) { Config: testAccJobDefinitionConfig_ECSProperties_advancedUpdate(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckJobDefinitionExists(ctx, resourceName, &jd), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.#", "2"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.environment.#", "2"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.environment.0.name", "test"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.environment.0.value", "Environment Variable"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.environment.1.name", "test2"), - resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.containers.0.environment.1.value", "Environment Variable 2"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.#", "2"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.environment.#", "2"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.environment.0.name", "test"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.environment.0.value", "Environment Variable"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.environment.1.name", "test2"), + resource.TestCheckResourceAttr(resourceName, "ecs_properties.0.task_properties.0.container.0.environment.1.value", "Environment Variable 2"), resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), resource.TestCheckResourceAttr(resourceName, names.AttrType, "container"), ), @@ -1811,7 +1811,7 @@ resource "aws_batch_job_definition" "test" { ecs_properties { task_properties { execution_role_arn = aws_iam_role.ecs_task_execution_role.arn - containers { + container { image = "public.ecr.aws/amazonlinux/amazonlinux:1" command = ["sleep", "60"] depends_on { @@ -1848,7 +1848,7 @@ resource "aws_batch_job_definition" "test" { } } - containers { + container { image = "public.ecr.aws/amazonlinux/amazonlinux:1" command = ["sleep", "360"] name = "container_b" @@ -1899,7 +1899,7 @@ resource "aws_batch_job_definition" "test" { ecs_properties { task_properties { execution_role_arn = aws_iam_role.ecs_task_execution_role.arn - containers { + container { image = "public.ecr.aws/amazonlinux/amazonlinux:1" command = ["sleep", "60"] depends_on { @@ -1940,7 +1940,7 @@ resource "aws_batch_job_definition" "test" { } } - containers { + container { image = "public.ecr.aws/amazonlinux/amazonlinux:1" command = ["sleep", "360"] name = "container_b" diff --git a/website/docs/r/batch_job_definition.html.markdown b/website/docs/r/batch_job_definition.html.markdown index 449b4f58aeb..c8afbc2cd77 100644 --- a/website/docs/r/batch_job_definition.html.markdown +++ b/website/docs/r/batch_job_definition.html.markdown @@ -307,7 +307,7 @@ The following arguments are optional: * `task_role_arn` - The Amazon Resource Name (ARN) of the IAM role that the Amazon ECS task.. * `volumes` - (Optional) The volumes to mount on the container in the task. See [volumes](#volumes) below. -### `containers` +### `container` * `image` - The image used to start the container. * `command` - (Optional) The command that's passed to the container. From 18ce938c07c3176c3a3dd20d0cde4e7c1937e745 Mon Sep 17 00:00:00 2001 From: Ryo Takaishi Date: Thu, 4 Jul 2024 21:41:55 +0900 Subject: [PATCH 13/26] doc: add example has multiple containers --- .../docs/r/batch_job_definition.html.markdown | 54 ++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/website/docs/r/batch_job_definition.html.markdown b/website/docs/r/batch_job_definition.html.markdown index c8afbc2cd77..60db3df9584 100644 --- a/website/docs/r/batch_job_definition.html.markdown +++ b/website/docs/r/batch_job_definition.html.markdown @@ -134,7 +134,7 @@ resource "aws_batch_job_definition" "test" { } ``` -### Job Definition of type container using `ecs_properties` +### Job Definition of type container using `ecs_properties` with single container ```terraform resource "aws_batch_job_definition" "test" { @@ -146,6 +146,7 @@ resource "aws_batch_job_definition" "test" { containers { essential = true image = "public.ecr.aws/amazonlinux/amazonlinux:1" + name = "container_a" command = [ "sleep", "60" @@ -167,6 +168,57 @@ resource "aws_batch_job_definition" "test" { } } ``` +### Job Definition of type container using `ecs_properties` with multiple containers + +```terraform +resource "aws_batch_job_definition" "test" { + name = " tf_test_batch_job_definition_ecs" + type = "container" + ecs_properties { + task_properties { + host_network = true + containers { + essential = true + image = "public.ecr.aws/amazonlinux/amazonlinux:1" + name = "container_a" + command = [ + "sleep", + "60" + ] + resource_requirements { + value = "1.0" + type = "VCPU" + } + resource_requirements { + value = "2048" + type = "MEMORY" + } + environment { + name = "test" + value = "Environment Variable" + } + } + + container { + image = "public.ecr.aws/amazonlinux/amazonlinux:1" + name = "container_b" + command = [ + "sleep", + "60" + ] + resource_requirements { + value = "1.0" + type = "VCPU" + } + resource_requirements { + value = "2048" + type = "MEMORY" + } + } + } + } +} +``` ### Fargate Platform Capability From f336d325fc2bf27ee6dd964bf182edfca3d8c9c9 Mon Sep 17 00:00:00 2001 From: Ryo Takaishi Date: Thu, 4 Jul 2024 21:50:54 +0900 Subject: [PATCH 14/26] chore: update go.mod --- tools/tfsdk2fw/go.mod | 8 ++++---- tools/tfsdk2fw/go.sum | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tools/tfsdk2fw/go.mod b/tools/tfsdk2fw/go.mod index 033db5b9070..a4a6ad0a85d 100644 --- a/tools/tfsdk2fw/go.mod +++ b/tools/tfsdk2fw/go.mod @@ -18,13 +18,13 @@ require ( github.com/agext/levenshtein v1.2.3 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/armon/go-radix v1.0.0 // indirect - github.com/aws/aws-sdk-go v1.54.12 // indirect + github.com/aws/aws-sdk-go v1.54.13 // indirect github.com/aws/aws-sdk-go-v2 v1.30.1 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 // indirect github.com/aws/aws-sdk-go-v2/config v1.27.23 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.23 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9 // indirect - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.3 // indirect + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.4 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.13 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.13 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect @@ -104,7 +104,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/docdbelastic v1.11.1 // indirect github.com/aws/aws-sdk-go-v2/service/drs v1.28.1 // indirect github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.1 // indirect - github.com/aws/aws-sdk-go-v2/service/ec2 v1.167.1 // indirect + github.com/aws/aws-sdk-go-v2/service/ec2 v1.168.0 // indirect github.com/aws/aws-sdk-go-v2/service/ecr v1.30.1 // indirect github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.25.1 // indirect github.com/aws/aws-sdk-go-v2/service/ecs v1.44.1 // indirect @@ -189,7 +189,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/route53domains v1.25.1 // indirect github.com/aws/aws-sdk-go-v2/service/route53profiles v1.2.1 // indirect github.com/aws/aws-sdk-go-v2/service/rum v1.19.1 // indirect - github.com/aws/aws-sdk-go-v2/service/s3 v1.57.1 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.58.0 // indirect github.com/aws/aws-sdk-go-v2/service/s3control v1.46.1 // indirect github.com/aws/aws-sdk-go-v2/service/scheduler v1.10.1 // indirect github.com/aws/aws-sdk-go-v2/service/schemas v1.26.1 // indirect diff --git a/tools/tfsdk2fw/go.sum b/tools/tfsdk2fw/go.sum index 9fa094611f0..1a95abd4458 100644 --- a/tools/tfsdk2fw/go.sum +++ b/tools/tfsdk2fw/go.sum @@ -24,6 +24,7 @@ github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aws/aws-sdk-go v1.54.12 h1:xPDB+GSBZq0rJbmDZF+EyfMbnWRyfEPcn7PZ7bJjXSw= github.com/aws/aws-sdk-go v1.54.12/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= +github.com/aws/aws-sdk-go v1.54.13/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= github.com/aws/aws-sdk-go-v2 v1.30.1 h1:4y/5Dvfrhd1MxRDD77SrfsDaj8kUkkljU7XE83NPV+o= github.com/aws/aws-sdk-go-v2 v1.30.1/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 h1:tW1/Rkad38LA15X4UQtjXZXNKsCgkshC3EbmcUmghTg= @@ -36,6 +37,7 @@ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9 h1:Aznqksmd6Rfv2HQN9cpqIV/ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9/go.mod h1:WQr3MY7AxGNxaqAtsDWn+fBxmd4XvLkzeqQ8P1VM0/w= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.3 h1:J2mHCzCeDQNfBOas73ARi4/CsLm0wYpQ3Itll8dPDBQ= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.3/go.mod h1:6rYGWnaLHD+WRF4E709VW+HEEJPKZbNdjHgq9osFXuE= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.4/go.mod h1:h0TjcRi+nTob6fksqubKOe+Hra8uqfgmN+vuw4xRwWE= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.13 h1:5SAoZ4jYpGH4721ZNoS1znQrhOfZinOhc4XuTXx/nVc= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.13/go.mod h1:+rdA6ZLpaSeM7tSg/B0IEDinCIBJGmW8rKDFkYpP04g= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.13 h1:WIijqeaAO7TYFLbhsZmi2rgLEAtWOC1LhxCAVTJlSKw= @@ -196,6 +198,7 @@ github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.1 h1:Szwz1vpZkvfhFMJ0X5uUECg github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.1/go.mod h1:b4wouGyJlzkr2HAvPrDGgYNp1EtmlXOkzhEOvl0c0FQ= github.com/aws/aws-sdk-go-v2/service/ec2 v1.167.1 h1:194kHl9h0FnIZ9PTWeBiAYVX8lKYJ9OT3rZXFM79X2M= github.com/aws/aws-sdk-go-v2/service/ec2 v1.167.1/go.mod h1:CtLD6CPq9z9dyMxV+H6/M5d9+/ea3dO80um029GXqV0= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.168.0/go.mod h1:CtLD6CPq9z9dyMxV+H6/M5d9+/ea3dO80um029GXqV0= github.com/aws/aws-sdk-go-v2/service/ecr v1.30.1 h1:zV3FlyuyPzfyFOXKu6mJW9JBGzdtOgpdlj3va+naOD8= github.com/aws/aws-sdk-go-v2/service/ecr v1.30.1/go.mod h1:l0zC7cSb2vAH1fr8+BRlolWT9cwlKpbRC8PjW6tyyIU= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.25.1 h1:54/7zy+oA2ep9UzWjAtccawCj3ZAXhMXxwBg0yNRxTA= @@ -366,6 +369,7 @@ github.com/aws/aws-sdk-go-v2/service/rum v1.19.1 h1:2LfqWtIyncZxc0hK9vScqTkXXY1s github.com/aws/aws-sdk-go-v2/service/rum v1.19.1/go.mod h1:HGOf93YUR9Na69vxfqcPK1op1LRlqXgd7/gIKdNkjmo= github.com/aws/aws-sdk-go-v2/service/s3 v1.57.1 h1:aHPtNY87GZ214N4rShgIo+5JQz7ICrJ50i17JbueUTw= github.com/aws/aws-sdk-go-v2/service/s3 v1.57.1/go.mod h1:hdV0NTYd0RwV4FvNKhKUNbPLZoq9CTr/lke+3I7aCAI= +github.com/aws/aws-sdk-go-v2/service/s3 v1.58.0/go.mod h1:hdV0NTYd0RwV4FvNKhKUNbPLZoq9CTr/lke+3I7aCAI= github.com/aws/aws-sdk-go-v2/service/s3control v1.46.1 h1:PGCbHXY4ykRTP072d2IZvJiFt6mW0RJ8vfFTdk2hLbA= github.com/aws/aws-sdk-go-v2/service/s3control v1.46.1/go.mod h1:6rKG97PjdiPjxN2IR3yINOjfchz9OMYtkWchgcn6DWY= github.com/aws/aws-sdk-go-v2/service/scheduler v1.10.1 h1:0PRs0NagmL38++LZ0AtIBJpJotPkGljE+x8VuInM3SI= From e0211602a799f84c7de6e5d69f27b5d4a90e4f0e Mon Sep 17 00:00:00 2001 From: Ryo Takaishi Date: Sat, 6 Jul 2024 11:12:26 +0900 Subject: [PATCH 15/26] fix: typo --- website/docs/r/batch_job_definition.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/batch_job_definition.html.markdown b/website/docs/r/batch_job_definition.html.markdown index 60db3df9584..596e6ad1b86 100644 --- a/website/docs/r/batch_job_definition.html.markdown +++ b/website/docs/r/batch_job_definition.html.markdown @@ -143,7 +143,7 @@ resource "aws_batch_job_definition" "test" { ecs_properties { task_properties { host_network = true - containers { + container { essential = true image = "public.ecr.aws/amazonlinux/amazonlinux:1" name = "container_a" @@ -177,7 +177,7 @@ resource "aws_batch_job_definition" "test" { ecs_properties { task_properties { host_network = true - containers { + container { essential = true image = "public.ecr.aws/amazonlinux/amazonlinux:1" name = "container_a" From 4c61ae13a17024e784b4b5847ab4a023f4b56c44 Mon Sep 17 00:00:00 2001 From: Ryo Takaishi Date: Sat, 6 Jul 2024 11:14:41 +0900 Subject: [PATCH 16/26] fix: max size of containers is 10 --- internal/service/batch/job_definition.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/service/batch/job_definition.go b/internal/service/batch/job_definition.go index b37409e30be..627ffde0bf2 100644 --- a/internal/service/batch/job_definition.go +++ b/internal/service/batch/job_definition.go @@ -343,6 +343,7 @@ func ResourceJobDefinition() *schema.Resource { "container": { Type: schema.TypeList, Required: true, + MaxItems: 10, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "image": { From aede86fbb87e4ab0ee7c55aa89d84b745484260a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 15 Aug 2024 12:01:43 -0400 Subject: [PATCH 17/26] Update internal/service/batch/job_definition.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fábio Franco Uechi <308613+fabito@users.noreply.github.com> --- internal/service/batch/job_definition.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/service/batch/job_definition.go b/internal/service/batch/job_definition.go index 627ffde0bf2..0acbe2db6d4 100644 --- a/internal/service/batch/job_definition.go +++ b/internal/service/batch/job_definition.go @@ -344,6 +344,7 @@ func ResourceJobDefinition() *schema.Resource { Type: schema.TypeList, Required: true, MaxItems: 10, + MaxItems: 10, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "image": { From 3fcbfb5c6032776144ef4f50423ce6f168d64e35 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 15 Aug 2024 14:08:31 -0400 Subject: [PATCH 18/26] r/aws_batch_job_definition: Some cleanup for 'ecs_properties'. --- internal/service/batch/job_definition.go | 103 +++++++++++++---------- 1 file changed, 59 insertions(+), 44 deletions(-) diff --git a/internal/service/batch/job_definition.go b/internal/service/batch/job_definition.go index ce09ee60715..a42db21557b 100644 --- a/internal/service/batch/job_definition.go +++ b/internal/service/batch/job_definition.go @@ -445,7 +445,6 @@ func resourceJobDefinition() *schema.Resource { }, }, }, - names.AttrType: { Type: schema.TypeString, Required: true, @@ -612,7 +611,8 @@ func resourceJobDefinitionCreate(ctx context.Context, d *schema.ResourceData, me Type: jobDefinitionType, } - if jobDefinitionType == awstypes.JobDefinitionTypeContainer { + switch jobDefinitionType { + case awstypes.JobDefinitionTypeContainer: if v, ok := d.GetOk("node_properties"); ok && v != nil { return sdkdiag.AppendErrorf(diags, "No `node_properties` can be specified when `type` is %q", jobDefinitionType) } @@ -623,7 +623,7 @@ func resourceJobDefinitionCreate(ctx context.Context, d *schema.ResourceData, me return sdkdiag.AppendFromErr(diags, err) } - removeEmptyEnvironmentVariables(&diags, props.Environment, cty.GetAttrPath("container_properties")) + diags = append(diags, removeEmptyEnvironmentVariables(props.Environment, cty.GetAttrPath("container_properties"))...) input.ContainerProperties = props } @@ -633,6 +633,11 @@ func resourceJobDefinitionCreate(ctx context.Context, d *schema.ResourceData, me return sdkdiag.AppendFromErr(diags, err) } + for _, taskProp := range props.TaskProperties { + for _, c := range taskProp.Containers { + diags = append(diags, removeEmptyEnvironmentVariables(c.Environment, cty.GetAttrPath("ecs_properties"))...) + } + } input.EcsProperties = props } @@ -645,9 +650,8 @@ func resourceJobDefinitionCreate(ctx context.Context, d *schema.ResourceData, me } } } - } - if jobDefinitionType == awstypes.JobDefinitionTypeMultinode { + case awstypes.JobDefinitionTypeMultinode: if v, ok := d.GetOk("container_properties"); ok && v != nil { return sdkdiag.AppendErrorf(diags, "No `container_properties` can be specified when `type` is %q", jobDefinitionType) } @@ -665,7 +669,7 @@ func resourceJobDefinitionCreate(ctx context.Context, d *schema.ResourceData, me } for _, node := range props.NodeRangeProperties { - removeEmptyEnvironmentVariables(&diags, node.Container.Environment, cty.GetAttrPath("node_properties")) + diags = append(diags, removeEmptyEnvironmentVariables(node.Container.Environment, cty.GetAttrPath("node_properties"))...) } input.NodeProperties = props } @@ -780,51 +784,54 @@ func resourceJobDefinitionUpdate(ctx context.Context, d *schema.ResourceData, me Type: jobDefinitionType, } - if v, ok := d.GetOk("container_properties"); ok { - props, err := expandContainerProperties(v.(string)) - if err != nil { - return sdkdiag.AppendFromErr(diags, err) - } + switch jobDefinitionType { + case awstypes.JobDefinitionTypeContainer: + if v, ok := d.GetOk("container_properties"); ok { + props, err := expandContainerProperties(v.(string)) + if err != nil { + return sdkdiag.AppendFromErr(diags, err) + } - if jobDefinitionType == awstypes.JobDefinitionTypeContainer { - removeEmptyEnvironmentVariables(&diags, props.Environment, cty.GetAttrPath("container_properties")) + diags = append(diags, removeEmptyEnvironmentVariables(props.Environment, cty.GetAttrPath("container_properties"))...) input.ContainerProperties = props } - } - - if v, ok := d.GetOk("ecs_properties"); ok { - props, err := expandECSProperties(v.(string)) - if err != nil { - return sdkdiag.AppendFromErr(diags, err) - } - input.EcsProperties = props - } + if v, ok := d.GetOk("ecs_properties"); ok { + props, err := expandECSProperties(v.(string)) + if err != nil { + return sdkdiag.AppendFromErr(diags, err) + } - if v, ok := d.GetOk("eks_properties"); ok { - eksProps := v.([]interface{})[0].(map[string]interface{}) - if podProps, ok := eksProps["pod_properties"].([]interface{}); ok && len(podProps) > 0 { - props := expandEKSPodProperties(podProps[0].(map[string]interface{})) - input.EksProperties = &awstypes.EksProperties{ - PodProperties: props, + for _, taskProp := range props.TaskProperties { + for _, c := range taskProp.Containers { + diags = append(diags, removeEmptyEnvironmentVariables(c.Environment, cty.GetAttrPath("ecs_properties"))...) + } } + input.EcsProperties = props } - } - if v, ok := d.GetOk("node_properties"); ok { - props, err := expandJobNodeProperties(v.(string)) - if err != nil { - return sdkdiag.AppendFromErr(diags, err) + if v, ok := d.GetOk("eks_properties"); ok { + eksProps := v.([]interface{})[0].(map[string]interface{}) + if podProps, ok := eksProps["pod_properties"].([]interface{}); ok && len(podProps) > 0 { + props := expandEKSPodProperties(podProps[0].(map[string]interface{})) + input.EksProperties = &awstypes.EksProperties{ + PodProperties: props, + } + } } - for _, node := range props.NodeRangeProperties { - removeEmptyEnvironmentVariables(&diags, node.Container.Environment, cty.GetAttrPath("node_properties")) - } - input.NodeProperties = props - } + case awstypes.JobDefinitionTypeMultinode: + if v, ok := d.GetOk("node_properties"); ok { + props, err := expandJobNodeProperties(v.(string)) + if err != nil { + return sdkdiag.AppendFromErr(diags, err) + } - if v, ok := d.GetOk(names.AttrPropagateTags); ok { - input.PropagateTags = aws.Bool(v.(bool)) + for _, node := range props.NodeRangeProperties { + diags = append(diags, removeEmptyEnvironmentVariables(node.Container.Environment, cty.GetAttrPath("node_properties"))...) + } + input.NodeProperties = props + } } if v, ok := d.GetOk(names.AttrParameters); ok { @@ -835,14 +842,18 @@ func resourceJobDefinitionUpdate(ctx context.Context, d *schema.ResourceData, me input.PlatformCapabilities = flex.ExpandStringyValueSet[awstypes.PlatformCapability](v.(*schema.Set)) } - if v, ok := d.GetOk("scheduling_priority"); ok { - input.SchedulingPriority = aws.Int32(int32(v.(int))) + if v, ok := d.GetOk(names.AttrPropagateTags); ok { + input.PropagateTags = aws.Bool(v.(bool)) } if v, ok := d.GetOk("retry_strategy"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { input.RetryStrategy = expandRetryStrategy(v.([]interface{})[0].(map[string]interface{})) } + if v, ok := d.GetOk("scheduling_priority"); ok { + input.SchedulingPriority = aws.Int32(int32(v.(int))) + } + if v, ok := d.GetOk(names.AttrTimeout); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { input.Timeout = expandJobTimeout(v.([]interface{})[0].(map[string]interface{})) } @@ -1138,16 +1149,20 @@ func flattenJobTimeout(apiObject *awstypes.JobTimeout) map[string]interface{} { return tfMap } -func removeEmptyEnvironmentVariables(diags *diag.Diagnostics, environment []awstypes.KeyValuePair, attributePath cty.Path) { +func removeEmptyEnvironmentVariables(environment []awstypes.KeyValuePair, attributePath cty.Path) diag.Diagnostics { + var diags diag.Diagnostics + for _, env := range environment { if aws.ToString(env.Value) == "" { - *diags = append(*diags, errs.NewAttributeWarningDiagnostic( + diags = append(diags, errs.NewAttributeWarningDiagnostic( attributePath, "Ignoring environment variable", fmt.Sprintf("The environment variable %q has an empty value, which is ignored by the Batch service", aws.ToString(env.Name))), ) } } + + return diags } func expandEKSPodProperties(tfMap map[string]interface{}) *awstypes.EksPodProperties { From e35c0bd6cdf783013386fe3862ab82fe04ab75fe Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 15 Aug 2024 15:06:28 -0400 Subject: [PATCH 19/26] Add 'TestEquivalentECSPropertiesJSON'. --- internal/service/batch/ecs_properties.go | 78 +++++++++- internal/service/batch/ecs_properties_test.go | 147 ++++++++++++++++++ internal/service/batch/exports_test.go | 1 + 3 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 internal/service/batch/ecs_properties_test.go diff --git a/internal/service/batch/ecs_properties.go b/internal/service/batch/ecs_properties.go index 0a7a2945e2e..8f6f4c38ff1 100644 --- a/internal/service/batch/ecs_properties.go +++ b/internal/service/batch/ecs_properties.go @@ -1,17 +1,93 @@ package batch import ( + "sort" _ "unsafe" // Required for go:linkname + "github.com/aws/aws-sdk-go-v2/aws" _ "github.com/aws/aws-sdk-go-v2/service/batch" // Required for go:linkname awstypes "github.com/aws/aws-sdk-go-v2/service/batch/types" smithyjson "github.com/aws/smithy-go/encoding/json" tfjson "github.com/hashicorp/terraform-provider-aws/internal/json" + tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" ) -type ecsProperties awstypes.EcsProperties +type ecsProperties struct { + TaskProperties []*ecsTaskProperties +} func (ep *ecsProperties) reduce() { + for _, taskProp := range ep.TaskProperties { + taskProp.reduce() + } +} + +type ecsTaskProperties awstypes.EcsTaskProperties + +func (tp *ecsTaskProperties) reduce() { + tp.orderContainers() + + for i, c := range tp.Containers { + cp := taskContainerProperties(c) + pcp := &cp + pcp.reduce() + tp.Containers[i] = awstypes.TaskContainerProperties(cp) + } + + // Set all empty slices to nil. + if len(tp.Volumes) == 0 { + tp.Volumes = nil + } +} + +func (tp *ecsTaskProperties) orderContainers() { + sort.Slice(tp.Containers, func(i, j int) bool { + return aws.ToString(tp.Containers[i].Name) < aws.ToString(tp.Containers[j].Name) + }) +} + +type taskContainerProperties awstypes.TaskContainerProperties + +func (cp *taskContainerProperties) reduce() { + cp.orderEnvironmentVariables() + cp.orderSecrets() + + // Remove environment variables with empty values. + cp.Environment = tfslices.Filter(cp.Environment, func(kvp awstypes.KeyValuePair) bool { + return aws.ToString(kvp.Value) != "" + }) + + // Set all empty slices to nil. + if len(cp.Command) == 0 { + cp.Command = nil + } + if len(cp.DependsOn) == 0 { + cp.DependsOn = nil + } + if len(cp.Environment) == 0 { + cp.Environment = nil + } + if len(cp.MountPoints) == 0 { + cp.MountPoints = nil + } + if len(cp.Secrets) == 0 { + cp.Secrets = nil + } + if len(cp.Ulimits) == 0 { + cp.Ulimits = nil + } +} + +func (cp *taskContainerProperties) orderEnvironmentVariables() { + sort.Slice(cp.Environment, func(i, j int) bool { + return aws.ToString(cp.Environment[i].Name) < aws.ToString(cp.Environment[j].Name) + }) +} + +func (cp *taskContainerProperties) orderSecrets() { + sort.Slice(cp.Secrets, func(i, j int) bool { + return aws.ToString(cp.Secrets[i].Name) < aws.ToString(cp.Secrets[j].Name) + }) } func equivalentECSPropertiesJSON(str1, str2 string) (bool, error) { diff --git a/internal/service/batch/ecs_properties_test.go b/internal/service/batch/ecs_properties_test.go new file mode 100644 index 00000000000..0eb0833c394 --- /dev/null +++ b/internal/service/batch/ecs_properties_test.go @@ -0,0 +1,147 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package batch_test + +import ( + "testing" + + tfbatch "github.com/hashicorp/terraform-provider-aws/internal/service/batch" +) + +func TestEquivalentECSPropertiesJSON(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + ApiJson string + ConfigurationJson string + ExpectEquivalent bool + ExpectError bool + }{ + "empty": { + ApiJson: ``, + ConfigurationJson: ``, + ExpectEquivalent: true, + }, + "reordered containers": { + ApiJson: ` +{ + "taskProperties": [ + { + "containers": [ + { + "name": "container1", + "image": "my_ecr_image1" + }, + { + "name": "container2", + "image": "my_ecr_image2" + } + ] + } + ] + } + `, + ConfigurationJson: ` +{ + "taskProperties": [ + { + "containers": [ + { + "name": "container2", + "image": "my_ecr_image2" + }, + { + "name": "container1", + "image": "my_ecr_image1" + } + ] + } + ] + } + `, + ExpectEquivalent: true, + }, + "reordered environment": { + ApiJson: ` +{ + "taskProperties": [ + { + "containers": [ + { + "name": "container1", + "image": "my_ecr_image1", + "environment": [ + { + "name": "VARNAME1", + "value": "VARVAL1" + }, + { + "name": "VARNAME2", + "value": "VARVAL2" + } + ] + }, + { + "name": "container2", + "image": "my_ecr_image2", + "environment": [] + } + ] + } + ] +} + `, + ConfigurationJson: ` +{ + "taskProperties": [ + { + "containers": [ + { + "name": "container1", + "image": "my_ecr_image1", + "environment": [ + { + "name": "VARNAME2", + "value": "VARVAL2" + }, + { + "name": "VARNAME1", + "value": "VARVAL1" + } + ] + }, + { + "name": "container2", + "image": "my_ecr_image2" + } + ] + } + ] +} + `, + ExpectEquivalent: true, + }, + } + + for name, testCase := range testCases { + testCase := testCase + t.Run(name, func(t *testing.T) { + t.Parallel() + + got, err := tfbatch.EquivalentECSPropertiesJSON(testCase.ConfigurationJson, testCase.ApiJson) + + if err != nil && !testCase.ExpectError { + t.Errorf("got unexpected error: %s", err) + } + + if err == nil && testCase.ExpectError { + t.Errorf("expected error, but received none") + } + + if got != testCase.ExpectEquivalent { + t.Errorf("got %t, expected %t", got, testCase.ExpectEquivalent) + } + }) + } +} diff --git a/internal/service/batch/exports_test.go b/internal/service/batch/exports_test.go index a2fc1c4654f..38f831debeb 100644 --- a/internal/service/batch/exports_test.go +++ b/internal/service/batch/exports_test.go @@ -11,6 +11,7 @@ var ( ResourceSchedulingPolicy = resourceSchedulingPolicy EquivalentContainerPropertiesJSON = equivalentContainerPropertiesJSON + EquivalentECSPropertiesJSON = equivalentECSPropertiesJSON EquivalentNodePropertiesJSON = equivalentNodePropertiesJSON ExpandEC2ConfigurationsUpdate = expandEC2ConfigurationsUpdate ExpandLaunchTemplateSpecificationUpdate = expandLaunchTemplateSpecificationUpdate From d1210d6f63ab0816e7cf1a37bd69d0467abcb79c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 15 Aug 2024 15:57:57 -0400 Subject: [PATCH 20/26] Add 'TestAccBatchJobDefinition_ECSProperties_basic'. --- internal/service/batch/ecs_properties.go | 8 + internal/service/batch/job_definition.go | 3 +- internal/service/batch/job_definition_test.go | 137 ++++++++++++++++++ 3 files changed, 147 insertions(+), 1 deletion(-) diff --git a/internal/service/batch/ecs_properties.go b/internal/service/batch/ecs_properties.go index 8f6f4c38ff1..72aed963936 100644 --- a/internal/service/batch/ecs_properties.go +++ b/internal/service/batch/ecs_properties.go @@ -57,6 +57,11 @@ func (cp *taskContainerProperties) reduce() { return aws.ToString(kvp.Value) != "" }) + // Deal with special fields which have defaults. + if cp.Essential == nil { + cp.Essential = aws.Bool(true) + } + // Set all empty slices to nil. if len(cp.Command) == 0 { cp.Command = nil @@ -67,6 +72,9 @@ func (cp *taskContainerProperties) reduce() { if len(cp.Environment) == 0 { cp.Environment = nil } + if cp.LogConfiguration != nil && len(cp.LogConfiguration.SecretOptions) == 0 { + cp.LogConfiguration.SecretOptions = nil + } if len(cp.MountPoints) == 0 { cp.MountPoints = nil } diff --git a/internal/service/batch/job_definition.go b/internal/service/batch/job_definition.go index a42db21557b..3a03d9e9f9d 100644 --- a/internal/service/batch/job_definition.go +++ b/internal/service/batch/job_definition.go @@ -78,6 +78,7 @@ func resourceJobDefinition() *schema.Resource { }, "ecs_properties": { Type: schema.TypeString, + Optional: true, ConflictsWith: []string{"container_properties", "eks_properties", "node_properties"}, StateFunc: func(v interface{}) string { json, _ := structure.NormalizeJsonString(v) @@ -982,7 +983,7 @@ func validJobECSProperties(v interface{}, k string) (ws []string, errors []error value := v.(string) _, err := expandECSProperties(value) if err != nil { - errors = append(errors, fmt.Errorf("AWS Batch Job node_properties is invalid: %s", err)) + errors = append(errors, fmt.Errorf("AWS Batch Job ecs_properties is invalid: %s", err)) } return } diff --git a/internal/service/batch/job_definition_test.go b/internal/service/batch/job_definition_test.go index c201b6485cb..aaff1b195b1 100644 --- a/internal/service/batch/job_definition_test.go +++ b/internal/service/batch/job_definition_test.go @@ -54,6 +54,8 @@ func TestAccBatchJobDefinition_basic(t *testing.T) { "ulimits": [], "volumes": [] }`), + resource.TestCheckResourceAttr(resourceName, "ecs_properties", ""), + resource.TestCheckResourceAttr(resourceName, "eks_properties.#", acctest.Ct0), resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), resource.TestCheckResourceAttr(resourceName, "parameters.%", acctest.Ct0), resource.TestCheckResourceAttr(resourceName, "platform_capabilities.#", acctest.Ct0), @@ -976,6 +978,37 @@ func TestAccBatchJobDefinition_emptyRetryStrategy(t *testing.T) { }) } +func TestAccBatchJobDefinition_ECSProperties_basic(t *testing.T) { + ctx := acctest.Context(t) + var jd awstypes.JobDefinition + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_batch_job_definition.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.BatchServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckJobDefinitionDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccJobDefinitionConfig_ECSProperties_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckJobDefinitionExists(ctx, resourceName, &jd), + resource.TestCheckResourceAttrSet(resourceName, "ecs_properties"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "deregister_on_new_revision", + }, + }, + }, + }) +} + func testAccCheckJobDefinitionExists(ctx context.Context, n string, v *awstypes.JobDefinition) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -1894,3 +1927,107 @@ resource "aws_batch_job_definition" "test" { } `, rName) } + +func testAccJobDefinitionConfig_ECSProperties_basic(rName string) string { + return fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_iam_role" "ecs_task_execution_role" { + name = %[1]q + assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json +} + +data "aws_iam_policy_document" "assume_role_policy" { + statement { + actions = ["sts:AssumeRole"] + + principals { + type = "Service" + identifiers = ["ecs-tasks.amazonaws.com"] + } + } +} + +resource "aws_iam_role_policy_attachment" "ecs_task_execution_role_policy" { + role = aws_iam_role.ecs_task_execution_role.name + policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" +} + +resource "aws_batch_job_definition" "test" { + name = %[1]q + type = "container" + + platform_capabilities = ["FARGATE"] + + ecs_properties = jsonencode({ + taskProperties = [ + { + executionRoleArn = aws_iam_role.ecs_task_execution_role.arn + containers = [ + { + image = "public.ecr.aws/amazonlinux/amazonlinux:1" + command = ["sleep", "60"] + dependsOn = [ + { + containerName = "container_b" + condition = "COMPLETE" + } + ] + secrets = [ + { + name = "TEST" + valueFrom = "DUMMY" + } + ] + environment = [ + { + name = "test" + value = "Environment Variable" + } + ] + essential = true + logConfiguration = { + logDriver = "awslogs" + options = { + "awslogs-group" = %[1]q + "awslogs-region" = %[2]q + "awslogs-stream-prefix" = "ecs" + } + } + name = "container_a" + privileged = false + readonlyRootFilesystem = false + resourceRequirements = [ + { + value = "1.0" + type = "VCPU" + }, + { + value = "2048" + type = "MEMORY" + } + ] + }, + { + image = "public.ecr.aws/amazonlinux/amazonlinux:1" + command = ["sleep", "360"] + name = "container_b" + essential = false + resourceRequirements = [ + { + value = "1.0" + type = "VCPU" + }, + { + value = "2048" + type = "MEMORY" + } + ] + } + ] + } + ] + }) +} +`, rName, acctest.Region()) +} From 3b3722690e4cff7acf185b80895f6cb31328da10 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 16 Aug 2024 11:59:04 -0400 Subject: [PATCH 21/26] r/aws_batch_job_definitions: Fixup normalization of 'ecs_properties'. --- .../service/batch/container_properties.go | 6 +- internal/service/batch/ecs_properties.go | 143 ++++++------ internal/service/batch/ecs_properties_test.go | 217 ++++++++++++++++-- internal/service/batch/job_definition.go | 12 +- 4 files changed, 279 insertions(+), 99 deletions(-) diff --git a/internal/service/batch/container_properties.go b/internal/service/batch/container_properties.go index b201a609948..d3f8ca74e65 100644 --- a/internal/service/batch/container_properties.go +++ b/internal/service/batch/container_properties.go @@ -15,6 +15,10 @@ import ( tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" ) +const ( + fargatePlatformVersionLatest = "LATEST" +) + type containerProperties awstypes.ContainerProperties func (cp *containerProperties) reduce() { @@ -40,7 +44,7 @@ func (cp *containerProperties) reduce() { // Prevent difference of API response that contains the default Fargate platform configuration. if cp.FargatePlatformConfiguration != nil { - if aws.ToString(cp.FargatePlatformConfiguration.PlatformVersion) == "LATEST" { + if aws.ToString(cp.FargatePlatformConfiguration.PlatformVersion) == fargatePlatformVersionLatest { cp.FargatePlatformConfiguration = nil } } diff --git a/internal/service/batch/ecs_properties.go b/internal/service/batch/ecs_properties.go index 72aed963936..3f8838e65a6 100644 --- a/internal/service/batch/ecs_properties.go +++ b/internal/service/batch/ecs_properties.go @@ -12,90 +12,95 @@ import ( tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" ) -type ecsProperties struct { - TaskProperties []*ecsTaskProperties -} +type ecsProperties awstypes.EcsProperties func (ep *ecsProperties) reduce() { - for _, taskProp := range ep.TaskProperties { - taskProp.reduce() - } -} - -type ecsTaskProperties awstypes.EcsTaskProperties - -func (tp *ecsTaskProperties) reduce() { - tp.orderContainers() - - for i, c := range tp.Containers { - cp := taskContainerProperties(c) - pcp := &cp - pcp.reduce() - tp.Containers[i] = awstypes.TaskContainerProperties(cp) - } + ep.orderContainers() + ep.orderEnvironmentVariables() + ep.orderSecrets() // Set all empty slices to nil. - if len(tp.Volumes) == 0 { - tp.Volumes = nil + // Deal with special fields which have defaults. + for i, taskProps := range ep.TaskProperties { + for j, container := range taskProps.Containers { + if container.Essential == nil { + container.Essential = aws.Bool(true) + } + + if len(container.Command) == 0 { + container.Command = nil + } + if len(container.DependsOn) == 0 { + container.DependsOn = nil + } + if len(container.Environment) == 0 { + container.Environment = nil + } + if container.LogConfiguration != nil && len(container.LogConfiguration.SecretOptions) == 0 { + container.LogConfiguration.SecretOptions = nil + } + if len(container.MountPoints) == 0 { + container.MountPoints = nil + } + if len(container.Secrets) == 0 { + container.Secrets = nil + } + if len(container.Ulimits) == 0 { + container.Ulimits = nil + } + + taskProps.Containers[j] = container + } + + if taskProps.PlatformVersion == nil { + taskProps.PlatformVersion = aws.String(fargatePlatformVersionLatest) + } + + if len(taskProps.Volumes) == 0 { + taskProps.Volumes = nil + } + + ep.TaskProperties[i] = taskProps } } -func (tp *ecsTaskProperties) orderContainers() { - sort.Slice(tp.Containers, func(i, j int) bool { - return aws.ToString(tp.Containers[i].Name) < aws.ToString(tp.Containers[j].Name) - }) -} +func (ep *ecsProperties) orderContainers() { + for i, taskProps := range ep.TaskProperties { + sort.Slice(taskProps.Containers, func(i, j int) bool { + return aws.ToString(taskProps.Containers[i].Name) < aws.ToString(taskProps.Containers[j].Name) + }) -type taskContainerProperties awstypes.TaskContainerProperties + ep.TaskProperties[i].Containers = taskProps.Containers + } +} -func (cp *taskContainerProperties) reduce() { - cp.orderEnvironmentVariables() - cp.orderSecrets() +func (ep *ecsProperties) orderEnvironmentVariables() { + for i, taskProps := range ep.TaskProperties { + for j, container := range taskProps.Containers { + // Remove environment variables with empty values. + container.Environment = tfslices.Filter(container.Environment, func(kvp awstypes.KeyValuePair) bool { + return aws.ToString(kvp.Value) != "" + }) - // Remove environment variables with empty values. - cp.Environment = tfslices.Filter(cp.Environment, func(kvp awstypes.KeyValuePair) bool { - return aws.ToString(kvp.Value) != "" - }) + sort.Slice(container.Environment, func(i, j int) bool { + return aws.ToString(container.Environment[i].Name) < aws.ToString(container.Environment[j].Name) + }) - // Deal with special fields which have defaults. - if cp.Essential == nil { - cp.Essential = aws.Bool(true) - } - - // Set all empty slices to nil. - if len(cp.Command) == 0 { - cp.Command = nil - } - if len(cp.DependsOn) == 0 { - cp.DependsOn = nil - } - if len(cp.Environment) == 0 { - cp.Environment = nil - } - if cp.LogConfiguration != nil && len(cp.LogConfiguration.SecretOptions) == 0 { - cp.LogConfiguration.SecretOptions = nil - } - if len(cp.MountPoints) == 0 { - cp.MountPoints = nil - } - if len(cp.Secrets) == 0 { - cp.Secrets = nil - } - if len(cp.Ulimits) == 0 { - cp.Ulimits = nil + ep.TaskProperties[i].Containers[j].Environment = container.Environment + } } } -func (cp *taskContainerProperties) orderEnvironmentVariables() { - sort.Slice(cp.Environment, func(i, j int) bool { - return aws.ToString(cp.Environment[i].Name) < aws.ToString(cp.Environment[j].Name) - }) -} +func (ep *ecsProperties) orderSecrets() { + for i, taskProps := range ep.TaskProperties { + for j, container := range taskProps.Containers { + sort.Slice(container.Secrets, func(i, j int) bool { + return aws.ToString(container.Secrets[i].Name) < aws.ToString(container.Secrets[j].Name) + }) -func (cp *taskContainerProperties) orderSecrets() { - sort.Slice(cp.Secrets, func(i, j int) bool { - return aws.ToString(cp.Secrets[i].Name) < aws.ToString(cp.Secrets[j].Name) - }) + ep.TaskProperties[i].Containers[j].Secrets = container.Secrets + } + } } func equivalentECSPropertiesJSON(str1, str2 string) (bool, error) { diff --git a/internal/service/batch/ecs_properties_test.go b/internal/service/batch/ecs_properties_test.go index 0eb0833c394..553831bfe13 100644 --- a/internal/service/batch/ecs_properties_test.go +++ b/internal/service/batch/ecs_properties_test.go @@ -6,6 +6,8 @@ package batch_test import ( "testing" + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-provider-aws/internal/acctest/jsoncmp" tfbatch "github.com/hashicorp/terraform-provider-aws/internal/service/batch" ) @@ -13,18 +15,18 @@ func TestEquivalentECSPropertiesJSON(t *testing.T) { t.Parallel() testCases := map[string]struct { - ApiJson string - ConfigurationJson string - ExpectEquivalent bool - ExpectError bool + apiJSON string + configurationJSON string + wantEquivalent bool + wantErr bool }{ "empty": { - ApiJson: ``, - ConfigurationJson: ``, - ExpectEquivalent: true, + apiJSON: ``, + configurationJSON: ``, + wantEquivalent: true, }, "reordered containers": { - ApiJson: ` + apiJSON: ` { "taskProperties": [ { @@ -42,7 +44,7 @@ func TestEquivalentECSPropertiesJSON(t *testing.T) { ] } `, - ConfigurationJson: ` + configurationJSON: ` { "taskProperties": [ { @@ -60,10 +62,10 @@ func TestEquivalentECSPropertiesJSON(t *testing.T) { ] } `, - ExpectEquivalent: true, + wantEquivalent: true, }, "reordered environment": { - ApiJson: ` + apiJSON: ` { "taskProperties": [ { @@ -92,7 +94,7 @@ func TestEquivalentECSPropertiesJSON(t *testing.T) { ] } `, - ConfigurationJson: ` + configurationJSON: ` { "taskProperties": [ { @@ -120,7 +122,174 @@ func TestEquivalentECSPropertiesJSON(t *testing.T) { ] } `, - ExpectEquivalent: true, + wantEquivalent: true, + }, + "full": { + apiJSON: ` +{ + "taskProperties": [ + { + "containers": [ + { + "command": [ + "sleep", + "60" + ], + "dependsOn": [ + { + "condition": "COMPLETE", + "containerName": "container_b" + } + ], + "environment": [ + { + "name": "test", + "value": "Environment Variable" + } + ], + "essential": true, + "image": "public.ecr.aws/amazonlinux/amazonlinux:1", + "logConfiguration": { + "logDriver": "awslogs", + "options": { + "awslogs-stream-prefix": "ecs", + "awslogs-group": "ewbankkit-test-003", + "awslogs-region": "us-west-2" + }, + "secretOptions": [] + }, + "mountPoints": [], + "name": "container_a", + "privileged": false, + "readonlyRootFilesystem": false, + "resourceRequirements": [ + { + "type": "VCPU", + "value": "1.0" + }, + { + "type": "MEMORY", + "value": "2048" + } + ], + "secrets": [ + { + "name": "TEST", + "valueFrom": "DUMMY" + } + ], + "ulimits": [] + }, + { + "command": [ + "sleep", + "360" + ], + "dependsOn": [], + "environment": [], + "essential": false, + "image": "public.ecr.aws/amazonlinux/amazonlinux:1", + "mountPoints": [], + "name": "container_b", + "resourceRequirements": [ + { + "type": "VCPU", + "value": "1.0" + }, + { + "type": "MEMORY", + "value": "2048" + } + ], + "secrets": [], + "ulimits": [] + } + ], + "executionRoleArn": "arn:aws:iam::187416307283:role/ewbankkit-test-003", + "platformVersion": "LATEST", + "volumes": [] + } + ] +} + `, + configurationJSON: ` +{ + "taskProperties": [ + { + "containers": [ + { + "command": [ + "sleep", + "60" + ], + "dependsOn": [ + { + "condition": "COMPLETE", + "containerName": "container_b" + } + ], + "environment": [ + { + "name": "test", + "value": "Environment Variable" + } + ], + "essential": true, + "image": "public.ecr.aws/amazonlinux/amazonlinux:1", + "logConfiguration": { + "logDriver": "awslogs", + "options": { + "awslogs-group": "ewbankkit-test-003", + "awslogs-region": "us-west-2", + "awslogs-stream-prefix": "ecs" + } + }, + "name": "container_a", + "privileged": false, + "readonlyRootFilesystem": false, + "resourceRequirements": [ + { + "type": "VCPU", + "value": "1.0" + }, + { + "type": "MEMORY", + "value": "2048" + } + ], + "secrets": [ + { + "name": "TEST", + "valueFrom": "DUMMY" + } + ] + }, + { + "command": [ + "sleep", + "360" + ], + "essential": false, + "image": "public.ecr.aws/amazonlinux/amazonlinux:1", + "name": "container_b", + "resourceRequirements": [ + { + "type": "VCPU", + "value": "1.0" + }, + { + "type": "MEMORY", + "value": "2048" + } + ] + } + ], + "executionRoleArn": "arn:aws:iam::187416307283:role/ewbankkit-test-003" + } + ] +} + `, + wantEquivalent: true, }, } @@ -129,18 +298,20 @@ func TestEquivalentECSPropertiesJSON(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, err := tfbatch.EquivalentECSPropertiesJSON(testCase.ConfigurationJson, testCase.ApiJson) - - if err != nil && !testCase.ExpectError { - t.Errorf("got unexpected error: %s", err) - } - - if err == nil && testCase.ExpectError { - t.Errorf("expected error, but received none") + output, err := tfbatch.EquivalentECSPropertiesJSON(testCase.configurationJSON, testCase.apiJSON) + if got, want := err != nil, testCase.wantErr; !cmp.Equal(got, want) { + t.Errorf("EquivalentECSPropertiesJSON err %t, want %t", got, want) } - if got != testCase.ExpectEquivalent { - t.Errorf("got %t, expected %t", got, testCase.ExpectEquivalent) + if err == nil { + if got, want := output, testCase.wantEquivalent; !cmp.Equal(got, want) { + t.Errorf("EquivalentECSPropertiesJSON equivalent %t, want %t", got, want) + if want { + if diff := jsoncmp.Diff(testCase.configurationJSON, testCase.apiJSON); diff != "" { + t.Errorf("unexpected diff (+wanted, -got): %s", diff) + } + } + } } }) } diff --git a/internal/service/batch/job_definition.go b/internal/service/batch/job_definition.go index 3a03d9e9f9d..a9671f441ad 100644 --- a/internal/service/batch/job_definition.go +++ b/internal/service/batch/job_definition.go @@ -634,9 +634,9 @@ func resourceJobDefinitionCreate(ctx context.Context, d *schema.ResourceData, me return sdkdiag.AppendFromErr(diags, err) } - for _, taskProp := range props.TaskProperties { - for _, c := range taskProp.Containers { - diags = append(diags, removeEmptyEnvironmentVariables(c.Environment, cty.GetAttrPath("ecs_properties"))...) + for _, taskProps := range props.TaskProperties { + for _, container := range taskProps.Containers { + diags = append(diags, removeEmptyEnvironmentVariables(container.Environment, cty.GetAttrPath("ecs_properties"))...) } } input.EcsProperties = props @@ -803,9 +803,9 @@ func resourceJobDefinitionUpdate(ctx context.Context, d *schema.ResourceData, me return sdkdiag.AppendFromErr(diags, err) } - for _, taskProp := range props.TaskProperties { - for _, c := range taskProp.Containers { - diags = append(diags, removeEmptyEnvironmentVariables(c.Environment, cty.GetAttrPath("ecs_properties"))...) + for _, taskProps := range props.TaskProperties { + for _, container := range taskProps.Containers { + diags = append(diags, removeEmptyEnvironmentVariables(container.Environment, cty.GetAttrPath("ecs_properties"))...) } } input.EcsProperties = props From ac79175a751d85d9132f9c0327afcb8cfd0d1c73 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 16 Aug 2024 12:04:29 -0400 Subject: [PATCH 22/26] Use 'jsoncmp' in unit tests. --- .../batch/container_properties_test.go | 92 ++++++++++--------- .../service/batch/node_properties_test.go | 50 +++++----- 2 files changed, 75 insertions(+), 67 deletions(-) diff --git a/internal/service/batch/container_properties_test.go b/internal/service/batch/container_properties_test.go index 4038a34e081..7a68ba0aa73 100644 --- a/internal/service/batch/container_properties_test.go +++ b/internal/service/batch/container_properties_test.go @@ -6,6 +6,8 @@ package batch_test import ( "testing" + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-provider-aws/internal/acctest/jsoncmp" tfbatch "github.com/hashicorp/terraform-provider-aws/internal/service/batch" ) @@ -13,18 +15,18 @@ func TestEquivalentContainerPropertiesJSON(t *testing.T) { t.Parallel() testCases := map[string]struct { - ApiJson string - ConfigurationJson string - ExpectEquivalent bool - ExpectError bool + apiJSON string + configurationJSON string + wantEquivalent bool + wantErr bool }{ "empty": { - ApiJson: ``, - ConfigurationJson: ``, - ExpectEquivalent: true, + apiJSON: ``, + configurationJSON: ``, + wantEquivalent: true, }, "empty ResourceRequirements": { - ApiJson: ` + apiJSON: ` { "command": ["ls", "-la"], "environment": [ @@ -61,7 +63,7 @@ func TestEquivalentContainerPropertiesJSON(t *testing.T) { ] } `, - ConfigurationJson: ` + configurationJSON: ` { "command": ["ls", "-la"], "environment": [ @@ -97,10 +99,10 @@ func TestEquivalentContainerPropertiesJSON(t *testing.T) { ] } `, - ExpectEquivalent: true, + wantEquivalent: true, }, "reordered Environment": { - ApiJson: ` + apiJSON: ` { "command": ["ls", "-la"], "environment": [ @@ -141,7 +143,7 @@ func TestEquivalentContainerPropertiesJSON(t *testing.T) { ] } `, - ConfigurationJson: ` + configurationJSON: ` { "command": ["ls", "-la"], "environment": [ @@ -182,11 +184,11 @@ func TestEquivalentContainerPropertiesJSON(t *testing.T) { ] } `, - ExpectEquivalent: true, + wantEquivalent: true, }, "empty environment, mountPoints, ulimits, and volumes": { //lintignore:AWSAT005 - ApiJson: ` + apiJSON: ` { "image": "example:image", "vcpus": 8, @@ -201,7 +203,7 @@ func TestEquivalentContainerPropertiesJSON(t *testing.T) { } `, //lintignore:AWSAT005 - ConfigurationJson: ` + configurationJSON: ` { "command": ["start.py", "Ref::S3bucket", "Ref::S3key"], "image": "example:image", @@ -210,11 +212,11 @@ func TestEquivalentContainerPropertiesJSON(t *testing.T) { "jobRoleArn": "arn:aws:iam::123456789012:role/example" } `, - ExpectEquivalent: true, + wantEquivalent: true, }, "empty command, logConfiguration.secretOptions, mountPoints, resourceRequirements, secrets, ulimits, volumes": { //lintignore:AWSAT003,AWSAT005 - ApiJson: ` + apiJSON: ` { "image": "123.dkr.ecr.us-east-1.amazonaws.com/my-app", "vcpus": 1, @@ -234,7 +236,7 @@ func TestEquivalentContainerPropertiesJSON(t *testing.T) { } `, //lintignore:AWSAT003,AWSAT005 - ConfigurationJson: ` + configurationJSON: ` { "image": "123.dkr.ecr.us-east-1.amazonaws.com/my-app", "memory": 4096, @@ -251,11 +253,11 @@ func TestEquivalentContainerPropertiesJSON(t *testing.T) { } } `, - ExpectEquivalent: true, + wantEquivalent: true, }, "no fargatePlatformConfiguration": { //lintignore:AWSAT003,AWSAT005 - ApiJson: ` + apiJSON: ` { "image": "123.dkr.ecr.us-east-1.amazonaws.com/my-app", "resourceRequirements": [ @@ -274,7 +276,7 @@ func TestEquivalentContainerPropertiesJSON(t *testing.T) { } `, //lintignore:AWSAT003,AWSAT005 - ConfigurationJson: ` + configurationJSON: ` { "image": "123.dkr.ecr.us-east-1.amazonaws.com/my-app", "resourceRequirements": [ @@ -289,11 +291,11 @@ func TestEquivalentContainerPropertiesJSON(t *testing.T) { ] } `, - ExpectEquivalent: true, + wantEquivalent: true, }, "empty linuxParameters.devices, linuxParameters.tmpfs, logConfiguration.options": { //lintignore:AWSAT003,AWSAT005 - ApiJson: ` + apiJSON: ` { "image": "123.dkr.ecr.us-east-1.amazonaws.com/my-app", "vcpus": 1, @@ -312,7 +314,7 @@ func TestEquivalentContainerPropertiesJSON(t *testing.T) { } `, //lintignore:AWSAT003,AWSAT005 - ConfigurationJson: ` + configurationJSON: ` { "image": "123.dkr.ecr.us-east-1.amazonaws.com/my-app", "vcpus": 1, @@ -327,11 +329,11 @@ func TestEquivalentContainerPropertiesJSON(t *testing.T) { } } `, - ExpectEquivalent: true, + wantEquivalent: true, }, "empty linuxParameters.devices.permissions, linuxParameters.tmpfs.mountOptions": { //lintignore:AWSAT003,AWSAT005 - ApiJson: ` + apiJSON: ` { "image": "123.dkr.ecr.us-east-1.amazonaws.com/my-app", "vcpus": 1, @@ -354,7 +356,7 @@ func TestEquivalentContainerPropertiesJSON(t *testing.T) { } `, //lintignore:AWSAT003,AWSAT005 - ConfigurationJson: ` + configurationJSON: ` { "image": "123.dkr.ecr.us-east-1.amazonaws.com/my-app", "vcpus": 1, @@ -374,11 +376,11 @@ func TestEquivalentContainerPropertiesJSON(t *testing.T) { } } `, - ExpectEquivalent: true, + wantEquivalent: true, }, "empty environment variables": { //lintignore:AWSAT005 - ApiJson: ` + apiJSON: ` { "image": "example:image", "vcpus": 8, @@ -397,7 +399,7 @@ func TestEquivalentContainerPropertiesJSON(t *testing.T) { "resourceRequirements": [] }`, //lintignore:AWSAT005 - ConfigurationJson: ` + configurationJSON: ` { "command": ["start.py", "Ref::S3bucket", "Ref::S3key"], "image": "example:image", @@ -415,11 +417,11 @@ func TestEquivalentContainerPropertiesJSON(t *testing.T) { ], "jobRoleArn": "arn:aws:iam::123456789012:role/example" }`, - ExpectEquivalent: true, + wantEquivalent: true, }, "empty environment variable": { //lintignore:AWSAT005 - ApiJson: ` + apiJSON: ` { "image": "example:image", "vcpus": 8, @@ -433,7 +435,7 @@ func TestEquivalentContainerPropertiesJSON(t *testing.T) { "resourceRequirements": [] }`, //lintignore:AWSAT005 - ConfigurationJson: ` + configurationJSON: ` { "command": ["start.py", "Ref::S3bucket", "Ref::S3key"], "image": "example:image", @@ -447,7 +449,7 @@ func TestEquivalentContainerPropertiesJSON(t *testing.T) { ], "jobRoleArn": "arn:aws:iam::123456789012:role/example" }`, - ExpectEquivalent: true, + wantEquivalent: true, }, } @@ -456,18 +458,20 @@ func TestEquivalentContainerPropertiesJSON(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, err := tfbatch.EquivalentContainerPropertiesJSON(testCase.ConfigurationJson, testCase.ApiJson) - - if err != nil && !testCase.ExpectError { - t.Errorf("got unexpected error: %s", err) - } - - if err == nil && testCase.ExpectError { - t.Errorf("expected error, but received none") + output, err := tfbatch.EquivalentContainerPropertiesJSON(testCase.configurationJSON, testCase.apiJSON) + if got, want := err != nil, testCase.wantErr; !cmp.Equal(got, want) { + t.Errorf("EquivalentContainerPropertiesJSON err %t, want %t", got, want) } - if got != testCase.ExpectEquivalent { - t.Errorf("got %t, expected %t", got, testCase.ExpectEquivalent) + if err == nil { + if got, want := output, testCase.wantEquivalent; !cmp.Equal(got, want) { + t.Errorf("EquivalentContainerPropertiesJSON equivalent %t, want %t", got, want) + if want { + if diff := jsoncmp.Diff(testCase.configurationJSON, testCase.apiJSON); diff != "" { + t.Errorf("unexpected diff (+wanted, -got): %s", diff) + } + } + } } }) } diff --git a/internal/service/batch/node_properties_test.go b/internal/service/batch/node_properties_test.go index e47bfd53fef..7e09f08080b 100644 --- a/internal/service/batch/node_properties_test.go +++ b/internal/service/batch/node_properties_test.go @@ -6,6 +6,8 @@ package batch_test import ( "testing" + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-provider-aws/internal/acctest/jsoncmp" tfbatch "github.com/hashicorp/terraform-provider-aws/internal/service/batch" ) @@ -13,18 +15,18 @@ func TestEquivalentNodePropertiesJSON(t *testing.T) { t.Parallel() testCases := map[string]struct { - ApiJson string - ConfigurationJson string - ExpectEquivalent bool - ExpectError bool + apiJSON string + configurationJSON string + wantEquivalent bool + wantErr bool }{ "empty": { - ApiJson: ``, - ConfigurationJson: ``, - ExpectEquivalent: true, + apiJSON: ``, + configurationJSON: ``, + wantEquivalent: true, }, "Single Node with empty environment variable": { - ApiJson: ` + apiJSON: ` { "mainNode": 1, "nodeRangeProperties": [ @@ -42,7 +44,7 @@ func TestEquivalentNodePropertiesJSON(t *testing.T) { "numNodes": 2 } `, - ConfigurationJson: ` + configurationJSON: ` { "mainNode": 1, "nodeRangeProperties": [ @@ -65,10 +67,10 @@ func TestEquivalentNodePropertiesJSON(t *testing.T) { "numNodes": 2 } `, - ExpectEquivalent: true, + wantEquivalent: true, }, "Two Nodes with empty command and mountPoints": { - ApiJson: ` + apiJSON: ` { "mainNode": 1, "nodeRangeProperties": [ @@ -99,7 +101,7 @@ func TestEquivalentNodePropertiesJSON(t *testing.T) { "numNodes": 2 } `, - ConfigurationJson: ` + configurationJSON: ` { "mainNode": 1, "nodeRangeProperties": [ @@ -130,7 +132,7 @@ func TestEquivalentNodePropertiesJSON(t *testing.T) { "numNodes": 2 } `, - ExpectEquivalent: true, + wantEquivalent: true, }, } @@ -139,18 +141,20 @@ func TestEquivalentNodePropertiesJSON(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, err := tfbatch.EquivalentNodePropertiesJSON(testCase.ConfigurationJson, testCase.ApiJson) - - if err != nil && !testCase.ExpectError { - t.Errorf("got unexpected error: %s", err) - } - - if err == nil && testCase.ExpectError { - t.Errorf("expected error, but received none") + output, err := tfbatch.EquivalentNodePropertiesJSON(testCase.configurationJSON, testCase.apiJSON) + if got, want := err != nil, testCase.wantErr; !cmp.Equal(got, want) { + t.Errorf("EquivalentNodePropertiesJSON err %t, want %t", got, want) } - if got != testCase.ExpectEquivalent { - t.Errorf("got %t, expected %t", got, testCase.ExpectEquivalent) + if err == nil { + if got, want := output, testCase.wantEquivalent; !cmp.Equal(got, want) { + t.Errorf("EquivalentNodePropertiesJSON equivalent %t, want %t", got, want) + if want { + if diff := jsoncmp.Diff(testCase.configurationJSON, testCase.apiJSON); diff != "" { + t.Errorf("unexpected diff (+wanted, -got): %s", diff) + } + } + } } }) } From f964e4f4a028a05df2b62230465f512b5ff15c2a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 16 Aug 2024 12:17:34 -0400 Subject: [PATCH 23/26] 'TestAccBatchJobDefinition_ECSProperties_basic' -> 'TestAccBatchJobDefinition_ECSProperties_update'. --- internal/service/batch/job_definition_test.go | 127 +++++++++++++++++- 1 file changed, 120 insertions(+), 7 deletions(-) diff --git a/internal/service/batch/job_definition_test.go b/internal/service/batch/job_definition_test.go index aaff1b195b1..0f217b2267a 100644 --- a/internal/service/batch/job_definition_test.go +++ b/internal/service/batch/job_definition_test.go @@ -978,7 +978,7 @@ func TestAccBatchJobDefinition_emptyRetryStrategy(t *testing.T) { }) } -func TestAccBatchJobDefinition_ECSProperties_basic(t *testing.T) { +func TestAccBatchJobDefinition_ECSProperties_update(t *testing.T) { ctx := acctest.Context(t) var jd awstypes.JobDefinition rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -995,15 +995,20 @@ func TestAccBatchJobDefinition_ECSProperties_basic(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( testAccCheckJobDefinitionExists(ctx, resourceName, &jd), resource.TestCheckResourceAttrSet(resourceName, "ecs_properties"), + acctest.CheckResourceAttrJMES(resourceName, "ecs_properties", "length(taskProperties)", acctest.Ct1), + acctest.CheckResourceAttrJMES(resourceName, "ecs_properties", "length(taskProperties[0].containers)", acctest.Ct2), + acctest.CheckResourceAttrJMES(resourceName, "ecs_properties", "length(taskProperties[0].containers[0].environment)", acctest.Ct1), ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "deregister_on_new_revision", - }, + Config: testAccJobDefinitionConfig_ECSProperties_updated(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckJobDefinitionExists(ctx, resourceName, &jd), + resource.TestCheckResourceAttrSet(resourceName, "ecs_properties"), + acctest.CheckResourceAttrJMES(resourceName, "ecs_properties", "length(taskProperties)", acctest.Ct1), + acctest.CheckResourceAttrJMES(resourceName, "ecs_properties", "length(taskProperties[0].containers)", acctest.Ct2), + acctest.CheckResourceAttrJMES(resourceName, "ecs_properties", "length(taskProperties[0].containers[0].environment)", acctest.Ct2), + ), }, }, }) @@ -2031,3 +2036,111 @@ resource "aws_batch_job_definition" "test" { } `, rName, acctest.Region()) } + +func testAccJobDefinitionConfig_ECSProperties_updated(rName string) string { + return fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_iam_role" "ecs_task_execution_role" { + name = %[1]q + assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json +} + +data "aws_iam_policy_document" "assume_role_policy" { + statement { + actions = ["sts:AssumeRole"] + + principals { + type = "Service" + identifiers = ["ecs-tasks.amazonaws.com"] + } + } +} + +resource "aws_iam_role_policy_attachment" "ecs_task_execution_role_policy" { + role = aws_iam_role.ecs_task_execution_role.name + policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" +} + +resource "aws_batch_job_definition" "test" { + name = %[1]q + type = "container" + + platform_capabilities = ["FARGATE"] + + ecs_properties = jsonencode({ + taskProperties = [ + { + executionRoleArn = aws_iam_role.ecs_task_execution_role.arn + containers = [ + { + image = "public.ecr.aws/amazonlinux/amazonlinux:1" + command = ["sleep", "60"] + dependsOn = [ + { + containerName = "container_b" + condition = "COMPLETE" + } + ] + secrets = [ + { + name = "TEST" + valueFrom = "DUMMY" + } + ] + environment = [ + { + name = "test 1" + value = "Environment Variable 1" + }, + { + name = "test 2" + value = "Environment Variable 2" + } + ] + essential = true + logConfiguration = { + logDriver = "awslogs" + options = { + "awslogs-group" = %[1]q + "awslogs-region" = %[2]q + "awslogs-stream-prefix" = "ecs" + } + } + name = "container_a" + privileged = false + readonlyRootFilesystem = false + resourceRequirements = [ + { + value = "1.0" + type = "VCPU" + }, + { + value = "2048" + type = "MEMORY" + } + ] + }, + { + image = "public.ecr.aws/amazonlinux/amazonlinux:1" + command = ["sleep", "360"] + name = "container_b" + essential = false + resourceRequirements = [ + { + value = "1.0" + type = "VCPU" + }, + { + value = "2048" + type = "MEMORY" + } + ] + } + ] + } + ] + }) +} +`, rName, acctest.Region()) +} From 15a70ad309a70cf436d20991ab1fd7b101dedc5b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 16 Aug 2024 12:21:52 -0400 Subject: [PATCH 24/26] r/aws_batch_job_definition: Documentation example of 'ecs_properties'. --- .../docs/r/batch_job_definition.html.markdown | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/website/docs/r/batch_job_definition.html.markdown b/website/docs/r/batch_job_definition.html.markdown index e518d4c02a3..09936a3bcbd 100644 --- a/website/docs/r/batch_job_definition.html.markdown +++ b/website/docs/r/batch_job_definition.html.markdown @@ -191,6 +191,87 @@ resource "aws_batch_job_definition" "test" { } ``` +### Job definition of type container using `ecs_properties` + +```terraform +resource "aws_batch_job_definition" "test" { + name = "tf_test_batch_job_definition" + type = "container" + + platform_capabilities = ["FARGATE"] + + ecs_properties = jsonencode({ + taskProperties = [ + { + executionRoleArn = aws_iam_role.ecs_task_execution_role.arn + containers = [ + { + image = "public.ecr.aws/amazonlinux/amazonlinux:1" + command = ["sleep", "60"] + dependsOn = [ + { + containerName = "container_b" + condition = "COMPLETE" + } + ] + secrets = [ + { + name = "TEST" + valueFrom = "DUMMY" + } + ] + environment = [ + { + name = "test" + value = "Environment Variable" + } + ] + essential = true + logConfiguration = { + logDriver = "awslogs" + options = { + "awslogs-group" = "tf_test_batch_job" + "awslogs-region" = "us-west-2" + "awslogs-stream-prefix" = "ecs" + } + } + name = "container_a" + privileged = false + readonlyRootFilesystem = false + resourceRequirements = [ + { + value = "1.0" + type = "VCPU" + }, + { + value = "2048" + type = "MEMORY" + } + ] + }, + { + image = "public.ecr.aws/amazonlinux/amazonlinux:1" + command = ["sleep", "360"] + name = "container_b" + essential = false + resourceRequirements = [ + { + value = "1.0" + type = "VCPU" + }, + { + value = "2048" + type = "MEMORY" + } + ] + } + ] + } + ] + }) +} +``` + ## Argument Reference The following arguments are required: From 4955f8b8c7f2f1389ce256ba6d7f8b3d9f874e08 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 16 Aug 2024 12:28:23 -0400 Subject: [PATCH 25/26] Add copyright headers. --- internal/service/batch/ecs_properties.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/service/batch/ecs_properties.go b/internal/service/batch/ecs_properties.go index 3f8838e65a6..b6c317c1934 100644 --- a/internal/service/batch/ecs_properties.go +++ b/internal/service/batch/ecs_properties.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package batch import ( From cc5762c4a652db2081b93f49731f984879df671b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 16 Aug 2024 13:04:05 -0400 Subject: [PATCH 26/26] Fix providerlint AWSAT003 & AWSAT005. --- internal/service/batch/ecs_properties_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/service/batch/ecs_properties_test.go b/internal/service/batch/ecs_properties_test.go index 553831bfe13..9e8387ba9b4 100644 --- a/internal/service/batch/ecs_properties_test.go +++ b/internal/service/batch/ecs_properties_test.go @@ -154,7 +154,7 @@ func TestEquivalentECSPropertiesJSON(t *testing.T) { "options": { "awslogs-stream-prefix": "ecs", "awslogs-group": "ewbankkit-test-003", - "awslogs-region": "us-west-2" + "awslogs-region": "region-2" }, "secretOptions": [] }, @@ -205,7 +205,7 @@ func TestEquivalentECSPropertiesJSON(t *testing.T) { "ulimits": [] } ], - "executionRoleArn": "arn:aws:iam::187416307283:role/ewbankkit-test-003", + "executionRoleArn": "role1", "platformVersion": "LATEST", "volumes": [] } @@ -240,7 +240,7 @@ func TestEquivalentECSPropertiesJSON(t *testing.T) { "logDriver": "awslogs", "options": { "awslogs-group": "ewbankkit-test-003", - "awslogs-region": "us-west-2", + "awslogs-region": "region-2", "awslogs-stream-prefix": "ecs" } }, @@ -284,7 +284,7 @@ func TestEquivalentECSPropertiesJSON(t *testing.T) { ] } ], - "executionRoleArn": "arn:aws:iam::187416307283:role/ewbankkit-test-003" + "executionRoleArn": "role1" } ] }