diff --git a/aws/aws_ecs_service_blue_green/.stackgen/stackgen.yaml b/aws/aws_ecs_service_blue_green/.stackgen/stackgen.yaml new file mode 100644 index 0000000..b1160b7 --- /dev/null +++ b/aws/aws_ecs_service_blue_green/.stackgen/stackgen.yaml @@ -0,0 +1,22 @@ +version: 1.0 + +representation: + side_panel: + label: AWS ECS Service + node: + label: + static: AWS ECS Service + template: ${name} + display_type: default + +discovery: + type: aws_ecs_service_blue_green + dnd_supported: false + data_source: data_aws_ecs_service_blue_green + references: + cluster: + from: aws_ecs_cluster + output: arn + task_definition: + from: aws_ecs_task_definition + output: arn diff --git a/aws/aws_ecs_service_blue_green/README.md b/aws/aws_ecs_service_blue_green/README.md new file mode 100644 index 0000000..d7ba5e9 --- /dev/null +++ b/aws/aws_ecs_service_blue_green/README.md @@ -0,0 +1,5 @@ +# aws_ecs_service_blue_green + +Discovery module scaffold for issue #55. + +Copied from sibling aws_ecs_service and adapted for workflow validation. diff --git a/aws/aws_ecs_service_blue_green/aws_ecs_service_blue_green.tf b/aws/aws_ecs_service_blue_green/aws_ecs_service_blue_green.tf new file mode 100644 index 0000000..2cb00ff --- /dev/null +++ b/aws/aws_ecs_service_blue_green/aws_ecs_service_blue_green.tf @@ -0,0 +1,101 @@ +resource "aws_ecs_service" "this" { + name = var.name + cluster = var.cluster + availability_zone_rebalancing = var.availability_zone_rebalancing + task_definition = var.task_definition + launch_type = var.launch_type + force_delete = var.force_delete + desired_count = var.desired_count + platform_version = var.platform_version + propagate_tags = var.propagate_tags + scheduling_strategy = var.scheduling_strategy + deployment_maximum_percent = var.deployment_maximum_percent + deployment_minimum_healthy_percent = var.deployment_minimum_healthy_percent + enable_ecs_managed_tags = var.enable_ecs_managed_tags + enable_execute_command = var.enable_execute_command + force_new_deployment = var.force_new_deployment + health_check_grace_period_seconds = var.health_check_grace_period_seconds + iam_role = var.iam_role + wait_for_steady_state = var.wait_for_steady_state + tags = var.tags + + dynamic "capacity_provider_strategy" { + for_each = var.capacity_provider_strategy + content { + base = capacity_provider_strategy.value.base + capacity_provider = capacity_provider_strategy.value.capacity_provider + weight = capacity_provider_strategy.value.weight + } + } + + dynamic "deployment_controller" { + for_each = var.deployment_controller + content { + type = deployment_controller.value.type + } + } + + dynamic "deployment_circuit_breaker" { + for_each = var.deployment_circuit_breaker + content { + enable = deployment_circuit_breaker.value.enable + rollback = deployment_circuit_breaker.value.rollback + } + } + + dynamic "network_configuration" { + for_each = var.network_configuration + content { + assign_public_ip = network_configuration.value.assign_public_ip + subnets = network_configuration.value.subnets + security_groups = network_configuration.value.security_groups + } + } + + dynamic "load_balancer" { + for_each = var.load_balancer + content { + elb_name = load_balancer.value.elb_name + target_group_arn = load_balancer.value.target_group_arn + container_name = load_balancer.value.container_name + container_port = load_balancer.value.container_port + } + } + + dynamic "ordered_placement_strategy" { + for_each = var.ordered_placement_strategy + content { + type = ordered_placement_strategy.value.type + field = ordered_placement_strategy.value.field + } + } + + dynamic "placement_constraints" { + for_each = var.placement_constraints + content { + type = placement_constraints.value.type + expression = placement_constraints.value.expression + } + } + + dynamic "service_registries" { + for_each = var.service_registries + content { + registry_arn = service_registries.value.registry_arn + container_name = service_registries.value.container_name + container_port = service_registries.value.container_port + port = service_registries.value.port + } + } + + dynamic "timeouts" { + for_each = var.timeouts != null ? [var.timeouts] : [] + content { + create = lookup(timeouts.value, "create", null) + delete = lookup(timeouts.value, "delete", null) + update = lookup(timeouts.value, "update", null) + } + } +} + + diff --git a/aws/aws_ecs_service_blue_green/basic.tftest.hcl b/aws/aws_ecs_service_blue_green/basic.tftest.hcl new file mode 100644 index 0000000..a02adfd --- /dev/null +++ b/aws/aws_ecs_service_blue_green/basic.tftest.hcl @@ -0,0 +1,6 @@ +mock_provider "aws" {} + +# Plan-only smoke test; no assert with literal true (OpenTofu rejects non-referential conditions). +run "basic_plan" { + command = plan +} diff --git a/aws/aws_ecs_service_blue_green/outputs.tf.json b/aws/aws_ecs_service_blue_green/outputs.tf.json new file mode 100644 index 0000000..17597dc --- /dev/null +++ b/aws/aws_ecs_service_blue_green/outputs.tf.json @@ -0,0 +1,8 @@ +{ + "output": { + "arn": { + "description": "The value of the arn output", + "value": "${aws_ecs_service.this.id}" + } + } +} diff --git a/aws/aws_ecs_service_blue_green/policy.json b/aws/aws_ecs_service_blue_green/policy.json new file mode 100644 index 0000000..fc948ec --- /dev/null +++ b/aws/aws_ecs_service_blue_green/policy.json @@ -0,0 +1,27 @@ +{ + "name": "aws_ecs_service", + "policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "Default", + "Effect": "Allow", + "Action": [ + "ecs:Describe*", + "ecs:List*", + "ecs:DiscoverPollEndpoint", + "ecr:GetAuthorizationToken", + "ecr:BatchCheckLayerAvailability", + "ecr:GetDownloadUrlForLayer", + "ecr:BatchGetImage", + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Resource": [ + "${module.module_name.arn}" + ] + } + ] + } +} \ No newline at end of file diff --git a/aws/aws_ecs_service_blue_green/variables.tf.json b/aws/aws_ecs_service_blue_green/variables.tf.json new file mode 100644 index 0000000..c689171 --- /dev/null +++ b/aws/aws_ecs_service_blue_green/variables.tf.json @@ -0,0 +1,208 @@ +{ + "variable": { + "name": [ + { + "description": "The name of the ECS service", + "type": "string", + "nullable": false + } + ], + "cluster": [ + { + "description": "The ARN of the ECS cluster to run the service on", + "type": "string", + "nullable": true + } + ], + "availability_zone_rebalancing": [ + { + "description": "The availability zone rebalancing strategy to use", + "type": "string", + "nullable": true, + "default": "DISABLED" + } + ], + "task_definition": [ + { + "description": "The ARN of the task definition to run on the service", + "type": "string", + "nullable": true + } + ], + "launch_type": [ + { + "description": "The launch type on which to run your service", + "type": "string", + "nullable": true, + "default": "EC2" + } + ], + "force_delete": [ + { + "description": "Whether to force a new deployment of the service", + "type": "bool", + "nullable": true + } + ], + "desired_count": [ + { + "description": "The number of instances of the task to run on the service", + "type": "number", + "nullable": true + } + ], + "platform_version": [ + { + "description": "The platform version on which to run your service", + "type": "string", + "nullable": true, + "default": "LATEST" + } + ], + "propagate_tags": [ + { + "description": "Specifies whether to propagate the tags to the tasks", + "type": "string", + "nullable": true + } + ], + "scheduling_strategy": [ + { + "description": "The scheduling strategy to use for the service", + "type": "string", + "nullable": true, + "default": "REPLICA" + } + ], + "deployment_maximum_percent": [ + { + "description": "The upper limit of the number of tasks in a service", + "type": "number", + "nullable": true + } + ], + "deployment_minimum_healthy_percent": [ + { + "description": "The lower limit of the number of tasks in a service", + "type": "number", + "nullable": true + } + ], + "enable_ecs_managed_tags": [ + { + "description": "Whether to enable Amazon ECS managed tags for the service", + "type": "bool", + "nullable": true + } + ], + "enable_execute_command": [ + { + "description": "Whether to enable execute command for the service", + "type": "bool", + "nullable": true + } + ], + "force_new_deployment": [ + { + "description": "Whether to force a new deployment of the service", + "type": "bool", + "nullable": true + } + ], + "health_check_grace_period_seconds": [ + { + "description": "The period of time, in seconds, that the Amazon ECS service scheduler ignores unhealthy Elastic Load Balancing target health checks after a task has started", + "type": "number", + "nullable": true + } + ], + "iam_role": [ + { + "description": "The IAM role to use for the service", + "type": "string", + "nullable": true + } + ], + "wait_for_steady_state": [ + { + "description": "Whether to wait for the service to reach a steady state before proceeding", + "type": "bool", + "nullable": true + } + ], + "tags": [ + { + "description": "A map of tags to add to all resources", + "type": "map(string)", + "nullable": true + } + ], + "load_balancer": [ + { + "description": "A list of load balancer configuration blocks", + "type": "list(object({ target_group_arn: string, container_name: string, container_port: number, elb_name: string }))", + "nullable": true + } + ], + "capacity_provider_strategy": [ + { + "description": "A list of capacity provider strategy blocks", + "type": "list(object({ capacity_provider: string, base: number, weight: number }))", + "nullable": true + } + ], + "deployment_circuit_breaker": [ + { + "description": "A list of deployment circuit breaker blocks", + "type": "list(object({ enable: bool, rollback: bool }))", + "nullable": true + } + ], + "network_configuration": [ + { + "description": "A list of network configuration blocks", + "type": "list(object({ subnets: list(string), security_groups: list(string), assign_public_ip: bool }))", + "nullable": true + } + ], + "deployment_controller": [ + { + "description": "A list of deployment controller blocks", + "type": "list(object({ type: string }))", + "nullable": true + } + ], + "ordered_placement_strategy": [ + { + "description": "A list of ordered placement strategy blocks", + "type": "list(object({ type: string, field: string }))", + "nullable": true, + "default": [] + } + ], + "placement_constraints": [ + { + "description": "A list of placement constraints", + "type": "list(object({ type: string, expression: string }))", + "nullable": true, + "default": [] + } + ], + "service_registries": [ + { + "description": "A list of service registry blocks", + "type": "list(object({ registry_arn: string, container_name: string, container_port: number, port: number }))", + "nullable": true, + "default": [] + } + ], + "timeouts": [ + { + "description": "A map of timeouts", + "type": "object({ create: optional(string), delete: optional(string), update: optional(string) })", + "nullable": true, + "default": {} + } + ] + } +} diff --git a/aws/aws_ecs_service_blue_green/versions.tf b/aws/aws_ecs_service_blue_green/versions.tf new file mode 100644 index 0000000..f38a81c --- /dev/null +++ b/aws/aws_ecs_service_blue_green/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">= 1.0.0, < 2.0.0" + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + } +} \ No newline at end of file