diff --git a/ecs-update-and-deploy-task-definition/README.md b/ecs-update-and-deploy-task-definition/README.md index ff447e07..17e1689c 100644 --- a/ecs-update-and-deploy-task-definition/README.md +++ b/ecs-update-and-deploy-task-definition/README.md @@ -23,3 +23,72 @@ permissions: } } ``` + +## How to use + +Here is an example deploying two containers in one task definition. + +```yaml + + ecs-deploy: + - runs-on: ubuntu-latest + name: Deploy ECS task definition + environment: pirates-dev-app-too-tikki-ecr + permissions: + id-token: write # For the GitHub's OIDC Token endpoint + + steps: + + - name: Set images to deploy ⚙️ + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + id: set-images + with: + script: | + // Images data structure documentation: + // https://github.com/oslokommune/composite-actions/blob/main/ecs-update-and-deploy-task-definition/README.md + const images = {}; + + const initImageBuildResult = "${{ needs.docker-build-push-init.result }}"; + const appImageBuildResult = "${{ needs.docker-build-push.result }}"; + + console.log("Step result for init container image:", initImageBuildResult); + console.log("Step result for app container image:", appImageBuildResult); + + if (initImageBuildResult === 'success') { + images["init-container"] = { + "imageRepository": "pirates-dev-too-tikki-init", + "imageDigest": "${{ needs.docker-build-push-init.outputs.image_digest }}", + "imageTag": "${{ needs.docker-build-push-init.outputs.image_version }}" + }; + } + + if (appImageBuildResult === 'success') { + images["too-tikki"] = { + "imageRepository": "pirates-dev-too-tikki", + "imageDigest": "${{ needs.docker-build-push.outputs.image_digest }}", + "imageTag": "${{ needs.docker-build-push.outputs.image_version }}" + }; + } + + console.log("Images to deploy:"); + console.log(images); + + return images; + + + - name: "Update and deploy ECS task definition with new image URI" + uses: oslokommune/composite-actions/ecs-update-and-deploy-task-definition@... # set digest + with: + aws-region: "eu-west-1" + aws-role-arn: "${{ secrets.AWS_ROLE_ARN }}" + + cluster-name: "pirates-dev" + service-name: "too-tikki" + task-definition-name: "too-tikki" + + deploy: "true" + wait-for-service-stability: "false" + + images: ${{ steps.set-images.outputs.result }} + images-ssm-parameter-name: "/pirates-dev/ecs/too-tikki/images" +``` diff --git a/ecs-update-and-deploy-task-definition/action.yml b/ecs-update-and-deploy-task-definition/action.yml index dd2f12ae..f990b137 100644 --- a/ecs-update-and-deploy-task-definition/action.yml +++ b/ecs-update-and-deploy-task-definition/action.yml @@ -1,6 +1,8 @@ name: "Update and deploy ECS task definition" -description: "Downloads an existing ECS task definition, updates multiple container image URIs, and optionally deploys the updated task definition to the specified ECS service." +description: | + Downloads an existing ECS task definition, updates multiple container image URIs, optionally deploys the updated task + definition to the specified ECS service, and optionally writes the images deployed to an SSM parameter. inputs: aws-region: @@ -36,17 +38,18 @@ inputs: required: false default: "true" - -outputs: - task-definition-file-name: - description: "The path to the rendered task definition file." - value: "${{ steps.update-task-definition.outputs.task-definition }}" + images-ssm-parameter-name: + description: "Set this to store images as an SSM parameter. If empty, the action will not store images in SSM." + required: false + default: "" runs: using: composite steps: + + - name: Configure AWS credentials using the OpenID Connect (OIDC) provider 🔑 uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 # v4.1.0 with: @@ -61,12 +64,27 @@ runs: - name: Download existing ECS task definition ⚙️ + id: get-task-info shell: bash + env: + TASK_DEFINITION_NAME: "${{ inputs.task-definition-name }}" run: | - aws ecs describe-task-definition \ - --task-definition "${{ inputs.task-definition-name }}" \ - --query taskDefinition \ - | jq 'del(.registeredAt, .registeredBy, .compatibilities, .taskDefinitionArn, .requiresAttributes, .revision, .status)' > "task-definition.json" + TASK_RESPONSE=$(aws ecs describe-task-definition \ + --task-definition "$TASK_DEFINITION_NAME" \ + --include TAGS) + + # Remove unnecessary fields from the task definition + echo "$TASK_RESPONSE" | jq '.taskDefinition | + del(.registeredAt, .registeredBy, .compatibilities, .taskDefinitionArn, + .requiresAttributes, .revision, .status)' > "task-definition.json" + + # Get tags from the API response + TAGS=$(echo "$TASK_RESPONSE" | jq '.tags') + + # Add tags to task definition + jq --argjson tags "$TAGS" '. + {tags: $tags}' "task-definition.json" > "temp.json" && mv "temp.json" "task-definition.json" + + echo "✅ Task definition with tags saved to task-definition.json" - name: Update ECS task definition with new image URIs ⚙️ @@ -79,7 +97,7 @@ runs: const fs = require('fs'); // Set filenames - const taskDefFile = 'task-definition.json'; + const taskDefFile = "task-definition.json"; const outputTaskDefFile = 'updated-task-definition.json'; // Read task definition @@ -130,7 +148,6 @@ runs: // Set output core.setOutput('task-definition', outputTaskDefFile); - - if: inputs.deploy == 'true' name: Deploy task definition 🚀 id: deploy @@ -142,6 +159,39 @@ runs: wait-for-service-stability: "${{ inputs.wait-for-service-stability }}" + - if: inputs.deploy == 'true' && inputs.images-ssm-parameter-name != '' + name: Write deployed images to SSM parameter 📝 + shell: bash + env: + DEPLOYED_IMAGES: ${{ inputs.images }} + SSM_PARAMETER_NAME: ${{ inputs.images-ssm-parameter-name }} + run: | + echo "Deployed images: (This is the input image to this workflow.)" + echo $DEPLOYED_IMAGES | jq + echo + + CURRENT_IMAGES=$(aws ssm get-parameter \ + --name "$SSM_PARAMETER_NAME" \ + --query "Parameter.Value" \ + --output text) + echo "Current images from SSM: (These are all images stored for this task definition, before deploying.)" + echo $CURRENT_IMAGES | jq + echo + + MERGED_IMAGES=$(echo "$CURRENT_IMAGES" | jq --argjson new "$DEPLOYED_IMAGES" '. + $new') + echo "Current images from SSM merged with deployed images:" + echo $MERGED_IMAGES | jq + echo + + aws ssm put-parameter \ + --name "$SSM_PARAMETER_NAME" \ + --type "String" \ + --value "$MERGED_IMAGES" \ + --overwrite + + echo "✅ Wrote deployed images to SSM parameter '$SSM_PARAMETER_NAME'" + + - if: inputs.deploy == 'false' name: Write simple summary for non-deployment 📝 shell: bash @@ -160,6 +210,7 @@ runs: ECR_REGISTRY: ${{ steps.ecr-login.outputs.registry }} TASK_DEFINITION_NAME: ${{ inputs.task-definition-name }} TASK_DEFINITION_ARN: ${{ steps.deploy.outputs.task-definition-arn }} + IMAGES_SSM_PARAMETER_NAME: ${{ inputs.images-ssm-parameter-name }} run: | # To test the summary locally, copy the rest of this workflow into a script, uncomment the variables, and run. # @@ -172,12 +223,13 @@ runs: #CLUSTER_NAME='pirates-dev' #TASK_DEFINITION_NAME='too-tikki' #TASK_DEFINITION_ARN="arn:aws:ecs:$AWS_REGION:$AWS_ACCOUNT_ID:task-definition/$TASK_DEFINITION_NAME:143" + #IMAGES_SSM_PARAMETER_NAME="/ecs/pirates-dev/too-tikki/images" IMAGE_COUNT=$(echo "$IMAGES_JSON" | jq 'length') AWS_ACCOUNT_ID=$(echo "$ECR_REGISTRY" | cut -d. -f1) SERVICE_URL="https://$AWS_REGION.console.aws.amazon.com/ecs/v2/clusters/$CLUSTER_NAME/services/$SERVICE_NAME?region=$AWS_REGION" - TASK_REVISION=$(echo "$TASK_DEFINITION_ARN" | cut -d ':' -f 7) - TASK_DEF_URL="https://$AWS_REGION.console.aws.amazon.com/ecs/v2/task-definitions/$TASK_DEFINITION_NAME/$TASK_REVISION/containers?region=$AWS_REGION" + TASK_DEFINITION_REVISION=$(echo "$TASK_DEFINITION_ARN" | cut -d ':' -f 7) + TASK_DEF_URL="https://$AWS_REGION.console.aws.amazon.com/ecs/v2/task-definitions/$TASK_DEFINITION_NAME/$TASK_DEFINITION_REVISION/containers?region=$AWS_REGION" CONTAINER_ROWS=$(echo "$IMAGES_JSON" | jq -r 'to_entries[] | "| \(.key) | \(.value.imageRepository) | `\(.value.imageDigest)` | `\(.value.imageTag)` |"') ####################################### @@ -188,16 +240,21 @@ runs: ## Deployment summary 📋 - ✅ Updated task definition successfully. + ✅ Successfully updated task definition. | Item | Link | - |-------------------|----------------------------------------------------------| - | ECS service | [$SERVICE_NAME]($SERVICE_URL) | - | Task definition | [$TASK_DEFINITION_NAME:$TASK_REVISION]($TASK_DEF_URL) | + |-------------------|---------------------------------------------------------------------| + | ECS service | [$SERVICE_NAME]($SERVICE_URL) | + | Task definition | [$TASK_DEFINITION_NAME:$TASK_DEFINITION_REVISION]($TASK_DEF_URL) | ### Container(s) updated 📦 - - | Container | Repository | Digest | Tag | - | --- | --- | --- | --- | + | Container | ECR repository | Digest | Tag | + | --------- | -------------- | ------ | --- | $CONTAINER_ROWS + EOF + + if [ -n "$IMAGES_SSM_PARAMETER_NAME" ]; then + SSM_URL="https://$AWS_REGION.console.aws.amazon.com/systems-manager/parameters/$IMAGES_SSM_PARAMETER_NAME/description?region=$AWS_REGION" + echo "✅ Successfully wrote image metadata to SSM parameter [$IMAGES_SSM_PARAMETER_NAME]($SSM_URL)." >> $GITHUB_STEP_SUMMARY + fi