Promote Container Images from Dev to Prod #79
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Promote Container Images from Dev to Prod | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| instruments: | |
| description: 'Instruments to promote' | |
| required: true | |
| type: choice | |
| options: | |
| - all | |
| - codice | |
| - glows | |
| - hit | |
| - hi | |
| - ialirt | |
| - idex | |
| - lo | |
| - mag | |
| - spacecraft | |
| - swapi | |
| - swe | |
| - ultra | |
| default: all | |
| dev_tag: | |
| description: 'Source image tag from dev' | |
| required: false | |
| type: string | |
| default: 'latest' | |
| prod_tag: | |
| description: 'Target image tag for prod' | |
| required: false | |
| type: string | |
| default: 'latest' | |
| l3_data: | |
| description: 'Deploy L3 data containers (instrument-l3-repo) instead of standard containers (instrument-repo)' | |
| required: false | |
| type: boolean | |
| default: false | |
| # Prevent multiple promotions running concurrently | |
| concurrency: | |
| group: container-promote-${{ github.repository }} | |
| cancel-in-progress: false | |
| env: | |
| # IMAP instruments - keep in sync with imap_data_access.VALID_INSTRUMENTS | |
| VALID_INSTRUMENTS: "codice,glows,hit,hi,ialirt,idex,lo,mag,spacecraft,swapi,swe,ultra" | |
| DEV_ACCOUNT: "449431850278" | |
| PROD_ACCOUNT: "593025701104" | |
| AWS_REGION: "us-west-2" | |
| jobs: | |
| prepare: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| instruments: ${{ steps.setup.outputs.instruments }} | |
| matrix: ${{ steps.setup.outputs.matrix }} | |
| steps: | |
| - name: Setup promotion parameters | |
| id: setup | |
| run: | | |
| # Determine which instruments to promote | |
| if [ "${{ inputs.instruments }}" = "all" ]; then | |
| instruments="${{ env.VALID_INSTRUMENTS }}" | |
| else | |
| instruments="${{ inputs.instruments }}" | |
| fi | |
| # Clean up whitespace and convert to JSON array | |
| instruments_json=$(echo "$instruments" | tr ',' '\n' | tr -d ' ' | grep -v '^$' | jq -R -s -c 'split("\n") | map(select(length > 0))') | |
| echo "instruments=$instruments_json" >> $GITHUB_OUTPUT | |
| echo "matrix={\"instrument\": $instruments_json}" >> $GITHUB_OUTPUT | |
| echo "Promoting instruments: $instruments_json" | |
| echo "From dev tag: ${{ inputs.dev_tag }}" | |
| echo "To prod tag: ${{ inputs.prod_tag }}" | |
| echo "L3 data containers: ${{ inputs.l3_data }}" | |
| promote_images: | |
| needs: prepare | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: ${{ fromJson(needs.prepare.outputs.matrix) }} | |
| fail-fast: false # Continue promoting other instruments if one fails | |
| permissions: | |
| id-token: write | |
| contents: read | |
| steps: | |
| - name: Configure AWS credentials for DEV account | |
| uses: aws-actions/configure-aws-credentials@v4 | |
| with: | |
| role-to-assume: arn:aws:iam::${{ env.DEV_ACCOUNT }}:role/GitHubDeploy | |
| aws-region: ${{ env.AWS_REGION }} | |
| role-session-name: GitHubActions-Dev-${{ matrix.instrument }}-promote | |
| - name: Login to Amazon ECR (DEV) | |
| id: login-ecr-dev | |
| uses: aws-actions/amazon-ecr-login@v2 | |
| with: | |
| mask-password: "true" | |
| - name: Pull image from DEV | |
| env: | |
| DEV_REGISTRY: ${{ steps.login-ecr-dev.outputs.registry }} | |
| REPOSITORY: ${{ matrix.instrument }}${{ inputs.l3_data == true && '-l3' || '' }}-repo | |
| DEV_TAG: ${{ inputs.dev_tag }} | |
| run: | | |
| echo "Pulling image from DEV: $DEV_REGISTRY/$REPOSITORY:$DEV_TAG" | |
| # Check if source image exists | |
| if ! aws ecr describe-images --repository-name $REPOSITORY --image-ids imageTag=$DEV_TAG --region ${{ env.AWS_REGION }} >/dev/null 2>&1; then | |
| echo "❌ Source image $DEV_REGISTRY/$REPOSITORY:$DEV_TAG does not exist in DEV account" | |
| exit 1 | |
| fi | |
| docker pull $DEV_REGISTRY/$REPOSITORY:$DEV_TAG | |
| echo "✅ Successfully pulled image from DEV" | |
| - name: Configure AWS credentials for PROD account | |
| uses: aws-actions/configure-aws-credentials@v4 | |
| with: | |
| role-to-assume: arn:aws:iam::${{ env.PROD_ACCOUNT }}:role/GitHubDeploy | |
| aws-region: ${{ env.AWS_REGION }} | |
| role-session-name: GitHubActions-Prod-${{ matrix.instrument }}-promote | |
| - name: Login to Amazon ECR (PROD) | |
| id: login-ecr-prod | |
| uses: aws-actions/amazon-ecr-login@v2 | |
| with: | |
| mask-password: "true" | |
| - name: Tag and push image to PROD | |
| env: | |
| DEV_REGISTRY: ${{ steps.login-ecr-dev.outputs.registry }} | |
| PROD_REGISTRY: ${{ steps.login-ecr-prod.outputs.registry }} | |
| REPOSITORY: ${{ matrix.instrument }}${{ inputs.l3_data == true && '-l3' || '' }}-repo | |
| DEV_TAG: ${{ inputs.dev_tag }} | |
| PROD_TAG: ${{ inputs.prod_tag }} | |
| run: | | |
| echo "Promoting image: $DEV_REGISTRY/$REPOSITORY:$DEV_TAG -> $PROD_REGISTRY/$REPOSITORY:$PROD_TAG" | |
| # Tag image for PROD | |
| docker tag $DEV_REGISTRY/$REPOSITORY:$DEV_TAG $PROD_REGISTRY/$REPOSITORY:$PROD_TAG | |
| # Push to PROD | |
| docker push $PROD_REGISTRY/$REPOSITORY:$PROD_TAG | |
| echo "✅ Successfully promoted ${{ matrix.instrument }} to PROD" | |
| # Clean up local images to save space | |
| docker rmi $DEV_REGISTRY/$REPOSITORY:$DEV_TAG || true | |
| docker rmi $PROD_REGISTRY/$REPOSITORY:$PROD_TAG || true | |
| verify_promotion: | |
| needs: [prepare, promote_images] | |
| runs-on: ubuntu-latest | |
| if: always() | |
| permissions: | |
| id-token: write | |
| contents: read | |
| strategy: | |
| matrix: ${{ fromJson(needs.prepare.outputs.matrix) }} | |
| fail-fast: false | |
| steps: | |
| - name: Configure AWS credentials for PROD account | |
| uses: aws-actions/configure-aws-credentials@v4 | |
| with: | |
| role-to-assume: arn:aws:iam::${{ env.PROD_ACCOUNT }}:role/GitHubDeploy | |
| aws-region: ${{ env.AWS_REGION }} | |
| role-session-name: GitHubActions-Verify-${{ matrix.instrument }} | |
| - name: Verify image in PROD | |
| env: | |
| REPOSITORY: ${{ matrix.instrument }}${{ inputs.l3_data == true && '-l3' || '' }}-repo | |
| PROD_TAG: ${{ inputs.prod_tag }} | |
| run: | | |
| echo "Verifying image $REPOSITORY:$PROD_TAG in PROD account..." | |
| if aws ecr describe-images --repository-name $REPOSITORY --image-ids imageTag=$PROD_TAG --region ${{ env.AWS_REGION }} >/dev/null 2>&1; then | |
| echo "✅ Image $REPOSITORY:$PROD_TAG verified in PROD account" | |
| # Get image details | |
| image_details=$(aws ecr describe-images --repository-name $REPOSITORY --image-ids imageTag=$PROD_TAG --region ${{ env.AWS_REGION }} --query 'imageDetails[0].{pushed: imagePushedAt, digest: imageDigest}' --output table) | |
| echo "Image details:" | |
| echo "$image_details" | |
| else | |
| echo "❌ Image $REPOSITORY:$PROD_TAG NOT found in PROD account" | |
| exit 1 | |
| fi | |
| summary: | |
| needs: [prepare, promote_images, verify_promotion] | |
| runs-on: ubuntu-latest | |
| if: always() | |
| steps: | |
| - name: Promotion Summary | |
| run: | | |
| echo "## Container Promotion Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Source:** DEV account (${{ env.DEV_ACCOUNT }}) - tag: ${{ inputs.dev_tag }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Target:** PROD account (${{ env.PROD_ACCOUNT }}) - tag: ${{ inputs.prod_tag }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Instruments:** $(echo '${{ needs.prepare.outputs.instruments }}' | jq -r 'join(", ")')" >> $GITHUB_STEP_SUMMARY | |
| echo "**Container type:** ${{ inputs.l3_data == true && 'L3 data containers (instrument-l3-repo)' || 'Standard containers (instrument-repo)' }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [ "${{ needs.promote_images.result }}" = "success" ] && [ "${{ needs.verify_promotion.result }}" = "success" ]; then | |
| echo "✅ All promotions completed successfully and verified" >> $GITHUB_STEP_SUMMARY | |
| elif [ "${{ needs.promote_images.result }}" = "failure" ]; then | |
| echo "❌ Some promotions failed" >> $GITHUB_STEP_SUMMARY | |
| elif [ "${{ needs.verify_promotion.result }}" = "failure" ]; then | |
| echo "⚠️ Promotions completed but verification failed" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "⚠️ Promotion status: promote=${{ needs.promote_images.result }}, verify=${{ needs.verify_promotion.result }}" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Next Steps" >> $GITHUB_STEP_SUMMARY | |
| echo "- Verify that the promoted images work correctly in PROD" >> $GITHUB_STEP_SUMMARY | |
| echo "- Update any deployment configurations if needed" >> $GITHUB_STEP_SUMMARY | |
| echo "- Consider running integration tests against the promoted images" >> $GITHUB_STEP_SUMMARY |