Skip to content

Commit

Permalink
Merge pull request #106 from buildkite-plugins/toote_deprecate_create…
Browse files Browse the repository at this point in the history
…_service

Deprecate ECS service creation
  • Loading branch information
pzeballos authored Mar 22, 2024
2 parents 5912855 + 5d9c44f commit 482c967
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 449 deletions.
65 changes: 13 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ steps:
concurrency_group: "my-service-deploy"
concurrency: 1
plugins:
- ecs-deploy#v2.1.0:
- ecs-deploy#v3.0.0:
cluster: "my-ecs-cluster"
service: "my-service"
container-definitions: "examples/hello-world.json"
Expand Down Expand Up @@ -96,87 +96,50 @@ Example: `"my-task"`

### Optional

#### `deployment-configuration` (optional)
#### `env` (array)

The minimum and maximum percentage of tasks that should be maintained during a deployment. Defaults to `100/200`
An array of environment variables to add to *every* image's task definition in the `NAME=VALUE` format

Example: `"0/100"`

#### `env` (optional)

An array of environment variables to add to *every* image's task definition

#### `execution-role` (optional)
#### `execution-role`

The Execution Role ARN used by ECS to pull container images and secrets.

Example: `"arn:aws:iam::012345678910:role/execution-role"`

Requires the `iam:PassRole` permission for the execution role.

#### `load-balancer-name` (optional)

The name of the Elastic Load Balancer (Application or Network) used with the ECS Service.

Example: `application-load-balancer`

#### `region` (optional)
#### `region`

The region we deploy the ECS Service to.

#### `service-definition`

The file path to the ECS service definition JSON file. Parameters specified in this file will be overridden by other arguments if set, e.g. `cluster`, `desired-count`, etc. Note that currently this json input will only be used when creating the service, NOT when updating it.

Example: `"ecs/service.json"`
```json
{
"schedulingStrategy": "DAEMON",
"propagateTags": "TASK_DEFINITION"
}
```

#### `target-container-name` (optional)

The Container Name to forward ALB requests to.

#### `target-container-port` (optional)

The Container Port to forward requests to.

#### `target-group` (optional)

The Target Group ARN to map the service to.

Example: `"arn:aws:elasticloadbalancing:us-east-1:012345678910:targetgroup/alb/e987e1234cd12abc"`

#### `task-cpu` (optional, integer)
#### `task-cpu` (integer)

CPU Units to assign to the task (1024 constitutes a whole CPU). Example: `256` (1/4 of a CPU).

#### `task-ephemeral-storage` (optional, integer)
#### `task-ephemeral-storage` (integer)

Amount of GBs to assign in ephemeral storage to the task. Example: `25`.

#### `task-ipc-mode` (optional)
#### `task-ipc-mode`

IPC resource namespace to use in the task. If specified, should be one of `host`, `task` or `none`.

#### `task-memory` (optional, integer)
#### `task-memory` (integer)

Amount of memory (in Mbs) to allocate for the task. Example: `1024` (1Gb).

#### `task-network-mode` (optional)
#### `task-network-mode`

Docker networking mode for the containers running in the task. If specified, should be one of `bridge`, `host`, `awsvpc` or `none`.

#### `task-pid-mode` (optional)
#### `task-pid-mode`

Process namespace to use for containers in the task. If specified, should be one of `host` or `task`.

#### `task-role-arn` (optional)
#### `task-role-arn`

An IAM ECS Task Role to assign to tasks.

Requires the `iam:PassRole` permission for the ARN specified.

