11#! /bin/bash
22set -euo pipefail
33
4- # Reads either a value or a list from plugin config
5- function plugin_read_list() {
6- prefix_read_list " BUILDKITE_PLUGIN_ECS_DEPLOY_$1 "
7- }
4+ DIR=" $( cd " $( dirname " ${BASH_SOURCE[0]} " ) " && pwd) "
85
9- # Reads either a value or a list from the given env prefix
10- function prefix_read_list() {
11- local prefix=" $1 "
12- local parameter=" ${prefix} _0"
13-
14- if [[ -n " ${! parameter:- } " ]]; then
15- local i=0
16- local parameter=" ${prefix} _${i} "
17- while [[ -n " ${! parameter:- } " ]]; do
18- echo " ${! parameter} "
19- i=$(( i+ 1 ))
20- parameter=" ${prefix} _${i} "
21- done
22- elif [[ -n " ${! prefix:- } " ]]; then
23- echo " ${! prefix} "
24- fi
25- }
6+ # shellcheck source=lib/plugin.bash
7+ . " $DIR /../lib/plugin.bash"
268
27- cluster=${BUILDKITE_PLUGIN_ECS_DEPLOY_CLUSTER?}
28- task_family=${BUILDKITE_PLUGIN_ECS_DEPLOY_TASK_FAMILY?}
29- service_name=${BUILDKITE_PLUGIN_ECS_DEPLOY_SERVICE?}
30- images=()
31- while read -r line ; do
32- [[ -n " $line " ]] && images+=(" $line " )
33- done <<< " $(plugin_read_list IMAGE)"
34- task_definition=${BUILDKITE_PLUGIN_ECS_DEPLOY_TASK_DEFINITION:- " " }
35- service_definition=${BUILDKITE_PLUGIN_ECS_DEPLOY_SERVICE_DEFINITION:- " " }
36- container_definitions=${BUILDKITE_PLUGIN_ECS_DEPLOY_CONTAINER_DEFINITIONS?}
9+ # mandatory configurations
10+ cluster=${BUILDKITE_PLUGIN_ECS_DEPLOY_CLUSTER?Missing cluster}
11+ container_definitions=${BUILDKITE_PLUGIN_ECS_DEPLOY_CONTAINER_DEFINITIONS?Missing container definitions}
12+ task_family=${BUILDKITE_PLUGIN_ECS_DEPLOY_TASK_FAMILY?Missing task family}
13+ service_name=${BUILDKITE_PLUGIN_ECS_DEPLOY_SERVICE?Missing service name}
14+
15+ if ! plugin_read_list_into_result " IMAGE" ; then
16+ echo " :boom: Missing image to use"
17+ exit 1
18+ fi
19+ images=(" ${result[@]} " )
20+
21+ # optional configurations
3722desired_count=${BUILDKITE_PLUGIN_ECS_DEPLOY_DESIRED_COUNT:- " 1" }
38- task_role_arn=${BUILDKITE_PLUGIN_ECS_DEPLOY_TASK_ROLE_ARN:- " " }
3923target_group=${BUILDKITE_PLUGIN_ECS_DEPLOY_TARGET_GROUP:- " " }
4024load_balancer_name=${BUILDKITE_PLUGIN_ECS_DEPLOY_LOAD_BALANCER_NAME:- " " }
4125target_container=${BUILDKITE_PLUGIN_ECS_DEPLOY_TARGET_CONTAINER_NAME:- " " }
4226target_port=${BUILDKITE_PLUGIN_ECS_DEPLOY_TARGET_CONTAINER_PORT:- " " }
43- execution_role=${BUILDKITE_PLUGIN_ECS_DEPLOY_EXECUTION_ROLE:- " " }
27+
28+ # necessary for compatibility with bash 4.3
29+ if plugin_read_list_into_result " ENV" ; then
30+ env_vars=(" ${result[@]} " )
31+ else
32+ env_vars=()
33+ fi
34+
35+ aws_default_args=()
4436region=${BUILDKITE_PLUGIN_ECS_DEPLOY_REGION:- " " }
45- env_vars=()
46- while read -r line ; do
47- [[ -n " $line " ]] && env_vars+=(" $line " )
48- done <<< " $(plugin_read_list ENV)"
49-
50- if [[ $region != " " ]]; then
51- # shellcheck disable=SC2034 # Used by the aws cli
52- AWS_DEFAULT_REGION=${region}
37+ if [[ -n " ${region} " ]]; then
38+ aws_default_args+=(--region " ${region} " )
5339fi
5440
5541# Resolve any runtime environment variables it has
5642target_group=$( eval " echo $target_group " )
5743load_balancer_name=$( eval " echo $load_balancer_name " )
5844
59- deployment_config=${BUILDKITE_PLUGIN_ECS_DEPLOY_DEPLOYMENT_CONFIGURATION:- " 100/200" }
60- # shellcheck disable=SC2206
61- min_max_percent=(${deployment_config// \/ / } )
62- min_deploy_perc=${min_max_percent[0]}
63- max_deploy_perc=${min_max_percent[1]}
64-
65- if [[ $( jq ' . | keys |first' " $container_definitions " ) != " 0" ]]; then
45+ if [[ $( jq ' . | keys | first' " $container_definitions " ) != " 0" ]]; then
6646 echo " ^^^"
6747 echo " Invalid Container Definitions"
6848 echo ' JSON definition should be in the format of [{"image": "..."}]'
@@ -74,26 +54,42 @@ function create_service() {
7454 local task_definition=$2
7555 local service_name=$3
7656 local desired_count=$4
77- local target_group_arguments
78- target_group_arguments=$( generate_target_group_arguments " $5 " " $6 " " $7 " )
79-
8057 local service_definition_json=" {}"
58+ local target_group_arguments
59+
60+ generate_target_group_arguments " $5 " " $6 " " $7 "
61+ target_group_arguments=(" ${result[@]} " ) # copying the array
62+
63+ service_definition=${BUILDKITE_PLUGIN_ECS_DEPLOY_SERVICE_DEFINITION:- " " }
8164 if [[ -n " ${service_definition} " ]]; then
8265 service_definition_json=$( cat " ${service_definition} " )
8366 fi
8467
85- # shellcheck disable=SC2016
86- service_defined=$( aws ecs describe-services --cluster " $cluster_name " --service " $service_name " --query ' services[?status==`ACTIVE`].status' --output text | wc -l)
68+ service_defined=$(
69+ aws ecs describe-services \
70+ " ${aws_default_args[@]} " \
71+ --cluster " $cluster_name " \
72+ --service " $service_name " \
73+ --query ' services[?status=="ACTIVE"].status' \
74+ --output text \
75+ | wc -l
76+ )
8777 if [[ $service_defined -eq 0 ]]; then
88- echo " --- :ecs: Creating a Service $service_name in cluster $cluster_name "
89- # shellcheck disable=SC2086
90- aws ecs create-service \
78+ echo " --- :ecs: Creating a Service $service_name in cluster $cluster_name "
79+
80+ deployment_config=${BUILDKITE_PLUGIN_ECS_DEPLOY_DEPLOYMENT_CONFIGURATION:- " 100/200" }
81+ IFS=" /" read -r -a min_max_percent <<< " ${deployment_config}"
82+ min_deploy_perc=${min_max_percent[0]}
83+ max_deploy_perc=${min_max_percent[1]}
84+
85+ aws ecs create-service \
86+ " ${aws_default_args[@]} " \
9187 --cluster " $cluster_name " \
9288 --service-name " $service_name " \
9389 --task-definition " $task_definition " \
9490 --desired-count " $desired_count " \
9591 --deployment-configuration " maximumPercent=${max_deploy_perc} ,minimumHealthyPercent=${min_deploy_perc} " \
96- $ target_group_arguments \
92+ " ${ target_group_arguments[@]} " \
9793 --cli-input-json " $service_definition_json "
9894 fi
9995}
@@ -102,7 +98,7 @@ function generate_target_group_arguments() {
10298 local target_group=$1
10399 local target_container=$2
104100 local target_port=$3
105- local target_group_arguments= " "
101+ result=()
106102 if [[ -n $target_container ]] && [[ -n $target_port ]]; then
107103 local load_balancer_ref=" "
108104 if [[ -n $target_group ]]; then
@@ -111,60 +107,65 @@ function generate_target_group_arguments() {
111107 load_balancer_ref=" loadBalancerName=${load_balancer_name} "
112108 else
113109 echo " +++ ^^^"
114- # shellcheck disable=SC2016
115- echo ' +++ You must specify either `target-group` or `load-balancer-name`'
110+ echo ' +++ You must specify either target-group or load-balancer-name'
116111 exit 1
117112 fi
118113
119- target_group_arguments= " --load-balancers ${load_balancer_ref} ,containerName=${target_container} ,containerPort=${target_port} "
114+ result+=( --load-balancers " ${load_balancer_ref} ,containerName=${target_container} ,containerPort=${target_port} " )
120115 fi
121- echo " $target_group_arguments "
116+ return 0
122117}
123118
124119# # This is the template definition of your containers
125120image_idx=0
126121container_definitions_json=$( cat " ${container_definitions} " )
127122for image in " ${images[@]} " ; do
128- container_definitions_json=$( echo " $container_definitions_json " | jq --arg IMAGE " $image " \
129- " .[${image_idx} ].image=\$ IMAGE"
123+ container_definitions_json=$(
124+ echo " $container_definitions_json " \
125+ | jq --arg IMAGE " $image " " .[${image_idx} ].image=\$ IMAGE"
130126 )
131- image_idx=$(( image_idx+ 1 ))
132- done
133127
134- # # This adds the env vars to each container
135- image_idx=0
136- for image in " ${images[@]} " ; do
137- for env_var in " ${env_vars[@]} " ; do
138- # shellcheck disable=SC2206
139- var_val=(${env_var// =/ } )
140- container_definitions_json=$( echo " $container_definitions_json " | jq --arg ENVVAR " ${var_val[0]} " --arg ENVVAL " ${var_val[1]} " \
141- " .[${image_idx} ].environment += [{\" name\" : \$ ENVVAR, \" value\" : \$ ENVVAL}]"
142- )
143- done
128+ # this check is only necessary to be compatible with bash 4.3 (see issue #81)
129+ if [ " ${# env_vars[@]} " -gt 0 ]; then
130+ for env_var in " ${env_vars[@]} " ; do
131+ IFS=" =" read -r -a var_val <<< " ${env_var}"
132+ container_definitions_json=$(
133+ echo " $container_definitions_json " \
134+ | jq --arg ENVVAR " ${var_val[0]} " --arg ENVVAL " ${var_val[1]} " \
135+ " .[${image_idx} ].environment += [{\" name\" : \$ ENVVAR, \" value\" : \$ ENVVAL}]"
136+ )
137+ done
138+ fi
139+
144140 image_idx=$(( image_idx+ 1 ))
145141done
146142
147143echo " --- :ecs: Registering new task definition for ${task_family} "
148- register_command=" aws ecs register-task-definition \
149- --family ${task_family} \
150- --container-definitions '$container_definitions_json '"
144+ register_command=(aws ecs register-task-definition
145+ " ${aws_default_args[@]} "
146+ --family " ${task_family} "
147+ --container-definitions " ${container_definitions_json} "
148+ )
151149
150+ task_role_arn=${BUILDKITE_PLUGIN_ECS_DEPLOY_TASK_ROLE_ARN:- " " }
152151if [[ -n " ${task_role_arn} " ]]; then
153- register_command+=" --task-role-arn ${task_role_arn} "
152+ register_command+=( --task-role-arn " ${task_role_arn} " )
154153fi
155154
155+ execution_role=${BUILDKITE_PLUGIN_ECS_DEPLOY_EXECUTION_ROLE:- " " }
156156if [[ -n " ${execution_role} " ]]; then
157- register_command+=" --execution-role-arn ${execution_role} "
157+ register_command+=( --execution-role-arn " ${execution_role} " )
158158fi
159159
160+ task_definition=${BUILDKITE_PLUGIN_ECS_DEPLOY_TASK_DEFINITION:- " " }
160161if [[ -n " ${task_definition} " ]]; then
161162 task_definition_json=$( cat " ${task_definition} " )
162- register_command+=" --cli-input-json ' ${task_definition_json} ' "
163+ register_command+=( --cli-input-json " ${task_definition_json} " )
163164fi
164165
165166echo " --- :ecs: register command:"
166167
167- json_output=$( eval " $ register_command" )
168+ json_output=$( " ${ register_command[@]} " )
168169register_exit_code=$?
169170
170171if [[ $register_exit_code -ne 0 ]] ; then
@@ -179,8 +180,7 @@ echo "Registered ${task_family}:${task_revision}"
179180# Create service if it doesn't already exist
180181create_service " $cluster " " ${task_family} :${task_revision} " " $service_name " " $desired_count " " $target_group " " $target_container " " $target_port "
181182
182- # shellcheck disable=SC2016
183- lb_config=$( aws ecs describe-services --cluster " $cluster " --services " $service_name " --query ' services[?status==`ACTIVE`]' | jq -r ' .[0].loadBalancers[0]' )
183+ lb_config=$( aws ecs describe-services --cluster " $cluster " --services " $service_name " --query ' services[?status=="ACTIVE"]' | jq -r ' .[0].loadBalancers[0]' )
184184error=" +++ ^^^
185185+++ 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"
186186
195195if [[ " $lb_config " == " null" ]]; then
196196 # noop
197197 true
198- elif [[ $( echo " $lb_config " | jq -r ' .containerName' ) != " $target_container " ]] || [[ $( echo " $lb_config " | jq -r ' .containerPort' ) -ne $target_port ]]; then
198+ elif [[ $( echo " $lb_config " | jq -r ' .containerName' ) != " $target_container " ]] || [[ $( echo " $lb_config " | jq -r ' .containerPort' ) -ne $target_port ]]; then
199199 echo " $error . Container config differs"
200200 exit 1
201- elif [[ -n " $target_group " ]] && [[ $( echo " $lb_config " | jq -r ' .targetGroupArn' ) != " $target_group " ]]; then
201+ elif [[ -n " $target_group " ]] && [[ $( echo " $lb_config " | jq -r ' .targetGroupArn' ) != " $target_group " ]]; then
202202 echo " $error . ALB config differs"
203203 exit 1
204- elif [[ -n " $load_balancer_name " ]] && [[ $( echo " $lb_config " | jq -r ' .loadBalancerName' ) != " $load_balancer_name " ]]; then
204+ elif [[ -n " $load_balancer_name " ]] && [[ $( echo " $lb_config " | jq -r ' .loadBalancerName' ) != " $load_balancer_name " ]]; then
205205 echo " $error . ELB config differs"
206206 exit 1
207207fi
208208
209209echo " --- :ecs: Updating service for ${service_name} "
210210aws ecs update-service \
211+ " ${aws_default_args[@]} " \
211212 --cluster " ${cluster} " \
212213 --service " ${service_name} " \
213214 --task-definition " ${task_family} :${task_revision} "
@@ -216,11 +217,13 @@ aws ecs update-service \
216217echo " --- :ecs: Waiting for services to stabilize"
217218deploy_exitcode=0
218219aws ecs wait services-stable \
220+ " ${aws_default_args[@]} " \
219221 --cluster " ${cluster} " \
220222 --services " ${service_name} " || deploy_exitcode=$?
221223
222224
223225service_events=$( aws ecs describe-services \
226+ " ${aws_default_args[@]} " \
224227 --cluster " ${cluster} " \
225228 --service " ${service_name} " \
226229 --query ' services[].events' --output text)
0 commit comments