## AWS Roles
Expand All @@ -195,8 +158,6 @@ Policy:
Resource: '*'
```

This plugin will create the ECS Service if it does not already exist, which additionally requires the `ecs:CreateService` permission.

## Developing

To run testing, shellchecks and plugin linting use use `bk run` with the [Buildkite CLI](https://github.com/buildkite/cli).
Expand Down
4 changes: 0 additions & 4 deletions examples/service-definition.json

This file was deleted.

125 changes: 22 additions & 103 deletions hooks/command
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,35 @@ if ! plugin_read_list_into_result "IMAGE"; then
fi
images=("${result[@]}")

# optional configurations
desired_count=${BUILDKITE_PLUGIN_ECS_DEPLOY_DESIRED_COUNT:-"1"}
target_group=${BUILDKITE_PLUGIN_ECS_DEPLOY_TARGET_GROUP:-""}
load_balancer_name=${BUILDKITE_PLUGIN_ECS_DEPLOY_LOAD_BALANCER_NAME:-""}
target_container=${BUILDKITE_PLUGIN_ECS_DEPLOY_TARGET_CONTAINER_NAME:-""}
target_port=${BUILDKITE_PLUGIN_ECS_DEPLOY_TARGET_CONTAINER_PORT:-""}

if [ -n "${BUILDKITE_PLUGIN_ECS_DEPLOY_TASK_DEFINITION:-""}" ]; then
echo ":boom: The task-definition parameter has been deprecated"
exit 1
fi

if [ -n "${BUILDKITE_PLUGIN_ECS_DEPLOY_SERVICE_DEFINITION:-""}" ]; then
echo ":boom: The service-definition parameter has been deprecated"
echo "Create the service outside of this plugin first (using CloudFormation or Terraform)"
exit 1
fi

for DEPRECATED_CONFIG in deployment-config deployment-configuration desired-count load-balancer-name target-container-name target-container-port target-group; do
VAR_NAME="BUILDKITE_PLUGIN_ECS_DEPLOY_$(echo "${DEPRECATED_CONFIG}" | tr 'a-z-' 'A-Z_')"

if [ -n "${!VAR_NAME:-""}" ]; then
echo ":warning: The ${DEPRECATED_CONFIG} parameter has been deprecated"
echo "Please configure the service outside of this plugin"
fi
done

aws_default_args=()
if [ -n "${BUILDKITE_PLUGIN_ECS_DEPLOY_REGION:-}" ]; then
aws_default_args+=(--region "${BUILDKITE_PLUGIN_ECS_DEPLOY_REGION}")
fi

task_file=$(mktemp)
trap 'rm "${task_file}"' EXIT

if ! aws ecs describe-task-definition --task-definition "${task_family}" --query 'taskDefinition' >"${task_file}"; then
if ! aws ecs describe-task-definition "${aws_default_args[@]+"${aws_default_args[@]}"}" --task-definition "${task_family}" --query 'taskDefinition' >"${task_file}"; then
echo "Could not obtain existing task definition"
fi

Expand All @@ -56,15 +69,6 @@ else
env_vars=()
fi

aws_default_args=()
if [ -n "${BUILDKITE_PLUGIN_ECS_DEPLOY_REGION:-}" ]; then
aws_default_args+=(--region "${BUILDKITE_PLUGIN_ECS_DEPLOY_REGION}")
fi

# Resolve any runtime environment variables it has
target_group=$(eval "echo $target_group")
load_balancer_name=$(eval "echo $load_balancer_name")

# jq has no in-place edition https://github.com/jqlang/jq/issues/105
container_definitions_json=$(cat "${container_definitions}")
image_idx=0
Expand Down Expand Up @@ -166,91 +170,6 @@ fi
task_revision=$(jq '.taskDefinition.revision' <<< "$json_output")
echo "Registered ${task_family}:${task_revision}"

# Create service if it doesn't already exist
aws_describe_service_args=(
--cluster "$cluster"
--service "$service_name"
)

aws_create_service_args=(
--cluster "$cluster"
--service-name "$service_name"
--task-definition "${task_family}:${task_revision}"
--desired-count "$desired_count"
)

service_definition=${BUILDKITE_PLUGIN_ECS_DEPLOY_SERVICE_DEFINITION:-""}
if [[ -n "${service_definition}" ]]; then
service_definition_json=$(cat "${service_definition}")
else
service_definition_json="{}"
fi

service_defined=$(
aws ecs describe-services \
"${aws_default_args[@]+"${aws_default_args[@]}"}" \
"${aws_describe_service_args[@]}" \
--query "services[?status=='ACTIVE'].status" \
--output text \
| wc -l
)

deployment_config=${BUILDKITE_PLUGIN_ECS_DEPLOY_DEPLOYMENT_CONFIGURATION:-"100/200"}
IFS="/" read -r -a min_max_percent <<< "${deployment_config}"
min_deploy_perc=${min_max_percent[0]}
max_deploy_perc=${min_max_percent[1]}

aws_create_service_args+=(--deployment-configuration "maximumPercent=${max_deploy_perc},minimumHealthyPercent=${min_deploy_perc}")

if [[ -n $target_container ]] && [[ -n $target_port ]]; then
if [[ -n $target_group ]]; then
load_balancer_ref="targetGroupArn=${target_group}"
elif [[ -n $load_balancer_name ]]; then
load_balancer_ref="loadBalancerName=${load_balancer_name}"
else
echo "+++ ^^^"
echo '+++ You must specify either target-group or load-balancer-name'
exit 1
fi

aws_create_service_args+=(--load-balancers "${load_balancer_ref},containerName=${target_container},containerPort=${target_port}")
fi

if [[ $service_defined -eq 0 ]]; then
echo "--- :ecs: Creating a Service $service_name in cluster $cluster"

aws ecs create-service \
"${aws_default_args[@]+"${aws_default_args[@]}"}" \
"${aws_create_service_args[@]}" \
--cli-input-json "$service_definition_json"
fi

lb_config=$(aws ecs describe-services --cluster "$cluster" --services "$service_name" --query "services[?status=='ACTIVE']" | jq -r '.[0].loadBalancers[0]')
error="+++ ^^^
+++ Cannot update a service to add/remove a load balancer. First delete the service and then run again, or rename the service to force a new one to be created"

# No easy way to tell if the target group has changed, since describe-services only returns the load balancer name
if [[ "$lb_config" == "null" ]]; then
if [[ -n "$target_group" ]] || [[ -n "$load_balancer_name" ]]; then
echo "$error. ELB configured but none set in container"
exit 1
fi
fi

if [[ "$lb_config" == "null" ]]; then
# noop
true
elif [[ $(echo "$lb_config" | jq -r '.containerName') != "$target_container" ]] || [[ $(echo "$lb_config" | jq -r '.containerPort') -ne $target_port ]]; then
echo "$error. Container config differs"
exit 1
elif [[ -n "$target_group" ]] && [[ $(echo "$lb_config" | jq -r '.targetGroupArn') != "$target_group" ]]; then
echo "$error. ALB config differs"
exit 1
elif [[ -n "$load_balancer_name" ]] && [[ $(echo "$lb_config" | jq -r '.loadBalancerName') != "$load_balancer_name" ]]; then
echo "$error. ELB config differs"
exit 1
fi

echo "--- :ecs: Updating service for ${service_name}"
aws ecs update-service \
${aws_default_args[@]+"${aws_default_args[@]}"} \
Expand All @@ -270,7 +189,7 @@ aws ecs wait services-stable \
service_events=$(aws ecs describe-services \
${aws_default_args[@]+"${aws_default_args[@]}"} \
--cluster "${cluster}" \
--service "${service_name}" \
--services "${service_name}" \
--query 'services[].events' --output text)

if [[ $deploy_exitcode -eq 0 ]]; then
Expand Down
17 changes: 4 additions & 13 deletions plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,42 +10,33 @@ configuration:
type: string
container-definitions:
type: string
deployment-config:
type: string
desired-count:
type: string
env:
type: array
execution-role:
type: string
image:
type: [ string, array ]
load-balancer-name:
region:
type: string
service:
type: string
service-definition:
type: string
target-container-name:
type: string
target-container-port:
type: integer
target-group:
type: string
task-cpu:
type: integer
task-ephemeral-storage:
type: integer
task-ipc-mode:
type: string
enum: [ "host", "none", "task"]
task-family:
type: string
task-memory:
type: integer
task-network-mode:
type: string
enum: [ "awsvpc", "bridge", "host", "none" ]
task-pid-mode:
type: string
enum: [ "host", "task" ]
task-role-arn:
type: string
required:
Expand Down
Loading

0 comments on commit 482c967

Please sign in to comment.