diff --git a/.github/workflows/release-beta.yaml b/.github/workflows/release-beta.yaml new file mode 100644 index 00000000..e7d19631 --- /dev/null +++ b/.github/workflows/release-beta.yaml @@ -0,0 +1,19 @@ +name: Release Beta + +on: + push: + branches-ignore: + - master + +jobs: + release-beta: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set Beta Git tag + uses: weareyipyip/walking-tag-action@v2 + with: + tag-name: v2-beta + tag-message: The current beta is based on this commit + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 00000000..365fae1c --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,21 @@ +name: Release + +on: + push: + branches: [ master ] + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Bump version and push tag + id: tag_version + uses: mathieudutour/github-tag-action@v6.0 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + release_branches: "master" + - uses: sersoft-gmbh/running-release-tags-action@v1 + with: + tag: ${{ steps.tag_version.outputs.new_tag }} + github-token: ${{secrets.GITHUB_TOKEN}} \ No newline at end of file diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 00000000..f9e8a817 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,79 @@ +name: Test + +on: + workflow_run: + workflows: [Release Beta] + types: + - completed + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TERRAFORM_VERSION: "1.4.6" + TF_WORKSPACE: "testing" + USE_BETA_VERSION: "true" + COMMENTER_DEBUG: "true" + GH_ACCEPT_HEADER: "Accept: application/vnd.github+json" + GH_AUTH_HEADER: "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" + GH_API_VERSION: "X-GitHub-Api-Version: 2022-11-28" + GH_COMMENT_URL: https://api.github.com/repos/GetTerminus/terraform-pr-commenter/issues/${{ github.event.number }}/comments + +jobs: + set-outputs: + name: Set Outputs + if: ${{ github.event.workflow_run.conclusion == 'success' }} + runs-on: ubuntu-latest + outputs: + tf_fmt_fail: ${{ steps.file_outputs.outputs.tf_fmt_fail }} + tf_init_fail: ${{ steps.file_outputs.outputs.tf_init_fail }} + tf_plan_fail: ${{ steps.file_outputs.outputs.tf_plan_fail }} + tf_plan_fail_partial: ${{ steps.file_outputs.outputs.tf_plan_fail_partial }} + tf_plan_success_no_changes: ${{ steps.file_outputs.outputs.tf_plan_success_no_changes }} + tf_plan_success_with_changes: ${{ steps.file_outputs.outputs.tf_plan_success_with_changes }} + tf_plan_success_long: ${{ steps.file_outputs.outputs.tf_plan_success_long }} + tf_validate_fail: ${{ steps.file_outputs.outputs.tf_validate_fail }} + strategy: + matrix: + filenames: + - "tf_fmt_fail" + - "tf_init_fail" + - "tf_plan_fail" + - "tf_plan_fail_partial" + - "tf_plan_success_no_changes" + - "tf_plan_success_with_changes" + - "tf_plan_success_long" + - "tf_validate_fail" + steps: + - uses: actions/checkout@v3 + - name: Set Test Outputs + id: file_outputs + run: | + EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) + + #have to truncate so we don't get an "argument list too long" error + if [[ "${{ matrix.filenames }}" == "tf_plan_success_long" ]]; then + OUTPUT=$(cat ./testing/text-files/${{ matrix.filenames }}.txt) + echo "${OUTPUT::130000}" > ./testing/text-files/${{ matrix.filenames }}.txt + fi + + echo "${{ matrix.filenames }}<<$EOF" >> $GITHUB_OUTPUT + echo "$(cat ./testing/text-files/${{ matrix.filenames }}.txt)" >> $GITHUB_OUTPUT + echo "$EOF" >> $GITHUB_OUTPUT + + # To test other scenarios please change the below variables as necessary. + commenter-test: + name: Test Commenter + if: ${{ github.event.workflow_run.conclusion == 'success' }} + runs-on: ubuntu-latest + needs: set-outputs + steps: + - uses: actions/checkout@v3 + - name: Test + uses: GetTerminus/terraform-pr-commenter@v3-beta + with: + commenter_type: plan + # Should only be setting commenter_input or commenter_plan_path (commenter_plan_path only for plan commenter type) + #commenter_input: ${{ needs.set-outputs.outputs.tf_plan_fail }} + commenter_plan_path: ./testing/text-files/tf_plan_success_with_changes.txt + commenter_exitcode: 1 + terraform_version: ${{ env.TERRAFORM_VERSION }} + use_beta_version: ${{ env.USE_BETA_VERSION }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 27f403a5..79336ff3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ # IDEs .idea .vscode +.DS_Store diff --git a/Dockerfile b/Dockerfile index d6741783..8c217daf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,5 @@ -FROM hashicorp/terraform:1.0.6 +ARG TERRAFORM_VERSION=1.0.6 +FROM hashicorp/terraform:${TERRAFORM_VERSION} LABEL repository="https://github.com/robburger/terraform-pr-commenter" \ homepage="https://github.com/robburger/terraform-pr-commenter" \ @@ -11,6 +12,7 @@ LABEL repository="https://github.com/robburger/terraform-pr-commenter" \ RUN apk add --no-cache -q \ bash \ curl \ + perl \ jq ADD entrypoint.sh /entrypoint.sh diff --git a/action.yml b/action.yml index ea2f2464..2b116c3f 100644 --- a/action.yml +++ b/action.yml @@ -9,15 +9,76 @@ inputs: description: 'The type of comment. Options: [fmt, init, plan]' required: true commenter_input: - description: 'The comment to post from a previous step output' + description: 'The comment to post from a previous step output. Will be trimmed to 64k length.' required: true + commenter_plan_path: + description: 'The (optional) tfplan file' + required: false commenter_exitcode: description: 'The exit code from a previous step output' required: true + terraform_version: + description: 'The version of terraform with which a plan was generated' + required: false + default: "1.0.6" + use_beta_version: + description: 'Whether to use the beta version of the commenter' + required: false + default: 'false' runs: - using: 'docker' - image: 'Dockerfile' - args: - - ${{ inputs.commenter_type }} - - ${{ inputs.commenter_input }} - - ${{ inputs.commenter_exitcode }} + using: "composite" + steps: + - name: Build commenter docker image (master) + if: inputs.use_beta_version != 'true' + run: docker build --build-arg TERRAFORM_VERSION=${{ inputs.terraform_version }} -t commenter https://github.com/GetTerminus/terraform-pr-commenter.git#master + shell: bash + - name: Build commenter docker image (beta) + if: inputs.use_beta_version == 'true' + # append branch with a pound (#) if developing. e.g., `commenter.git#my-branch` + run: docker build --build-arg TERRAFORM_VERSION=${{ inputs.terraform_version }} -t commenter https://github.com/GetTerminus/terraform-pr-commenter.git#v2-beta + shell: bash + - name: Run commenter image (plan) + env: + COMMENTER_INPUT: ${{ inputs.commenter_input }} + COMMENTER_PLAN_FILE: ${{ inputs.commenter_plan_path }} + GITHUB_EVENT: ${{ toJSON(github.event) }} + AWS_SECRET_ACCESS_KEY: ${{ env.AWS_SECRET_KEY }} + run: | + COMMENTER_INPUT=${COMMENTER_INPUT::65000} + docker run \ + -e GITHUB_TOKEN \ + -e TF_WORKSPACE \ + -e EXPAND_SUMMARY_DETAILS \ + -e HIGHLIGHT_CHANGES \ + -e GITHUB_EVENT \ + -e COMMENTER_INPUT \ + -e AWS_ACCESS_KEY_ID \ + -e AWS_SECRET_KEY \ + -e AWS_SECRET_ACCESS_KEY \ + -e AWS_REGION \ + -e COMMENTER_DEBUG \ + -e COMMENTER_ECHO \ + -e COMMENTER_PLAN_FILE \ + -e COMMENTER_POST_PLAN_OUTPUTS \ + -v "$(pwd)"/:/workspace \ + commenter ${{ inputs.commenter_type }} ${{ inputs.commenter_exitcode }} + shell: bash + if: ${{ inputs.commenter_type == 'plan' }} + - name: Run commenter image (non-plan) + env: + COMMENTER_INPUT: ${{ inputs.commenter_input }} + GITHUB_EVENT: ${{ toJSON(github.event) }} + run: | + docker run \ + -e GITHUB_TOKEN \ + -e TF_WORKSPACE \ + -e EXPAND_SUMMARY_DETAILS \ + -e HIGHLIGHT_CHANGES \ + -e GITHUB_EVENT \ + -e COMMENTER_INPUT \ + -e COMMENTER_DEBUG \ + -e COMMENTER_ECHO \ + commenter ${{ inputs.commenter_type }} ${{ inputs.commenter_exitcode }} + shell: bash + if: ${{ inputs.commenter_type != 'plan' }} + diff --git a/entrypoint.sh b/entrypoint.sh index 1f71f2c8..bdc3f072 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,9 +1,13 @@ #!/usr/bin/env bash +if [ -n "${COMMENTER_ECHO+x}" ]; then + set -x +fi + ############# # Validations ############# -PR_NUMBER=$(jq -r ".pull_request.number" "$GITHUB_EVENT_PATH") +PR_NUMBER=$(echo "$GITHUB_EVENT" | jq -r ".pull_request.number") if [[ "$PR_NUMBER" == "null" ]]; then echo "This isn't a PR." exit 0 @@ -14,7 +18,7 @@ if [[ -z "$GITHUB_TOKEN" ]]; then exit 1 fi -if [[ -z $3 ]]; then +if [[ -z $2 ]]; then echo "There must be an exit code from a previous step." exit 1 fi @@ -24,243 +28,444 @@ if [[ ! "$1" =~ ^(fmt|init|plan|validate)$ ]]; then exit 1 fi +########### +# Logging # +########### +debug () { + if [ -n "${COMMENTER_DEBUG+x}" ]; then + echo -e "\033[33;1mDEBUG:\033[0m $1" + fi +} + +info () { + echo -e "\033[34;1mINFO:\033[0m $1" +} + +error () { + echo -e "\033[31;1mERROR:\033[0m $1" +} + ################## # Shared Variables ################## -# Arg 1 is command -COMMAND=$1 -# Arg 2 is input. We strip ANSI colours. -INPUT=$(echo "$2" | sed 's/\x1b\[[0-9;]*m//g') -# Arg 3 is the Terraform CLI exit code -EXIT_CODE=$3 - -# Read TF_WORKSPACE environment variable or use "default" -WORKSPACE=${TF_WORKSPACE:-default} - -# Read EXPAND_SUMMARY_DETAILS environment variable or use "true" -if [[ ${EXPAND_SUMMARY_DETAILS:-true} == "true" ]]; then - DETAILS_STATE=" open" -else - DETAILS_STATE="" -fi +parse_args () { + # Arg 1 is command + COMMAND=$1 + # Arg 2 is input file. We strip ANSI colours. + RAW_INPUT="$COMMENTER_INPUT" + if test -f "/workspace/${COMMENTER_PLAN_FILE}"; then + info "Found tfplan; showing." + pushd workspace > /dev/null || (error "Failed to push workspace dir" && exit 1) + INIT_OUTPUT="$(terraform init 2>&1)" + INIT_RESULT=$? + if [ $INIT_RESULT -ne 0 ]; then + error "Failed pre-plan init. Init output: \n$INIT_OUTPUT" + exit 1 + fi + RAW_INPUT="$( terraform show "${COMMENTER_PLAN_FILE}" 2>&1 )" + SHOW_RESULT=$? + if [ $SHOW_RESULT -ne 0 ]; then + error "Plan failed to show. Plan output: \n$RAW_INPUT" + exit 1 + fi + popd > /dev/null || (error "Failed to pop workspace dir" && exit 1) + debug "Plan raw input: $RAW_INPUT" + else + info "Found no tfplan. Proceeding with input argument." + fi + + # change diff character, a red '-', into a high unicode character \U1f605 (literally 😅) + # iff not preceded by a literal "/" as in "+/-". + # this serves as an intermediate representation representing "diff removal line" as distinct from + # a raw hyphen which could *also* indicate a yaml list entry. + INPUT=$(echo "$RAW_INPUT" | perl -pe "s/(? /dev/null +} + +# usage: split_string target_array_name plan_text +split_string () { + local -n split=$1 + local entire_string=$2 + local remaining_string=$entire_string + local processed_length=0 + split=() + + debug "Total length to split: ${#remaining_string}" + # trim to the last newline that fits within length + while [ ${#remaining_string} -gt 0 ] ; do + debug "Remaining input: \n${remaining_string}" + + local current_iteration=${remaining_string::65300} # GitHub has a 65535-char comment limit - truncate and iterate + if [ ${#current_iteration} -ne ${#remaining_string} ] ; then + debug "String is over 64k length limit. Splitting at index ${#current_iteration} of ${#remaining_string}." + current_iteration="${current_iteration%$'\n'*}" # trim to the last newline + debug "Trimmed split string to index ${#current_iteration}" + fi + processed_length=$((processed_length+${#current_iteration})) # evaluate length of outbound comment and store + + debug "Processed string length: ${processed_length}" + split+=("$current_iteration") + + remaining_string=${entire_string:processed_length} + done +} + +substitute_and_colorize () { + local current_plan=$1 + current_plan=$(echo "$current_plan" | sed -r 's/^([[:blank:]]*)([😅+~])/\2\1/g' | sed -r 's/^😅/-/') + if [[ $COLOURISE == 'true' ]]; then + current_plan=$(echo "$current_plan" | sed -r 's/^~/!/g') # Replace ~ with ! to colourise the diff in GitHub comments + fi + echo "$current_plan" +} + +get_page_count () { + local link_header + local last_page=1 + + link_header=$(curl -sSI -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -L "$PR_COMMENTS_URL" | grep -i ^link) + + # if I find a matching link header... + if grep -Fi 'rel="next"' <<< "$link_header"; then + # we found a next page -> find the last page + IFS=',' read -ra links <<< "$link_header" + for link in "${links[@]}"; do + # process "$i" + local regex + page_regex='^.*page=([0-9]+).*$' + + # if this is the 'last' ref... + if grep -Fi 'rel="last"' <<< "$link" ; then + if [[ $link =~ $page_regex ]]; then + last_page="${BASH_REMATCH[1]}" + break + fi + fi + done + fi + + eval "$1"="$last_page" +} + +delete_existing_comments () { + # Look for an existing PR comment and delete + # debug "Existing comments: $(curl -sS -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -L $PR_COMMENTS_URL)" + + local type=$1 + local regex=$2 + local last_page + + local jq='.[] | select(.body|test ("' + jq+=$regex + jq+='")) | .id' + + # gross, but... bash. + get_page_count PAGE_COUNT + last_page=$PAGE_COUNT + info "Found $last_page page(s) of comments at $PR_COMMENTS_URL." + + info "Looking for an existing $type PR comment." + local comment_ids=() + for page in $(seq $last_page) + do + # first, we read *all* of the comment IDs across all pages. saves us from the problem where we read a page, then + # delete some, then read the next page, *after* our page boundary has moved due to the delete. + # CAUTION. this line assumes the PR_COMMENTS_URL already has at least one query parameter. (note the '&') + readarray -t -O "${#comment_ids[@]}" comment_ids < <(curl -sS -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -L "$PR_COMMENTS_URL&page=$page" | jq "$jq") + done + + for PR_COMMENT_ID in "${comment_ids[@]}" + do + FOUND=true + info "Found existing $type PR comment: $PR_COMMENT_ID. Deleting." + PR_COMMENT_URL="$PR_COMMENT_URI/$PR_COMMENT_ID" + STATUS=$(curl -sS -X DELETE -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -o /dev/null -w "%{http_code}" -L "$PR_COMMENT_URL") + if [ "$STATUS" != "204" ]; then + info "Failed to delete: status $STATUS (most likely rate limited)" + fi + done + + if [ -z $FOUND ]; then + info "No existing $type PR comment found." + fi +} + +post_diff_comments () { + local type=$1 + local comment_prefix=$2 + local comment_string=$3 + + debug "Total $type length: ${#comment_string}" + local comment_split + split_string comment_split "$comment_string" + local comment_count=${#comment_split[@]} + + info "Writing $comment_count $type comment(s)" + + for i in "${!comment_split[@]}"; do + local current="${comment_split[$i]}" + local colorized_comment=$(substitute_and_colorize "$current") + local comment_count_text="" + if [ "$comment_count" -ne 1 ]; then + comment_count_text=" ($((i+1))/$comment_count)" + fi + + local comment=$(make_details_with_header "$comment_prefix$comment_count_text" "$colorized_comment" "diff") + make_and_post_payload "$type" "$comment" + done +} + +make_details_with_header() { + local header="### $1" + local body=$2 + local format=$3 + local pr_comment="$header +$(make_details "Show Output" "$body" "$format")" + echo "$pr_comment" +} + +make_details() { + local summary="$1" + local body=$2 + local format=$3 + local details="$summary + +\`\`\`$format +$body +\`\`\` +" + echo "$details" +} + +############### +# Handler: plan +############### +execute_plan () { + delete_existing_comments 'plan' '### Terraform `plan` .* for Workspace: `'$WORKSPACE'`.*' + delete_existing_comments 'outputs' '### Changes to outputs for Workspace: `'$WORKSPACE'`.*' + + # Exit Code: 0, 2 + # Meaning: 0 = Terraform plan succeeded with no changes. 2 = Terraform plan succeeded with changes. + # Actions: Strip out the refresh section, ignore everything after the 72 dashes, format, colourise and build PR comment. + if [[ $EXIT_CODE -eq 0 || $EXIT_CODE -eq 2 ]]; then + plan_success + fi + + # Exit Code: 1 + # Meaning: Terraform plan failed. + # Actions: Build PR comment. + if [[ $EXIT_CODE -eq 1 ]]; then + plan_fail + fi +} + +plan_success () { + post_plan_comments + if [[ $POST_PLAN_OUTPUTS == 'true' ]]; then + post_outputs_comments + fi +} + +plan_fail () { + local comment=$(make_details_with_header "Terraform \`plan\` Failed for Workspace: \`$WORKSPACE\`" "$INPUT") + + # Add plan comment to PR. + make_and_post_payload "plan failure" "$comment" +} + +post_plan_comments () { + local clean_plan=$(echo "$INPUT" | perl -pe'$_="" unless /(An execution plan has been generated and is shown below.|Terraform used the selected providers to generate the following execution|No changes. Infrastructure is up-to-date.|No changes. Your infrastructure matches the configuration.)/ .. 1') # Strip refresh section + clean_plan=$(echo "$clean_plan" | sed -r '/Plan: /q') # Ignore everything after plan summary + + post_diff_comments "plan" "Terraform \`plan\` Succeeded for Workspace: \`$WORKSPACE\`" "$clean_plan" +} + +post_outputs_comments() { + local clean_plan=$(echo "$INPUT" | perl -pe'$_="" unless /Changes to Outputs:/ .. 1') # Skip to end of plan summary + clean_plan=$(echo "$clean_plan" | sed -r '/------------------------------------------------------------------------/q') # Ignore everything after plan summary + + post_diff_comments "outputs" "Changes to outputs for Workspace: \`$WORKSPACE\`" "$clean_plan" +} ############## # Handler: fmt ############## -if [[ $COMMAND == 'fmt' ]]; then - # Look for an existing fmt PR comment and delete - echo -e "\033[34;1mINFO:\033[0m Looking for an existing fmt PR comment." - PR_COMMENT_ID=$(curl -sS -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -L "$PR_COMMENTS_URL" | jq '.[] | select(.body|test ("### Terraform `fmt` Failed")) | .id') - if [ "$PR_COMMENT_ID" ]; then - echo -e "\033[34;1mINFO:\033[0m Found existing fmt PR comment: $PR_COMMENT_ID. Deleting." - PR_COMMENT_URL="$PR_COMMENT_URI/$PR_COMMENT_ID" - curl -sS -X DELETE -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -L "$PR_COMMENT_URL" > /dev/null - else - echo -e "\033[34;1mINFO:\033[0m No existing fmt PR comment found." - fi +execute_fmt () { + delete_existing_comments 'fmt' '### Terraform `fmt` Failed' # Exit Code: 0 # Meaning: All files formatted correctly. # Actions: Exit. if [[ $EXIT_CODE -eq 0 ]]; then - echo -e "\033[34;1mINFO:\033[0m Terraform fmt completed with no errors. Continuing." + fmt_success + fi - exit 0 + # Exit Code: 1, 2 + # Meaning: 1 = Malformed Terraform CLI command. 2 = Terraform parse error. + # Actions: Build PR comment. + if [[ $EXIT_CODE -eq 1 || $EXIT_CODE -eq 2 || $EXIT_CODE -eq 3 ]]; then + fmt_fail fi +} + +fmt_success () { + info "Terraform fmt completed with no errors. Continuing." +} + +fmt_fail () { + local pr_comment # Exit Code: 1, 2 # Meaning: 1 = Malformed Terraform CLI command. 2 = Terraform parse error. # Actions: Build PR comment. if [[ $EXIT_CODE -eq 1 || $EXIT_CODE -eq 2 ]]; then - PR_COMMENT="### Terraform \`fmt\` Failed -Show Output - -\`\`\` -$INPUT -\`\`\` -" + pr_comment=$(make_details_with_header "Terraform \`fmt\` Failed" "$INPUT") fi # Exit Code: 3 # Meaning: One or more files are incorrectly formatted. # Actions: Iterate over all files and build diff-based PR comment. if [[ $EXIT_CODE -eq 3 ]]; then - ALL_FILES_DIFF="" + local all_files_diff="" for file in $INPUT; do - THIS_FILE_DIFF=$(terraform fmt -no-color -write=false -diff "$file") - ALL_FILES_DIFF="$ALL_FILES_DIFF -$file - -\`\`\`diff -$THIS_FILE_DIFF -\`\`\` -" + local this_file_diff=$(terraform fmt -no-color -write=false -diff "$file") + all_files_diff="$all_files_diff +$(make_details "$file" "$this_file_diff" "diff")" done - PR_COMMENT="### Terraform \`fmt\` Failed -$ALL_FILES_DIFF" + pr_comment="### Terraform \`fmt\` Failed +$all_files_diff" fi # Add fmt failure comment to PR. - PR_PAYLOAD=$(echo '{}' | jq --arg body "$PR_COMMENT" '.body = $body') - echo -e "\033[34;1mINFO:\033[0m Adding fmt failure comment to PR." - curl -sS -X POST -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -H "$CONTENT_HEADER" -d "$PR_PAYLOAD" -L "$PR_COMMENTS_URL" > /dev/null - - exit 0 -fi + make_and_post_payload "fmt failure" "$pr_comment" +} ############### # Handler: init ############### -if [[ $COMMAND == 'init' ]]; then - # Look for an existing init PR comment and delete - echo -e "\033[34;1mINFO:\033[0m Looking for an existing init PR comment." - PR_COMMENT_ID=$(curl -sS -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -L "$PR_COMMENTS_URL" | jq '.[] | select(.body|test ("### Terraform `init` Failed")) | .id') - if [ "$PR_COMMENT_ID" ]; then - echo -e "\033[34;1mINFO:\033[0m Found existing init PR comment: $PR_COMMENT_ID. Deleting." - PR_COMMENT_URL="$PR_COMMENT_URI/$PR_COMMENT_ID" - curl -sS -X DELETE -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -L "$PR_COMMENT_URL" > /dev/null - else - echo -e "\033[34;1mINFO:\033[0m No existing init PR comment found." - fi +execute_init () { + delete_existing_comments "init" '### Terraform `init` Failed' # Exit Code: 0 # Meaning: Terraform successfully initialized. # Actions: Exit. if [[ $EXIT_CODE -eq 0 ]]; then - echo -e "\033[34;1mINFO:\033[0m Terraform init completed with no errors. Continuing." - - exit 0 + init_success fi # Exit Code: 1 # Meaning: Terraform initialize failed or malformed Terraform CLI command. # Actions: Build PR comment. if [[ $EXIT_CODE -eq 1 ]]; then - PR_COMMENT="### Terraform \`init\` Failed -Show Output - -\`\`\` -$INPUT -\`\`\` -" + init_fail fi +} - # Add init failure comment to PR. - PR_PAYLOAD=$(echo '{}' | jq --arg body "$PR_COMMENT" '.body = $body') - echo -e "\033[34;1mINFO:\033[0m Adding init failure comment to PR." - curl -sS -X POST -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -H "$CONTENT_HEADER" -d "$PR_PAYLOAD" -L "$PR_COMMENTS_URL" > /dev/null +init_success () { + info "Terraform init completed with no errors. Continuing." +} - exit 0 -fi +init_fail () { + local pr_comment=$(make_details_with_header "Terraform \`init\` Failed" "$INPUT") -############### -# Handler: plan -############### -if [[ $COMMAND == 'plan' ]]; then - # Look for an existing plan PR comment and delete - echo -e "\033[34;1mINFO:\033[0m Looking for an existing plan PR comment." - PR_COMMENT_ID=$(curl -sS -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -L "$PR_COMMENTS_URL" | jq '.[] | select(.body|test ("### Terraform `plan` .* for Workspace: `'"$WORKSPACE"'`")) | .id') - if [ "$PR_COMMENT_ID" ]; then - echo -e "\033[34;1mINFO:\033[0m Found existing plan PR comment: $PR_COMMENT_ID. Deleting." - PR_COMMENT_URL="$PR_COMMENT_URI/$PR_COMMENT_ID" - curl -sS -X DELETE -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -L "$PR_COMMENT_URL" > /dev/null - else - echo -e "\033[34;1mINFO:\033[0m No existing plan PR comment found." - fi - - # Exit Code: 0, 2 - # Meaning: 0 = Terraform plan succeeded with no changes. 2 = Terraform plan succeeded with changes. - # Actions: Strip out the refresh section, ignore everything after the 72 dashes, format, colourise and build PR comment. - if [[ $EXIT_CODE -eq 0 || $EXIT_CODE -eq 2 ]]; then - CLEAN_PLAN=$(echo "$INPUT" | sed -r '/^(An execution plan has been generated and is shown below.|Terraform used the selected providers to generate the following execution|No changes. Infrastructure is up-to-date.|No changes. Your infrastructure matches the configuration.|Note: Objects have changed outside of Terraform)$/,$!d') # Strip refresh section - CLEAN_PLAN=$(echo "$CLEAN_PLAN" | sed -r '/Plan: /q') # Ignore everything after plan summary - CLEAN_PLAN=${CLEAN_PLAN::65300} # GitHub has a 65535-char comment limit - truncate plan, leaving space for comment wrapper - CLEAN_PLAN=$(echo "$CLEAN_PLAN" | sed -r 's/^([[:blank:]]*)([-+~])/\2\1/g') # Move any diff characters to start of line - if [[ $COLOURISE == 'true' ]]; then - CLEAN_PLAN=$(echo "$CLEAN_PLAN" | sed -r 's/^~/!/g') # Replace ~ with ! to colourise the diff in GitHub comments - fi - PR_COMMENT="### Terraform \`plan\` Succeeded for Workspace: \`$WORKSPACE\` -Show Output - -\`\`\`diff -$CLEAN_PLAN -\`\`\` -" - fi - - # Exit Code: 1 - # Meaning: Terraform plan failed. - # Actions: Build PR comment. - if [[ $EXIT_CODE -eq 1 ]]; then - PR_COMMENT="### Terraform \`plan\` Failed for Workspace: \`$WORKSPACE\` -Show Output - -\`\`\` -$INPUT -\`\`\` -" - fi - - # Add plan comment to PR. - PR_PAYLOAD=$(echo '{}' | jq --arg body "$PR_COMMENT" '.body = $body') - echo -e "\033[34;1mINFO:\033[0m Adding plan comment to PR." - curl -sS -X POST -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -H "$CONTENT_HEADER" -d "$PR_PAYLOAD" -L "$PR_COMMENTS_URL" > /dev/null - - exit 0 -fi + # Add init failure comment to PR. + make_and_post_payload "init failure" "$pr_comment" +} ################### # Handler: validate ################### -if [[ $COMMAND == 'validate' ]]; then - # Look for an existing validate PR comment and delete - echo -e "\033[34;1mINFO:\033[0m Looking for an existing validate PR comment." - PR_COMMENT_ID=$(curl -sS -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -L "$PR_COMMENTS_URL" | jq '.[] | select(.body|test ("### Terraform `validate` Failed")) | .id') - if [ "$PR_COMMENT_ID" ]; then - echo -e "\033[34;1mINFO:\033[0m Found existing validate PR comment: $PR_COMMENT_ID. Deleting." - PR_COMMENT_URL="$PR_COMMENT_URI/$PR_COMMENT_ID" - curl -sS -X DELETE -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -L "$PR_COMMENT_URL" > /dev/null - else - echo -e "\033[34;1mINFO:\033[0m No existing validate PR comment found." - fi +execute_validate () { + delete_existing_comments "validate" '### Terraform `validate` Failed' # Exit Code: 0 # Meaning: Terraform successfully validated. # Actions: Exit. if [[ $EXIT_CODE -eq 0 ]]; then - echo -e "\033[34;1mINFO:\033[0m Terraform validate completed with no errors. Continuing." - - exit 0 + validate_success fi # Exit Code: 1 # Meaning: Terraform validate failed or malformed Terraform CLI command. # Actions: Build PR comment. if [[ $EXIT_CODE -eq 1 ]]; then - PR_COMMENT="### Terraform \`validate\` Failed -Show Output - -\`\`\` -$INPUT -\`\`\` -" + validate_fail fi +} + +validate_success () { + info "Terraform validate completed with no errors. Continuing." +} + +validate_fail () { + local pr_comment=$(make_details_with_header "Terraform \`validate\` Failed" "$INPUT") + make_and_post_payload "validate failure" "$pr_comment" +} + +################### +# Procedural body # +################### +parse_args "$@" - # Add validate failure comment to PR. - PR_PAYLOAD=$(echo '{}' | jq --arg body "$PR_COMMENT" '.body = $body') - echo -e "\033[34;1mINFO:\033[0m Adding validate failure comment to PR." - curl -sS -X POST -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -H "$CONTENT_HEADER" -d "$PR_PAYLOAD" -L "$PR_COMMENTS_URL" > /dev/null +if [[ $COMMAND == 'fmt' ]]; then + execute_fmt + exit 0 +fi +if [[ $COMMAND == 'init' ]]; then + execute_init + exit 0 +fi + +if [[ $COMMAND == 'plan' ]]; then + execute_plan + exit 0 +fi + +if [[ $COMMAND == 'validate' ]]; then + execute_validate exit 0 fi diff --git a/testing/paginate.sh b/testing/paginate.sh new file mode 100755 index 00000000..85f7e315 --- /dev/null +++ b/testing/paginate.sh @@ -0,0 +1,104 @@ +#!/usr/bin/env bash +set -x + +ACCEPT_HEADER="Accept: application/vnd.github.v3+json" +AUTH_HEADER="Authorization: token $GH_TOKEN" +CONTENT_HEADER="Content-Type: application/json" + +PR_COMMENTS_URL="https://api.github.com/repositories/520589422/issues/7/comments?per_page=100" +#PR_COMMENTS_URL="https://api.github.com/repos/GetTerminus/eks-autoscaling-infra/issues/7/comments" +PR_COMMENT_URI="https://api.github.com/repositories/520589422/issues/comments" + +PAGE_COUNT=1 + +########### +# Logging # +########### +debug () { + if [ -n "${COMMENTER_DEBUG+x}" ]; then + echo -e "\033[33;1mDEBUG:\033[0m $1" + fi +} + +info () { + echo -e "\033[34;1mINFO:\033[0m $1" +} + +error () { + echo -e "\033[31;1mERROR:\033[0m $1" +} + +get_page_count () { + local link_header + local last_page=1 + + link_header=$(curl -sSI -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -L "$PR_COMMENTS_URL" | grep -i ^link) + + # if I find a matching link header... + if grep -Fi 'rel="next"' <<< "$link_header"; then + # we found a next page -> find the last page + IFS=',' read -ra links <<< "$link_header" + for link in "${links[@]}"; do + # process "$i" + local regex + page_regex='^.*page=([0-9]+).*$' + + # if this is the 'last' ref... + if grep -Fi 'rel="last"' <<< "$link" ; then + if [[ $link =~ $page_regex ]]; then + last_page="${BASH_REMATCH[1]}" + break + fi + fi + done + fi + + eval "$1"="$last_page" +} + +delete_existing_comments () { + # Look for an existing PR comment and delete + # debug "Existing comments: $(curl -sS -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -L $PR_COMMENTS_URL)" + + local type=$1 + local regex=$2 + local last_page + + local jq='.[] | select(.body|test ("' + jq+=$regex + jq+='")) | .id' + + # gross, but... bash. + get_page_count PAGE_COUNT + last_page=$PAGE_COUNT + info "Found $last_page page(s) of comments at $PR_COMMENTS_URL." + + info "Looking for an existing $type PR comment." + local comment_ids=() + for page in $(seq $last_page) + do + # first, we read *all* of the comment IDs across all pages. saves us from the problem where we read a page, then + # delete some, then read the next page, *after* our page boundary has moved due to the delete. + # CAUTION. this line assumes the PR_COMMENTS_URL already has at least one query parameter. (note the '&') + readarray -t -O "${#comment_ids[@]}" comment_ids < <(curl -sS -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -L "$PR_COMMENTS_URL&page=$page" | jq "$jq") + done + + for PR_COMMENT_ID in "${comment_ids[@]}" + do + FOUND=true + info "Found existing $type PR comment: $PR_COMMENT_ID. Deleting." + PR_COMMENT_URL="$PR_COMMENT_URI/$PR_COMMENT_ID" +# STATUS=$(curl -sS -X DELETE -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -o /dev/null -w "%{http_code}" -L "$PR_COMMENT_URL") +# if [ "$STATUS" != "204" ]; then +# info "Failed to delete: status $STATUS (most likely rate limited)" +# fi + done + + if [ -z $FOUND ]; then + info "No existing $type PR comment found." + fi +} + +WORKSPACE=prod-east +#delete_existing_comments 'plan' '### Terraform `plan` .* for Workspace: `'$WORKSPACE'`.*' +delete_existing_comments 'outputs' '### Changes to outputs for Workspace: `'$WORKSPACE'`.*' \ No newline at end of file diff --git a/testing/testing.sh b/testing/testing.sh new file mode 100755 index 00000000..befd4854 --- /dev/null +++ b/testing/testing.sh @@ -0,0 +1,2421 @@ +#!/usr/bin/env bash + +if [ -n "${COMMENTER_ECHO+x}" ]; then + set -x +fi + +make_and_post_payload () { + # Add plan comment to PR. + PR_PAYLOAD=$(echo '{}' | jq --arg body "$1" '.body = $body') + info "Adding comment to PR." + debug "PR payload:\n$PR_PAYLOAD" + # curl -sS -X POST -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -H "$CONTENT_HEADER" -d "$1" -L "$PR_COMMENTS_URL" > /dev/null +} + +debug () { + if [ -n "${COMMENTER_DEBUG+x}" ]; then + echo -e "\033[33;1mDEBUG:\033[0m $1" + fi +} + +info () { + echo -e "\033[34;1mINFO:\033[0m $1" +} + +error () { + echo -e "\033[31;1mERROR:\033[0m $1" +} + +# usage: split_string target_array_name plan_text +split_string () { + local -n split=$1 + local entire_string=$2 + local remaining_string=$entire_string + local processed_length=0 + split=() + + debug "Total length to split: ${#remaining_string}" + # trim to the last newline that fits within length + while [ ${#remaining_string} -gt 0 ] ; do + debug "Remaining input: \n${remaining_string}" + + local current_iteration=${remaining_string::65300} # GitHub has a 65535-char comment limit - truncate and iterate + if [ ${#current_iteration} -ne ${#remaining_string} ] ; then + debug "String is over 64k length limit. Splitting at index ${#current_iteration} of ${#remaining_string}." + current_iteration="${current_iteration%$'\n'*}" # trim to the last newline + debug "Trimmed split string to index ${#current_iteration}" + fi + processed_length=$((processed_length+${#current_iteration})) # evaluate length of outbound comment and store + + debug "Processed string length: ${processed_length}" + split+=("$current_iteration") + + remaining_string=${entire_string:processed_length} + done +} + +substitute_and_colorize () { + local current_plan=$1 + current_plan=$(echo "$current_plan" | sed -r 's/^([[:blank:]]*)([😅+~])/\2\1/g' | sed -r 's/^😅/-/') + if [[ $COLOURISE == 'true' ]]; then + current_plan=$(echo "$current_plan" | sed -r 's/^~/!/g') # Replace ~ with ! to colourise the diff in GitHub comments + fi + echo "$current_plan" +} + +delete_existing_comments () { + # Look for an existing plan PR comment and delete +# echo -e "TEST: PRS $(curl -sS -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -L $PR_COMMENTS_URL)" + + local type=$1 + local regex=$2 + + local jq='.[] | select(.body|test ("' + jq+=$regex + jq+='")) | .id' + echo -e "\033[34;1mINFO:\033[0m Looking for an existing $type PR comment." + for PR_COMMENT_ID in $(curl -sS -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -L $PR_COMMENTS_URL | jq "$jq") + do + FOUND=true + echo -e "\033[34;1mINFO:\033[0m Found existing $type PR comment: $PR_COMMENT_ID. Deleting." + PR_COMMENT_URL="$PR_COMMENT_URI/$PR_COMMENT_ID" + # curl -sS -X DELETE -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -L "$PR_COMMENT_URL" > /dev/null + done + if [ -z $FOUND ]; then + echo -e "\033[34;1mINFO:\033[0m No existing $type PR comment found." + fi +} + +post_comments () { + local type=$1 + local comment_prefix=$2 + local comment_string=$3 + + debug "Total $type length: ${#comment_string}" + local comment_split + split_string comment_split "$comment_string" + local comment_count=${#comment_split[@]} + + info "Writing $comment_count $type comment(s)" + + for i in "${!comment_split[@]}"; do + local current="${comment_split[$i]}" + local colorized_comment=$(substitute_and_colorize "$current") + local comment_count_text="" + if [ "$comment_count" -ne 1 ]; then + comment_count_text=" ($((i+1))/$comment_count)" + fi + local comment="$comment_prefix$comment_count_text +Show Output + +\`\`\`diff +$colorized_comment +\`\`\` +" + make_and_post_payload "$comment" + done +} + +post_plan_comments () { + local clean_plan=$(echo "$INPUT" | perl -pe'$_="" unless /(An execution plan has been generated and is shown below.|Terraform used the selected providers to generate the following execution|No changes. Infrastructure is up-to-date.|No changes. Your infrastructure matches the configuration.)/ .. 1') # Strip refresh section + clean_plan=$(echo "$clean_plan" | sed -r '/Plan: /q') # Ignore everything after plan summary + + post_comments "plan" "### Terraform \`plan\` Succeeded for Workspace: \`$WORKSPACE\`" "$clean_plan" +} + +post_outputs_comments() { + local clean_plan=$(echo "$INPUT" | perl -pe'$_="" unless /Changes to Outputs:/ .. 1') # Skip to end of plan summary + clean_plan=$(echo "$clean_plan" | sed -r '/------------------------------------------------------------------------/q') # Ignore everything after plan summary + + post_comments "outputs" "### Changes to outputs for Workspace: \`$WORKSPACE\`" "$clean_plan" +} + +plan_success () { + post_plan_comments + if [[ $POST_PLAN_OUTPUTS == 'true' ]]; then + post_outputs_comments + fi +} + +plan_fail () { + local comment="### Terraform \`plan\` Failed for Workspace: \`$WORKSPACE\` +Show Output + +\`\`\` +$INPUT +\`\`\` +" + + # Add plan comment to PR. + make_and_post_payload "$(echo '{}' | jq --arg body "$comment" '.body = $body')" +} + +plan_fail () { + local comment="### Terraform \`plan\` Failed for Workspace: \`$WORKSPACE\` +Show Output + +\`\`\` +$INPUT +\`\`\` +" + + # Add plan comment to PR. + make_and_post_payload "$(echo '{}' | jq --arg body "$comment" '.body = $body')" +} + +############### +# Handler: plan +############### +execute_plan () { + delete_existing_comments 'plan' '### Terraform `plan` .* for Workspace: `'$WORKSPACE'`' + + # Exit Code: 0, 2 + # Meaning: 0 = Terraform plan succeeded with no changes. 2 = Terraform plan succeeded with changes. + # Actions: Strip out the refresh section, ignore everything after the 72 dashes, format, colourise and build PR comment. + if [[ $EXIT_CODE -eq 0 || $EXIT_CODE -eq 2 ]]; then + plan_success + fi + + # Exit Code: 1 + # Meaning: Terraform plan failed. + # Actions: Build PR comment. + if [[ $EXIT_CODE -eq 1 ]]; then + plan_fail + fi +} + + + +read -r -d '' RAW_INPUT <<'EOI' +random_pet.eks: Refreshing state... [id=mighty-crab] +random_string.datadog_agent_token[0]: Refreshing state... [id=sKASHxANYnwscJqDfQRRRUnYWFIVUVkz] +datadog_monitor.datadog_log_volume_daily_quota: Refreshing state... [id=46013123] +datadog_monitor.kubernetes_node_state: Refreshing state... [id=42536272] +datadog_logs_custom_pipeline.cloudwatch_forwarded_logs: Refreshing state... [id=j-fz8ijrTcmfdKK0gLJSmw] +datadog_monitor.kubernetes_cpu: Refreshing state... [id=28636430] +datadog_logs_archive.dd-logs-archive: Refreshing state... [id=JzsLarnNRri4scQkVH6iYw] +datadog_monitor.kubernetes_pod_pending: Refreshing state... [id=42536271] +datadog_monitor.kubernetes_pod_availability: Refreshing state... [id=42536269] +datadog_monitor.kubernetes_pod_imagepullbackoff: Refreshing state... [id=43979968] +datadog_monitor.kubernetes_pod_status: Refreshing state... [id=42536274] +datadog_dashboard_list.sre_eks_dashboard_list: Refreshing state... [id=231117] +datadog_monitor.kubernetes_disk: Refreshing state... [id=42536273] +datadog_logs_custom_pipeline.botkube_glog_logs: Refreshing state... [id=ymtWat48SdSijdzxbuCkxQ] +datadog_logs_custom_pipeline.linkerd_proxy_logs: Refreshing state... [id=SgxdKPUITXySy-QF4iU5oQ] +datadog_logs_custom_pipeline.traefig_glog_logs: Refreshing state... [id=bY5FOXJWTFuvegamSNc8Sg] +datadog_logs_custom_pipeline.linkerd_tap_logs: Refreshing state... [id=qaAXk6bySOK6ohXZERfjag] +datadog_monitor.kubernetes_pod_capacity: Refreshing state... [id=50708240] +datadog_monitor.datadog_log_volume: Refreshing state... [id=45247461] +datadog_logs_custom_pipeline.istio_envoy_logs: Refreshing state... [id=t_3qTz6OQGuDgbyQvh5psw] +datadog_monitor.kubernetes_mem: Refreshing state... [id=42536270] +datadog_logs_custom_pipeline.datadog_trace_startup_logs: Refreshing state... [id=MowGqIBKQT-jQkR4XEVM8g] +module.eks_vpc.aws_vpc.this[0]: Refreshing state... [id=vpc-04ff83d39ddba4b4d] +module.eks_vpc.aws_eip.nat[0]: Refreshing state... [id=eipalloc-0c170bdb85bae72b3] +module.eks_vpc.aws_eip.nat[1]: Refreshing state... [id=eipalloc-0eeba723bb4d25ea3] +module.eks_vpc.aws_eip.nat[2]: Refreshing state... [id=eipalloc-05845bbfdf5ee8090] +aws_s3_bucket.dd-logs-archive-bucket: Refreshing state... [id=prod-midwest-dd-log-archive] +aws_iam_role.fargate_pod_executor: Refreshing state... [id=eks-fargate-pod-executor] +aws_acm_certificate.terminus_tools[0]: Refreshing state... [id=arn:aws:acm:us-east-1:***:certificate/1d076d27-d592-4e4f-91d5-c76ac575dc2b] +aws_acm_certificate.terminus_tools_no_wildcard[0]: Refreshing state... [id=arn:aws:acm:us-east-1:***:certificate/13ae5547-167f-4ffd-ad5e-60c67d30348e] +module.eks.aws_cloudwatch_log_group.this[0]: Refreshing state... [id=/aws/eks/prod-midwest-mighty-crab/cluster] +aws_ssm_document.node_drainer[0]: Refreshing state... [id=prod-midwest-mighty-crab-node-drainer] +datadog_dashboard_json.sre_kubernetes: Refreshing state... [id=4ay-98x-tnj] +aws_iam_role.eks_readonly[0]: Refreshing state... [id=eks-readonly] +module.eks.aws_iam_role.cluster[0]: Refreshing state... [id=prod-midwest-mighty-crab20201014132921928700000001] +aws_iam_policy.lifecycle_hook_access[0]: Refreshing state... [id=arn:aws:iam::***:policy/eks/prod-midwest-mighty-crab-lifecycle-hook-access] +aws_iam_policy.eks_readonly_policy[0]: Refreshing state... [id=arn:aws:iam::***:policy/eks/eks-readonly] +aws_iam_policy.eks_admin_policy[0]: Refreshing state... [id=arn:aws:iam::***:policy/eks/eks-admin] +aws_iam_role.node_drainer[0]: Refreshing state... [id=prod-midwest-mighty-crab-node-drainer] +aws_iam_policy.cni_put_metrics_role_policy: Refreshing state... [id=arn:aws:iam::***:policy/eks/CNIMetricsHelperPolicy] +aws_iam_role_policy_attachment.AmazonEKSFargatePodExecutionRolePolicy: Refreshing state... [id=eks-fargate-pod-executor-20201014134739157000000001] +aws_iam_role.eks_admin[0]: Refreshing state... [id=eks-admin] +aws_security_group.eks_db_subnet_access: Refreshing state... [id=sg-061be5c1a9526cb1b] +module.eks.aws_security_group.cluster[0]: Refreshing state... [id=sg-091ec20585b4dadc2] +module.eks_vpc.aws_vpc_endpoint.s3[0]: Refreshing state... [id=vpce-0baaef11d3995b842] +module.eks_vpc.aws_vpc_endpoint.dynamodb[0]: Refreshing state... [id=vpce-028c97b5db9d679ed] +module.eks_vpc.aws_internet_gateway.this[0]: Refreshing state... [id=igw-02cf7d8f6858f8a22] +module.eks_vpc.aws_subnet.public[0]: Refreshing state... [id=subnet-0f803e12464d4d018] +module.eks_vpc.aws_subnet.public[1]: Refreshing state... [id=subnet-0e34de2801aa56246] +module.eks_vpc.aws_subnet.public[2]: Refreshing state... [id=subnet-08b2f9179750b44db] +module.eks_vpc.aws_route_table.private[0]: Refreshing state... [id=rtb-0be98fc226f199aeb] +module.eks_vpc.aws_route_table.private[1]: Refreshing state... [id=rtb-0799f7610a5705a7c] +module.eks_vpc.aws_route_table.private[2]: Refreshing state... [id=rtb-0783fe9149db77c26] +module.eks.aws_iam_role_policy_attachment.cluster_AmazonEKSServicePolicy[0]: Refreshing state... [id=prod-midwest-mighty-crab20201014132921928700000001-20201014132922591200000002] +module.eks.aws_iam_role_policy_attachment.cluster_AmazonEKSClusterPolicy[0]: Refreshing state... [id=prod-midwest-mighty-crab20201014132921928700000001-20201014132922618600000003] +module.eks_vpc.aws_route_table.public[0]: Refreshing state... [id=rtb-08f038602531af595] +module.eks_vpc.aws_subnet.private[1]: Refreshing state... [id=subnet-04c14856ef9593c5a] +module.eks_vpc.aws_subnet.private[0]: Refreshing state... [id=subnet-0dd47e406fc214453] +module.eks_vpc.aws_subnet.private[2]: Refreshing state... [id=subnet-0c945c0315bb9c9ad] +aws_route53_record.terminus_tools["*.prod-midwest.terminus.tools"]: Refreshing state... [id=Z0157238VB243EMUUOC3__3a240892ebd676d1ec5580329ead1da9.prod-midwest.terminus.tools._CNAME] +aws_route53_record.terminus_tools["*.terminus.tools"]: Refreshing state... [id=Z0157238VB243EMUUOC3__32b4e034dadfe7146b3853d966e4c42c.terminus.tools._CNAME] +aws_route53_record.terminus_tools_no_wildcard["terminus.tools"]: Refreshing state... [id=Z0157238VB243EMUUOC3__32b4e034dadfe7146b3853d966e4c42c.terminus.tools._CNAME] +aws_iam_role_policy_attachment.eks_readonly_policy_attach[0]: Refreshing state... [id=eks-readonly-20211027161122470900000001] +module.eks.aws_security_group_rule.cluster_egress_internet[0]: Refreshing state... [id=sgrule-3112590249] +aws_iam_role_policy.node_drainer[0]: Refreshing state... [id=prod-midwest-mighty-crab-node-drainer:eks-node-drainer] +aws_iam_role_policy_attachment.eks_admin_policy_attach[0]: Refreshing state... [id=eks-admin-20210727185149890500000001] +module.eks_vpc.aws_vpc_endpoint_route_table_association.private_s3[0]: Refreshing state... [id=a-vpce-0baaef11d3995b8423337404169] +module.eks_vpc.aws_vpc_endpoint_route_table_association.private_s3[1]: Refreshing state... [id=a-vpce-0baaef11d3995b84280810125] +module.eks_vpc.aws_vpc_endpoint_route_table_association.private_s3[2]: Refreshing state... [id=a-vpce-0baaef11d3995b8421404072536] +module.eks_vpc.aws_nat_gateway.this[0]: Refreshing state... [id=nat-0bf69456fd35e1cda] +module.eks_vpc.aws_nat_gateway.this[1]: Refreshing state... [id=nat-0aa6b81307e69e55f] +module.eks_vpc.aws_nat_gateway.this[2]: Refreshing state... [id=nat-04e04fe307e062163] +module.eks_vpc.aws_vpc_endpoint_route_table_association.private_dynamodb[0]: Refreshing state... [id=a-vpce-028c97b5db9d679ed3337404169] +module.eks_vpc.aws_vpc_endpoint_route_table_association.private_dynamodb[2]: Refreshing state... [id=a-vpce-028c97b5db9d679ed1404072536] +module.eks_vpc.aws_vpc_endpoint_route_table_association.private_dynamodb[1]: Refreshing state... [id=a-vpce-028c97b5db9d679ed80810125] +module.eks_vpc.aws_vpc_endpoint_route_table_association.public_dynamodb[0]: Refreshing state... [id=a-vpce-028c97b5db9d679ed2523514364] +module.eks_vpc.aws_route_table_association.public[0]: Refreshing state... [id=rtbassoc-06305c1f056349b6a] +module.eks_vpc.aws_route_table_association.public[1]: Refreshing state... [id=rtbassoc-028d0ddfc13d6dade] +module.eks_vpc.aws_route_table_association.public[2]: Refreshing state... [id=rtbassoc-05183d2d439aa4a2b] +module.eks_vpc.aws_vpc_endpoint_route_table_association.public_s3[0]: Refreshing state... [id=a-vpce-0baaef11d3995b8422523514364] +module.eks_vpc.aws_route.public_internet_gateway[0]: Refreshing state... [id=r-rtb-08f038602531af5951080289494] +module.eks_vpc.aws_route_table_association.private[0]: Refreshing state... [id=rtbassoc-00397c3925e11ff0e] +module.eks_vpc.aws_route_table_association.private[2]: Refreshing state... [id=rtbassoc-03ada92fc27d5d778] +module.eks_vpc.aws_route_table_association.private[1]: Refreshing state... [id=rtbassoc-097a41e0d52a10a99] +aws_acm_certificate_validation.terminus_tools[0]: Refreshing state... [id=2021-11-17 21:02:17.798 +0000 UTC] +aws_acm_certificate_validation.terminus_tools_no_wildcard[0]: Refreshing state... [id=2021-11-17 21:02:15.747 +0000 UTC] +module.eks_vpc.aws_route.private_nat_gateway[0]: Refreshing state... [id=r-rtb-0be98fc226f199aeb1080289494] +module.eks_vpc.aws_route.private_nat_gateway[1]: Refreshing state... [id=r-rtb-0799f7610a5705a7c1080289494] +module.eks_vpc.aws_route.private_nat_gateway[2]: Refreshing state... [id=r-rtb-0783fe9149db77c261080289494] +module.eks.aws_eks_cluster.this: Refreshing state... [id=prod-midwest-mighty-crab] +module.eks.aws_iam_role.workers[0]: Refreshing state... [id=prod-midwest-mighty-crab20201014134016318400000005] +module.eks.aws_security_group.workers[0]: Refreshing state... [id=sg-0a85a7dc1373ecf6b] +module.eks.aws_iam_policy.worker_autoscaling[0]: Refreshing state... [id=arn:aws:iam::***:policy/eks/eks-worker-autoscaling-prod-midwest-mighty-crab20201014134016343400000007] +aws_iam_openid_connect_provider.eks_cluster: Refreshing state... [id=arn:aws:iam::***:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377] +module.eks.aws_security_group_rule.workers_egress_internet[0]: Refreshing state... [id=sgrule-68981973] +module.eks.aws_security_group_rule.workers_ingress_cluster_https[0]: Refreshing state... [id=sgrule-413899233] +module.eks.aws_security_group_rule.cluster_https_worker_ingress[0]: Refreshing state... [id=sgrule-2171936441] +module.eks.aws_security_group_rule.workers_ingress_cluster[0]: Refreshing state... [id=sgrule-3862769421] +module.eks.aws_security_group_rule.workers_ingress_self[0]: Refreshing state... [id=sgrule-174023373] +module.eks.aws_iam_role_policy_attachment.workers_autoscaling[0]: Refreshing state... [id=prod-midwest-mighty-crab20201014134016318400000005-2020101413401727460000000c] +module.eks.aws_iam_role_policy_attachment.workers_AmazonEC2ContainerRegistryReadOnly[0]: Refreshing state... [id=prod-midwest-mighty-crab20201014134016318400000005-2020101413401727060000000b] +module.eks.aws_iam_role_policy_attachment.workers_AmazonEKSWorkerNodePolicy[0]: Refreshing state... [id=prod-midwest-mighty-crab20201014134016318400000005-20201014134017246100000009] +module.eks.aws_iam_role_policy_attachment.workers_AmazonEKS_CNI_Policy[0]: Refreshing state... [id=prod-midwest-mighty-crab20201014134016318400000005-2020101413401734310000000e] +module.eks.aws_iam_instance_profile.workers[0]: Refreshing state... [id=prod-midwest-mighty-crab20201014134017057300000008] +module.eks.aws_iam_role_policy_attachment.workers_additional_policies[0]: Refreshing state... [id=prod-midwest-mighty-crab20201014134016318400000005-20211202190217976000000001] +module.eks.aws_iam_role_policy_attachment.workers_additional_policies[2]: Refreshing state... [id=prod-midwest-mighty-crab20201014134016318400000005-20211202190217978100000002] +module.eks.aws_iam_role_policy_attachment.workers_additional_policies[1]: Refreshing state... [id=prod-midwest-mighty-crab20201014134016318400000005-20211202190218001700000003] +module.eks_namespace_cert_manager.kubernetes_namespace.this[0]: Refreshing state... [id=cert-manager] +module.eks_namespace_traefik.kubernetes_namespace.this[0]: Refreshing state... [id=traefik] +module.eks_namespace_terminus_system.kubernetes_namespace.this[0]: Refreshing state... [id=terminus-system] +module.eks_namespace_linkerd.kubernetes_namespace.this[0]: Refreshing state... [id=linkerd] +kubernetes_cluster_role.node_drainer[0]: Refreshing state... [id=system:node-drainer] +kubernetes_cluster_role.crd_read_access[0]: Refreshing state... [id=view-crd] +kubernetes_cluster_role.global_read_access[0]: Refreshing state... [id=view-everything] +kubernetes_cluster_role_binding.read_access[0]: Refreshing state... [id=view] +kubernetes_cluster_role.traefik_crd_view: Refreshing state... [id=traefik-view] +kubernetes_cluster_role.traefik_crd_edit: Refreshing state... [id=traefik-edit] +kubernetes_cluster_role.fargate_datadog_agent: Refreshing state... [id=fargate-datadog-agent] +kubernetes_cluster_role.linkerd_crd_edit: Refreshing state... [id=linkerd-edit] +kubernetes_cluster_role.linkerd_crd_view: Refreshing state... [id=linkerd-view] +module.eks.aws_launch_configuration.workers[0]: Refreshing state... [id=prod-midwest-mighty-crab-apps20211116020406559000000001] +module.eks_namespace_linkerd.kubernetes_role.full_access[0]: Refreshing state... [id=linkerd/full-access] +module.eks_namespace_cert_manager.kubernetes_role.full_access[0]: Refreshing state... [id=cert-manager/full-access] +module.eks_namespace_terminus_system.kubernetes_role.read_only[0]: Refreshing state... [id=terminus-system/read-only] +module.eks_namespace_linkerd.kubernetes_role.read_only[0]: Refreshing state... [id=linkerd/read-only] +module.eks_namespace_cert_manager.kubernetes_role.read_only[0]: Refreshing state... [id=cert-manager/read-only] +module.eks_namespace_terminus_system.kubernetes_role.full_access[0]: Refreshing state... [id=terminus-system/full-access] +module.eks_namespace_traefik.kubernetes_role.read_only[0]: Refreshing state... [id=traefik/read-only] +module.eks_namespace_traefik.kubernetes_role.full_access[0]: Refreshing state... [id=traefik/full-access] +kubernetes_cluster_role_binding.node_drainer[0]: Refreshing state... [id=node-drainer] +kubernetes_ingress.traefik_alb[0]: Refreshing state... [id=traefik/traefik-alb] +module.eks.random_pet.workers[0]: Refreshing state... [id=divine-sloth] +module.cert_manager.helm_release.cert_manager[0]: Refreshing state... [id=cert-manager] +helm_release.datadog[0]: Refreshing state... [id=datadog] +kubernetes_ingress.traefik_internal_alb[0]: Refreshing state... [id=traefik/traefik-internal-alb] +module.eks_namespace_cert_manager.kubernetes_role_binding.full_access[0]: Refreshing state... [id=cert-manager/full-access] +module.eks_namespace_linkerd.kubernetes_role_binding.full_access[0]: Refreshing state... [id=linkerd/full-access] +module.eks_namespace_terminus_system.kubernetes_role_binding.full_access[0]: Refreshing state... [id=terminus-system/full-access] +module.eks_namespace_terminus_system.kubernetes_role_binding.read_only[0]: Refreshing state... [id=terminus-system/read-only] +module.eks_namespace_cert_manager.kubernetes_role_binding.read_only[0]: Refreshing state... [id=cert-manager/read-only] +module.eks_namespace_linkerd.kubernetes_role_binding.read_only[0]: Refreshing state... [id=linkerd/read-only] +module.eks_namespace_traefik.kubernetes_role_binding.full_access[0]: Refreshing state... [id=traefik/full-access] +kubernetes_manifest.cni-metrics-helper-cluster-role-binding: Refreshing state... +module.eks_namespace_traefik.kubernetes_role_binding.read_only[0]: Refreshing state... [id=traefik/read-only] +aws_iam_role.external_dns[0]: Refreshing state... [id=external-dns] +aws_iam_role.ingress_controller[0]: Refreshing state... [id=aws-alb-ingress-controller] +module.eks.aws_autoscaling_group.workers[0]: Refreshing state... [id=prod-midwest-mighty-crab-apps-divine-sloth20211116020407529900000002] +kubernetes_manifest.cni-metrics-helper-cluster-role: Refreshing state... +module.external_dns_terminustools.aws_iam_role.external_dns[0]: Refreshing state... [id=terminustools-external-dns] +module.external_dns_terminusplatform.aws_iam_role.external_dns[0]: Refreshing state... [id=terminusplatform-external-dns] +kubernetes_manifest.cni-metrics-helper-service-account: Refreshing state... +module.eks.kubernetes_config_map.aws_auth[0]: Refreshing state... [id=kube-system/aws-auth] +aws_cloudwatch_event_rule.ec2_state_transition[0]: Refreshing state... [id=prod-midwest-mighty-crab-capture-ec2-terminating] +kubernetes_manifest.cni-metrics-helper-deployment: Refreshing state... +aws_eks_addon.kube_proxy[0]: Refreshing state... [id=prod-midwest-mighty-crab:kube-proxy] +aws_eks_addon.core_dns[0]: Refreshing state... [id=prod-midwest-mighty-crab:coredns] +aws_eks_addon.vpc_cni[0]: Refreshing state... [id=prod-midwest-mighty-crab:vpc-cni] +module.eks_namespace_linkerd_viz.kubernetes_namespace.this[0]: Refreshing state... [id=linkerd-dashboard] +module.eks_namespace_linkerd_cni.kubernetes_namespace.this[0]: Refreshing state... [id=linkerd-cni] +aws_cloudwatch_event_target.ec2_state_transition[0]: Refreshing state... [id=prod-midwest-mighty-crab-capture-ec2-terminating-terraform-20201014134109541700000011] +helm_release.external_dns[0]: Refreshing state... [id=external-dns] +aws_iam_role_policy.external_dns[0]: Refreshing state... [id=external-dns:external-dns-r53-access] +module.eks_namespace_linkerd_viz.kubernetes_role.read_only[0]: Refreshing state... [id=linkerd-dashboard/read-only] +module.eks_namespace_linkerd_viz.kubernetes_role.full_access[0]: Refreshing state... [id=linkerd-dashboard/full-access] +module.eks_namespace_linkerd_cni.kubernetes_role.read_only[0]: Refreshing state... [id=linkerd-cni/read-only] +module.eks_namespace_linkerd_cni.kubernetes_role.full_access[0]: Refreshing state... [id=linkerd-cni/full-access] +helm_release.ingress_controller[0]: Refreshing state... [id=aws-alb-ingress-controller] +aws_iam_role_policy.ingress_controller[0]: Refreshing state... [id=aws-alb-ingress-controller:eks-ingress-controller-alb-mgmt] +module.eks_namespace_linkerd_viz.kubernetes_role_binding.read_only[0]: Refreshing state... [id=linkerd-dashboard/read-only] +module.eks_namespace_linkerd_cni.kubernetes_role_binding.read_only[0]: Refreshing state... [id=linkerd-cni/read-only] +module.eks_namespace_linkerd_viz.kubernetes_role_binding.full_access[0]: Refreshing state... [id=linkerd-dashboard/full-access] +module.eks_namespace_linkerd_cni.kubernetes_role_binding.full_access[0]: Refreshing state... [id=linkerd-cni/full-access] +module.external_dns_terminustools.aws_iam_role_policy.external_dns[0]: Refreshing state... [id=terminustools-external-dns:external-dns-r53-access] +module.external_dns_terminustools.helm_release.external_dns[0]: Refreshing state... [id=terminustools-external-dns] +module.external_dns_terminusplatform.helm_release.external_dns[0]: Refreshing state... [id=terminusplatform-external-dns] +module.external_dns_terminusplatform.aws_iam_role_policy.external_dns[0]: Refreshing state... [id=terminusplatform-external-dns:external-dns-r53-access] +module.linkerd.null_resource.module_depends_on["cert_manager_status"]: Refreshing state... [id=3587086136560643959] +module.linkerd.tls_private_key.linkerd_trust_anchor[0]: Refreshing state... [id=1a4525564825f95e44b33bc6e28adb745387bf33] +module.linkerd.tls_self_signed_cert.linkerd_trust_anchor[0]: Refreshing state... [id=316199143599888869802368478346395450892] +module.linkerd.kubernetes_secret.linkerd_trust_anchor[0]: Refreshing state... [id=linkerd/linkerd-trust-anchor] +module.linkerd.helm_release.linkerd_ca[0]: Refreshing state... [id=linkerd-ca] +module.linkerd.helm_release.linkerd[0]: Refreshing state... [id=linkerd] +module.linkerd.helm_release.linkerd_viz[0]: Refreshing state... [id=linkerd-viz] +module.linkerd.helm_release.linkerd_cni[0]: Refreshing state... [id=linkerd-cni] +module.traefik.null_resource.module_depends_on["linkerd_ca_status"]: Refreshing state... [id=5396547641986912147] +module.traefik.null_resource.module_depends_on["linkerd_status"]: Refreshing state... [id=9019411834470927621] +module.traefik.helm_release.traefik[0]: Refreshing state... [id=traefik] +module.linkerd.helm_release.linkerd_viz_ingress[0]: Refreshing state... [id=linkerd-viz-ingress] +module.traefik.helm_release.traefik_dashboard_ingress[0]: Refreshing state... [id=traefik-dashboard-ingress] +module.traefik.helm_release.traefik_forward_auth_traefik_dashboard[0]: Refreshing state... [id=okta-traefik-dashboard] +module.traefik.helm_release.traefik_forward_auth_linkerd_viz[0]: Refreshing state... [id=traefik-forward-auth-linkerd-viz] +module.traefik.helm_release.middleware[0]: Refreshing state... [id=middleware] +module.eks_namespace_botkube.kubernetes_namespace.this[0]: Refreshing state... [id=botkube] +module.eks_namespace_botkube.kubernetes_role.read_only[0]: Refreshing state... [id=botkube/read-only] +module.eks_namespace_botkube.kubernetes_role.full_access[0]: Refreshing state... [id=botkube/full-access] +module.eks_namespace_botkube.kubernetes_role_binding.read_only[0]: Refreshing state... [id=botkube/read-only] +module.eks_namespace_botkube.kubernetes_role_binding.full_access[0]: Refreshing state... [id=botkube/full-access] +module.botkube[0].helm_release.botkube[0]: Refreshing state... [id=botkube] + +An execution plan has been generated and is shown below. +Resource actions are indicated with the following symbols: + ~ update in-place ++/- create replacement and then destroy + <= read (data resources) + +Terraform will perform the following actions: + + # aws_iam_role.external_dns[0] will be updated in-place + ~ resource "aws_iam_role" "external_dns" { + ~ assume_role_policy = jsonencode( + { + - Statement = [ + - { + - Action = "sts:AssumeRoleWithWebIdentity" + - Condition = { + - StringLike = { + - oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377:sub = "system:serviceaccount:terminus-system:*" + } + } + - Effect = "Allow" + - Principal = { + - Federated = "arn:aws:iam::***:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377" + } + - Sid = "" + }, + ] + - Version = "2012-10-17" + } + ) -> (known after apply) + id = "external-dns" + name = "external-dns" + tags = { + "DeploymentName" = "EKS" + "Environment" = "Production" + "ManagedBy" = "https://github.com/GetTerminus/eks-infra" + "ServiceName" = "EKS" + "Shared" = "True" + "Team" = "SRE" + } + # (9 unchanged attributes hidden) + + # (1 unchanged block hidden) + } + + # aws_iam_role.ingress_controller[0] will be updated in-place + ~ resource "aws_iam_role" "ingress_controller" { + ~ assume_role_policy = jsonencode( + { + - Statement = [ + - { + - Action = "sts:AssumeRoleWithWebIdentity" + - Condition = { + - StringLike = { + - oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377:sub = "system:serviceaccount:terminus-system:*" + } + } + - Effect = "Allow" + - Principal = { + - Federated = "arn:aws:iam::***:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377" + } + - Sid = "" + }, + ] + - Version = "2012-10-17" + } + ) -> (known after apply) + id = "aws-alb-ingress-controller" + name = "aws-alb-ingress-controller" + tags = { + "DeploymentName" = "EKS" + "Environment" = "Production" + "ManagedBy" = "https://github.com/GetTerminus/eks-infra" + "ServiceName" = "EKS" + "Shared" = "True" + "Team" = "SRE" + } + # (9 unchanged attributes hidden) + + # (1 unchanged block hidden) + } + + # module.botkube[0].data.template_file.botkube_values will be read during apply + # (config refers to values not yet known) + <= data "template_file" "botkube_values" { + ~ id = "8652a3dd0df5cad1b3ef3685dc07e5cedc771920f0a51d3f7bacc6925e7945a2" -> (known after apply) + ~ rendered = <<-EOT + # Values for BotKube. + # This is a YAML-formatted file. + + image: + repository: infracloudio/botkube + tag: v0.12.3 + + config: + ## Resources you want to watch + resources: + - name: v1/pods # Name of the resource. Resource name must be in group/version/resource (G/V/R) format + # resource name should be plural (e.g apps/v1/deployments, v1/pods) + namespaces: # List of namespaces, "all" will watch all the namespaces + include: + - all + ignore: # List of namespaces to be ignored (omitempty), used only with include: all, can contain a wildcard (*) + - # example : include [all], ignore [x,y,secret-ns-*] + events: # List of lifecycle events you want to receive, e.g create, update, delete, error OR all + - error + - name: v1/services + namespaces: + include: + - all + ignore: + - + events: + - error + - name: apps/v1/deployments + namespaces: + include: + - all + ignore: + - + events: + - error + updateSetting: + includeDiff: true + fields: + - spec.template.spec.containers[*].image + - status.availableReplicas + - name: apps/v1/statefulsets + namespaces: + include: + - all + ignore: + - + events: + - error + updateSetting: + includeDiff: true + fields: + - spec.template.spec.containers[*].image + - status.readyReplicas + - name: networking.k8s.io/v1beta1/ingresses + namespaces: + include: + - all + ignore: + - + events: + - error + - name: v1/nodes + namespaces: + include: + - all + ignore: + - + events: + - error + - name: v1/namespaces + namespaces: + include: + - all + ignore: + - + events: + - error + - name: v1/persistentvolumes + namespaces: + include: + - all + ignore: + - + events: + - error + - name: v1/persistentvolumeclaims + namespaces: + include: + - all + ignore: + - + events: + - error + - name: v1/configmaps + namespaces: + include: + - all + ignore: + - + events: + - error + - name: apps/v1/daemonsets + namespaces: + include: + - all + ignore: + - + events: + - error + updateSetting: + includeDiff: true + fields: + - spec.template.spec.containers[*].image + - status.numberReady + - name: batch/v1/jobs + namespaces: + include: + - all + ignore: + - + events: + - error + updateSetting: + includeDiff: true + fields: + - spec.template.spec.containers[*].image + - status.conditions[*].type + - name: rbac.authorization.k8s.io/v1/roles + namespaces: + include: + - all + ignore: + - + events: + - error + - name: rbac.authorization.k8s.io/v1/rolebindings + namespaces: + include: + - all + ignore: + - + events: + - error + - name: rbac.authorization.k8s.io/v1/clusterrolebindings + namespaces: + include: + - all + ignore: + - + events: + - error + - name: rbac.authorization.k8s.io/v1/clusterroles + namespaces: + include: + - all + ignore: + - + events: + - create + - delete + - error + # Custom resource + - name: traefik.containo.us/v1alpha1/IngressRoute + namespaces: + include: + - all + ignore: + - + events: + - error + updateSetting: + includeDiff: true + fields: + - status.phase + + # Setting to support multiple clusters + settings: + # Cluster name to differentiate incoming messages + clustername: prod-midwest + # Kubectl executor configs + kubectl: + # Set true to enable kubectl commands execution + enabled: false + + + # Communication settings + communications: + + # Using existing Communication secret + existingSecretName: "" + + # Settings for Slack + slack: + enabled: true + channel: k8s-prod-midwest # Slack channel name without '#' prefix where you have added BotKube and want to receive notifications in + token: xoxb-6726794291-2448694983552-hIZnqC8votMn0jD4UXHkaKbi + notiftype: short # Change notification type short/long you want to receive. notiftype is optional and Default notification type is short (if not specified) + + + serviceAccount: + + # annotations for the service account + annotations: + eks.amazonaws.com/role-arn: arn:aws:iam::***:role/eks/eks-readonly + EOT -> (known after apply) + # (2 unchanged attributes hidden) + } + + # module.botkube[0].helm_release.botkube[0] will be updated in-place + ~ resource "helm_release" "botkube" { + id = "botkube" + name = "botkube" + ~ values = [ + - <<-EOT + # Values for BotKube. + # This is a YAML-formatted file. + + image: + repository: infracloudio/botkube + tag: v0.12.3 + + config: + ## Resources you want to watch + resources: + - name: v1/pods # Name of the resource. Resource name must be in group/version/resource (G/V/R) format + # resource name should be plural (e.g apps/v1/deployments, v1/pods) + namespaces: # List of namespaces, "all" will watch all the namespaces + include: + - all + ignore: # List of namespaces to be ignored (omitempty), used only with include: all, can contain a wildcard (*) + - # example : include [all], ignore [x,y,secret-ns-*] + events: # List of lifecycle events you want to receive, e.g create, update, delete, error OR all + - error + - name: v1/services + namespaces: + include: + - all + ignore: + - + events: + - error + - name: apps/v1/deployments + namespaces: + include: + - all + ignore: + - + events: + - error + updateSetting: + includeDiff: true + fields: + - spec.template.spec.containers[*].image + - status.availableReplicas + - name: apps/v1/statefulsets + namespaces: + include: + - all + ignore: + - + events: + - error + updateSetting: + includeDiff: true + fields: + - spec.template.spec.containers[*].image + - status.readyReplicas + - name: networking.k8s.io/v1beta1/ingresses + namespaces: + include: + - all + ignore: + - + events: + - error + - name: v1/nodes + namespaces: + include: + - all + ignore: + - + events: + - error + - name: v1/namespaces + namespaces: + include: + - all + ignore: + - + events: + - error + - name: v1/persistentvolumes + namespaces: + include: + - all + ignore: + - + events: + - error + - name: v1/persistentvolumeclaims + namespaces: + include: + - all + ignore: + - + events: + - error + - name: v1/configmaps + namespaces: + include: + - all + ignore: + - + events: + - error + - name: apps/v1/daemonsets + namespaces: + include: + - all + ignore: + - + events: + - error + updateSetting: + includeDiff: true + fields: + - spec.template.spec.containers[*].image + - status.numberReady + - name: batch/v1/jobs + namespaces: + include: + - all + ignore: + - + events: + - error + updateSetting: + includeDiff: true + fields: + - spec.template.spec.containers[*].image + - status.conditions[*].type + - name: rbac.authorization.k8s.io/v1/roles + namespaces: + include: + - all + ignore: + - + events: + - error + - name: rbac.authorization.k8s.io/v1/rolebindings + namespaces: + include: + - all + ignore: + - + events: + - error + - name: rbac.authorization.k8s.io/v1/clusterrolebindings + namespaces: + include: + - all + ignore: + - + events: + - error + - name: rbac.authorization.k8s.io/v1/clusterroles + namespaces: + include: + - all + ignore: + - + events: + - create + - delete + - error + # Custom resource + - name: traefik.containo.us/v1alpha1/IngressRoute + namespaces: + include: + - all + ignore: + - + events: + - error + updateSetting: + includeDiff: true + fields: + - status.phase + + # Setting to support multiple clusters + settings: + # Cluster name to differentiate incoming messages + clustername: prod-midwest + # Kubectl executor configs + kubectl: + # Set true to enable kubectl commands execution + enabled: false + + + # Communication settings + communications: + + # Using existing Communication secret + existingSecretName: "" + + # Settings for Slack + slack: + enabled: true + channel: k8s-prod-midwest # Slack channel name without '#' prefix where you have added BotKube and want to receive notifications in + token: xoxb-6726794291-2448694983552-hIZnqC8votMn0jD4UXHkaKbi + notiftype: short # Change notification type short/long you want to receive. notiftype is optional and Default notification type is short (if not specified) + + + serviceAccount: + + # annotations for the service account + annotations: + eks.amazonaws.com/role-arn: arn:aws:iam::***:role/eks/eks-readonly + EOT, + ] -> (known after apply) + # (25 unchanged attributes hidden) + } + + # module.eks.data.aws_iam_policy_document.worker_autoscaling will be read during apply + # (config refers to values not yet known) + <= data "aws_iam_policy_document" "worker_autoscaling" { + ~ id = "3978599367" -> (known after apply) + ~ json = jsonencode( + { + - Statement = [ + - { + - Action = [ + - "ec2:DescribeLaunchTemplateVersions", + - "autoscaling:DescribeTags", + - "autoscaling:DescribeLaunchConfigurations", + - "autoscaling:DescribeAutoScalingInstances", + - "autoscaling:DescribeAutoScalingGroups", + ] + - Effect = "Allow" + - Resource = "*" + - Sid = "eksWorkerAutoscalingAll" + }, + - { + - Action = [ + - "autoscaling:UpdateAutoScalingGroup", + - "autoscaling:TerminateInstanceInAutoScalingGroup", + - "autoscaling:SetDesiredCapacity", + ] + - Condition = { + - StringEquals = { + - autoscaling:ResourceTag/k8s.io/cluster-autoscaler/enabled = "true" + - autoscaling:ResourceTag/kubernetes.io/cluster/prod-midwest-mighty-crab = "owned" + } + } + - Effect = "Allow" + - Resource = "*" + - Sid = "eksWorkerAutoscalingOwn" + }, + ] + - Version = "2012-10-17" + } + ) -> (known after apply) + - version = "2012-10-17" -> null + + ~ statement { + - not_actions = [] -> null + - not_resources = [] -> null + # (4 unchanged attributes hidden) + } + ~ statement { + - not_actions = [] -> null + - not_resources = [] -> null + # (4 unchanged attributes hidden) + + # (2 unchanged blocks hidden) + } + } + + # module.eks.data.template_file.config_map_aws_auth will be read during apply + # (config refers to values not yet known) + <= data "template_file" "config_map_aws_auth" { + ~ id = "825b24ec2d3a1f36c24c4595d9f253591eb996a308a1654ea4a14e93539159be" -> (known after apply) + ~ rendered = <<-EOT + apiVersion: v1 + kind: ConfigMap + metadata: + name: aws-auth + namespace: kube-system + data: + mapRoles: | + - rolearn: arn:aws:iam::***:role/prod-midwest-mighty-crab20201014134016318400000005 + username: system:node:{{EC2PrivateDNSName}} + groups: + - system:bootstrappers + - system:nodes + + + - "groups": + - "system:masters" + "rolearn": "arn:aws:iam::***:role/admin" + "username": "admin" + - "groups": + - "system:masters" + "rolearn": "arn:aws:iam::***:role/eks-admin" + "username": "eks-admin" + - "groups": + - "system:readers" + "rolearn": "arn:aws:iam::***:role/administrator" + "username": "eks-readonly" + - "groups": + - "system:bootstrappers" + - "system:nodes" + - "system:node-proxier" + "rolearn": "arn:aws:iam::***:role/eks-fargate-pod-executor" + "username": "system:node:{{SessionName}}" + + + + mapUsers: | + - "groups": + - "system:readers" + - "team-growflare:admins" + - "team-ramble:admins" + - "team-thundercats:admins" + - "team-warriors:admins" + "userarn": "arn:aws:iam::***:user/humans/andrew.bridges" + "username": "andrew.bridges" + - "groups": + - "system:readers" + "userarn": "arn:aws:iam::***:user/humans/bill.jamison" + "username": "bill.jamison" + - "groups": + - "system:readers" + "userarn": "arn:aws:iam::***:user/humans/brendan.erwin" + "username": "brendan.erwin" + - "groups": + - "system:readers" + - "team-service-corps:admins" + - "team-service-corps:prodsupport_access" + - "team-the-a-team:admins" + - "team-thundercats:admins" + - "system:masters" + - "team-sre:admins" + "userarn": "arn:aws:iam::***:user/humans/brian.malinconico" + "username": "brian.malinconico" + - "groups": + - "system:readers" + - "team-growflare:admins" + - "team-ramble:admins" + - "team-thundercats:admins" + - "team-warriors:admins" + "userarn": "arn:aws:iam::***:user/humans/brian.weissler" + "username": "brian.weissler" + - "groups": + - "system:readers" + - "team-rolling-thunder:admins" + "userarn": "arn:aws:iam::***:user/humans/chris.vannoy" + "username": "chris.vannoy" + - "groups": + - "system:readers" + - "team-rolling-thunder:admins" + "userarn": "arn:aws:iam::***:user/humans/jason.steinhauser" + "username": "jason.steinhauser" + - "groups": + - "system:readers" + - "team-growflare:admins" + - "team-ramble:admins" + - "team-thundercats:admins" + - "team-warriors:admins" + - "team-the-a-team:admins" + "userarn": "arn:aws:iam::***:user/humans/john.barton" + "username": "john.barton" + - "groups": + - "system:readers" + - "team-rolling-thunder:admins" + "userarn": "arn:aws:iam::***:user/humans/jonathan.ascenci" + "username": "jonathan.ascenci" + - "groups": + - "system:readers" + - "team-application-backend:admins" + - "team-thundercats:admins" + - "team-service-corps:prodsupport_access" + "userarn": "arn:aws:iam::***:user/humans/matt.miller" + "username": "matt.miller" + - "groups": + - "system:readers" + - "team-rolling-thunder:admins" + "userarn": "arn:aws:iam::***:user/humans/patrick.gibbons" + "username": "patrick.gibbons" + - "groups": + - "system:readers" + - "team-rolling-thunder:admins" + "userarn": "arn:aws:iam::***:user/humans/robb.phillips" + "username": "robb.phillips" + - "groups": + - "system:readers" + - "team-emailx-contractors:admins" + "userarn": "arn:aws:iam::***:user/humans/sergey.kudryk" + "username": "sergey.kudryk" + - "groups": + - "system:readers" + - "team-growflare:admins" + - "team-ramble:admins" + - "team-thundercats:admins" + - "team-warriors:admins" + - "team-the-a-team:admins" + "userarn": "arn:aws:iam::***:user/humans/tyler.hastings" + "username": "tyler.hastings" + + + + EOT -> (known after apply) + ~ vars = { + ~ "worker_role_arn" = <<-EOT + - rolearn: arn:aws:iam::***:role/prod-midwest-mighty-crab20201014134016318400000005 + username: system:node:{{EC2PrivateDNSName}} + groups: + - system:bootstrappers + - system:nodes + EOT -> (known after apply) + # (3 unchanged elements hidden) + } + # (1 unchanged attribute hidden) + } + + # module.eks.data.template_file.kubeconfig will be read during apply + # (config refers to values not yet known) + <= data "template_file" "kubeconfig" { + ~ id = "2537f0935c2044eba7f6e43bee4a66e3cf9bded2fea1556569e69c6599780c5a" -> (known after apply) + ~ rendered = <<-EOT + apiVersion: v1 + preferences: {} + kind: Config + + clusters: + - cluster: + server: https://52802C254287C012F034999E4B36A377.gr7.us-east-1.eks.amazonaws.com + certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJd01UQXhOREV6TXpjeE4xb1hEVE13TVRBeE1qRXpNemN4TjFvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTkc1CllNcmlUZzBia0g2VlZ1TU5rMmUybEI1Vm45TUtMSDJja1hMNzcvK05FZU5tejZnLzJSV2ZZZ0lucnVmY3gxVTEKZG9yQVU5QU1WT0lnLzhLc2lncmhkcHJvQzZBcmR3aElwRi8vcE5JNjRyVGNwZkFKTHBIYTdIM0lZQSthT0kwawo3RDlyaGZzU2N3cXdkRndnN3gxVS84c3lkY1c3ZmIwQzY0TXBubTQ2MnJuSWtsTk5NdnppdEZDVDNtNlNkNy91CkF2RUJJa01IQWpVanZDcE1hLzlHZlYzVmptSzRZbGtIbVZHQ1cwMThzaWNiNDQxa2s4WlZuU3YzNlVzQWQ3SEUKUm9JK0RBSXRSdjlRR0RCcUJsVFZCU2lqbXBhQjM3TktEa0NkWlNMdi96azZ6MUtpbnRaOFVHZ3Qwd3lHKzJUTQpRL3cvWVk0cU1lanBvRWhCSXZrQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFLbFZQQUYrSXcyTUJETnlRRjQ4SGpWSFlHTGEKWXM0RVZUYmRmTGNGVFB2Q0JuRnR4bFR1OVBXNjMvOVdqSnRqSlVaQ2xmT21UTGZLRFpyb1c2ZU1xTjZGVm9FUgpNSEJzbjR5RkVaLzBDNkVwbWJNRGhSenBOM25Balk1RldmN3lEdHhWS2tWU01mVm9QSWhORy9nckZqYmY5cDNXCnhyQm9kaWtzKzQ2ODNTUktManFhQkJxRVBYT3hOOGd0U3lHMzZNdVZHeVRiZVRDb1RwUDRqUGNDTXN1YU4weXUKd1pXeCtKK1lqVnBmZ2NOMkxHMDBFQTQ2SDVlK0N2NFREcWRjQnVkR0tvYnZXOTNlYW9PcXFQb3B4T3JqY0hvdwpya0ZsVk5QV2paU2Uzbmo1UGFQcFBVZ3YzL0Jnait0c1JkRTM4NkZERTE1N1ZNeUNFUldabHJYd0dJND0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= + name: eks_prod-midwest-mighty-crab + + contexts: + - context: + cluster: eks_prod-midwest-mighty-crab + user: eks_prod-midwest-mighty-crab + name: eks_prod-midwest-mighty-crab + + current-context: eks_prod-midwest-mighty-crab + + users: + - name: eks_prod-midwest-mighty-crab + user: + exec: + apiVersion: client.authentication.k8s.io/v1alpha1 + command: aws-iam-authenticator + args: + - "token" + - "-i" + - "prod-midwest-mighty-crab" + + + EOT -> (known after apply) + # (2 unchanged attributes hidden) + } + + # module.eks.data.template_file.userdata[0] will be read during apply + # (config refers to values not yet known) + <= data "template_file" "userdata" { + ~ id = "89ac0e9d1a05026a8c7f42427f51201350b9e644e1fc670ea23c5eb024eecd17" -> (known after apply) + ~ rendered = <<-EOT + #!/bin/bash -xe + + # Allow user supplied pre userdata code + + + # Bootstrap and join the cluster + /etc/eks/bootstrap.sh --b64-cluster-ca 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJd01UQXhOREV6TXpjeE4xb1hEVE13TVRBeE1qRXpNemN4TjFvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTkc1CllNcmlUZzBia0g2VlZ1TU5rMmUybEI1Vm45TUtMSDJja1hMNzcvK05FZU5tejZnLzJSV2ZZZ0lucnVmY3gxVTEKZG9yQVU5QU1WT0lnLzhLc2lncmhkcHJvQzZBcmR3aElwRi8vcE5JNjRyVGNwZkFKTHBIYTdIM0lZQSthT0kwawo3RDlyaGZzU2N3cXdkRndnN3gxVS84c3lkY1c3ZmIwQzY0TXBubTQ2MnJuSWtsTk5NdnppdEZDVDNtNlNkNy91CkF2RUJJa01IQWpVanZDcE1hLzlHZlYzVmptSzRZbGtIbVZHQ1cwMThzaWNiNDQxa2s4WlZuU3YzNlVzQWQ3SEUKUm9JK0RBSXRSdjlRR0RCcUJsVFZCU2lqbXBhQjM3TktEa0NkWlNMdi96azZ6MUtpbnRaOFVHZ3Qwd3lHKzJUTQpRL3cvWVk0cU1lanBvRWhCSXZrQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFLbFZQQUYrSXcyTUJETnlRRjQ4SGpWSFlHTGEKWXM0RVZUYmRmTGNGVFB2Q0JuRnR4bFR1OVBXNjMvOVdqSnRqSlVaQ2xmT21UTGZLRFpyb1c2ZU1xTjZGVm9FUgpNSEJzbjR5RkVaLzBDNkVwbWJNRGhSenBOM25Balk1RldmN3lEdHhWS2tWU01mVm9QSWhORy9nckZqYmY5cDNXCnhyQm9kaWtzKzQ2ODNTUktManFhQkJxRVBYT3hOOGd0U3lHMzZNdVZHeVRiZVRDb1RwUDRqUGNDTXN1YU4weXUKd1pXeCtKK1lqVnBmZ2NOMkxHMDBFQTQ2SDVlK0N2NFREcWRjQnVkR0tvYnZXOTNlYW9PcXFQb3B4T3JqY0hvdwpya0ZsVk5QV2paU2Uzbmo1UGFQcFBVZ3YzL0Jnait0c1JkRTM4NkZERTE1N1ZNeUNFUldabHJYd0dJND0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=' --apiserver-endpoint 'https://52802C254287C012F034999E4B36A377.gr7.us-east-1.eks.amazonaws.com' --kubelet-extra-args "" 'prod-midwest-mighty-crab' + + # Allow user supplied userdata code + # Post EKS bootstrap user-data + # Increment to trigger rebuilding EKS ASGs: 1 + + # Restrict pod access to the ec2 metadata API. Pods should instead prefer to use Service Accounts annotated with AWS Roles. + # For more information, see https://docs.aws.amazon.com/en_pv/eks/latest/userguide/restrict-ec2-credential-access.html + yum install -y iptables-services + iptables --insert FORWARD 1 --in-interface eni+ --destination 169.254.169.254/32 --jump DROP + iptables-save | tee /etc/sysconfig/iptables + systemctl enable --now iptables + + # Install SSM + yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm + systemctl enable --now amazon-ssm-agent + + # Install kubectl + KUBECTL_VERSION=v1.21.2 + curl -LO https://storage.googleapis.com/kubernetes-release/release/$KUBECTL_VERSION/bin/linux/amd64/kubectl + chmod +x ./kubectl + mv ./kubectl /usr/bin/kubectl + + # Create kubectl config + aws eks --region us-east-1 update-kubeconfig --name prod-midwest-mighty-crab --kubeconfig /opt/kube/config + + # Create the drain-node script + mkdir -p /opt/scripts + cat << 'EOF' > /opt/scripts/drain-node.sh + #!/usr/bin/env bash + + trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM + + REQUESTED_INSTANCE_ID=${1:-none} + remaining_heartbeat_events=${2:-3} + + INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id) + if [[ $REQUESTED_INSTANCE_ID != $INSTANCE_ID ]]; then + echo "kubectl drain requested for $REQUESTED_INSTANCE_ID, not for $INSTANCE_ID. Exiting..." + exit 0 + fi + + set -eu + + K8S_NODE=$(curl -s http://169.254.169.254/latest/meta-data/hostname) + REGION=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed 's/[a-z]$//') + ASG_NAME=$(aws ec2 describe-tags --filters "Name=resource-id,Values=${INSTANCE_ID}" "Name=key,Values=aws:autoscaling:groupName" --region ${REGION} | jq '.Tags[0].Value' -r) + CMD_OPTS="--region ${REGION} --auto-scaling-group-name ${ASG_NAME} --lifecycle-hook-name prod-midwest-mighty-crab-worker-node-termination --instance-id ${INSTANCE_ID}" + + HEARTBEAT_TIMEOUT=$(aws autoscaling describe-lifecycle-hooks --region ${REGION} --auto-scaling-group-name ${ASG_NAME} --lifecycle-hook-names prod-midwest-mighty-crab-worker-node-termination | jq '.LifecycleHooks[0].HeartbeatTimeout') + POLL_EVENTS_UNTIL_HEARTBEAT=$(( $HEARTBEAT_TIMEOUT / 10 - 3 )) + + echo "draining node: $K8S_NODE - $INSTANCE_ID" + kubectl --kubeconfig='/opt/kube/config' drain --force --ignore-daemonsets --delete-local-data ${K8S_NODE} & + PROC_ID=$! + + remaining_poll_events=$POLL_EVENTS_UNTIL_HEARTBEAT + while kill -0 "$PROC_ID" &>/dev/null; do + ((remaining_poll_events--)) + + if (( $remaining_poll_events <= 0 )); then + if (( $remaining_heartbeat_events <= 0 )); then + aws autoscaling complete-lifecycle-action ${CMD_OPTS} --lifecycle-action-result ABORT + exit 1 + else + aws autoscaling record-lifecycle-action-heartbeat ${CMD_OPTS} + ((remaining_heartbeat_events--)) + remaining_poll_events=$POLL_EVENTS_UNTIL_HEARTBEAT + fi + fi + + sleep 10 + done + + aws autoscaling complete-lifecycle-action ${CMD_OPTS} --lifecycle-action-result CONTINUE + EOF + + chmod +x /opt/scripts/drain-node.sh + + EOT -> (known after apply) + # (2 unchanged attributes hidden) + } + + # module.eks.data.template_file.worker_role_arns[0] will be read during apply + # (config refers to values not yet known) + <= data "template_file" "worker_role_arns" { + ~ id = "106d45ac8acfeb546dbf236355bf517dfc56aecb51721493cff08f8f76172e23" -> (known after apply) + ~ rendered = <<-EOT + - rolearn: arn:aws:iam::***:role/prod-midwest-mighty-crab20201014134016318400000005 + username: system:node:{{EC2PrivateDNSName}} + groups: + - system:bootstrappers + - system:nodes + EOT -> (known after apply) + # (2 unchanged attributes hidden) + } + + # module.eks.aws_autoscaling_group.workers[0] must be replaced ++/- resource "aws_autoscaling_group" "workers" { + ~ arn = "arn:aws:autoscaling:us-east-1:***:autoScalingGroup:73c861f7-ac27-42f1-a435-c60a3a3217fd:autoScalingGroupName/prod-midwest-mighty-crab-apps-divine-sloth20211116020407529900000002" -> (known after apply) + ~ availability_zones = [ + - "us-east-1b", + - "us-east-1c", + - "us-east-1d", + ] -> (known after apply) + - capacity_rebalance = false -> null + ~ default_cooldown = 300 -> (known after apply) + - enabled_metrics = [] -> null + ~ health_check_type = "EC2" -> (known after apply) + ~ id = "prod-midwest-mighty-crab-apps-divine-sloth20211116020407529900000002" -> (known after apply) + ~ launch_configuration = "prod-midwest-mighty-crab-apps20211116020406559000000001" -> (known after apply) + - load_balancers = [] -> null + - max_instance_lifetime = 0 -> null + ~ name = "prod-midwest-mighty-crab-apps-divine-sloth20211116020407529900000002" -> (known after apply) + ~ name_prefix = "prod-midwest-mighty-crab-apps-divine-sloth" -> (known after apply) # forces replacement + ~ service_linked_role_arn = "arn:aws:iam::***:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling" -> (known after apply) + ~ tags = [ + + { + + "key" = "karpenter.sh/discovery" + + "propagate_at_launch" = "true" + + "value" = "prod-midwest-mighty-crab" + }, + # (12 unchanged elements hidden) + ] + - target_group_arns = [] -> null + # (12 unchanged attributes hidden) + + # (1 unchanged block hidden) + } + + # module.eks.aws_cloudwatch_log_group.this[0] will be updated in-place + ~ resource "aws_cloudwatch_log_group" "this" { + id = "/aws/eks/prod-midwest-mighty-crab/cluster" + name = "/aws/eks/prod-midwest-mighty-crab/cluster" + ~ tags = { + + "karpenter.sh/discovery" = "prod-midwest-mighty-crab" + # (6 unchanged elements hidden) + } + ~ tags_all = { + + "karpenter.sh/discovery" = "prod-midwest-mighty-crab" + # (6 unchanged elements hidden) + } + # (2 unchanged attributes hidden) + } + + # module.eks.aws_iam_policy.worker_autoscaling[0] will be updated in-place + ~ resource "aws_iam_policy" "worker_autoscaling" { + id = "arn:aws:iam::***:policy/eks/eks-worker-autoscaling-prod-midwest-mighty-crab20201014134016343400000007" + name = "eks-worker-autoscaling-prod-midwest-mighty-crab20201014134016343400000007" + ~ policy = jsonencode( + { + - Statement = [ + - { + - Action = [ + - "ec2:DescribeLaunchTemplateVersions", + - "autoscaling:DescribeTags", + - "autoscaling:DescribeLaunchConfigurations", + - "autoscaling:DescribeAutoScalingInstances", + - "autoscaling:DescribeAutoScalingGroups", + ] + - Effect = "Allow" + - Resource = "*" + - Sid = "eksWorkerAutoscalingAll" + }, + - { + - Action = [ + - "autoscaling:UpdateAutoScalingGroup", + - "autoscaling:TerminateInstanceInAutoScalingGroup", + - "autoscaling:SetDesiredCapacity", + ] + - Condition = { + - StringEquals = { + - autoscaling:ResourceTag/k8s.io/cluster-autoscaler/enabled = "true" + - autoscaling:ResourceTag/kubernetes.io/cluster/prod-midwest-mighty-crab = "owned" + } + } + - Effect = "Allow" + - Resource = "*" + - Sid = "eksWorkerAutoscalingOwn" + }, + ] + - Version = "2012-10-17" + } + ) -> (known after apply) + tags = {} + # (6 unchanged attributes hidden) + } + + # module.eks.aws_iam_role.cluster[0] will be updated in-place + ~ resource "aws_iam_role" "cluster" { + id = "prod-midwest-mighty-crab20201014132921928700000001" + name = "prod-midwest-mighty-crab20201014132921928700000001" + ~ tags = { + + "karpenter.sh/discovery" = "prod-midwest-mighty-crab" + # (6 unchanged elements hidden) + } + ~ tags_all = { + + "karpenter.sh/discovery" = "prod-midwest-mighty-crab" + # (6 unchanged elements hidden) + } + # (9 unchanged attributes hidden) + + # (1 unchanged block hidden) + } + + # module.eks.aws_iam_role.workers[0] will be updated in-place + ~ resource "aws_iam_role" "workers" { + id = "prod-midwest-mighty-crab20201014134016318400000005" + name = "prod-midwest-mighty-crab20201014134016318400000005" + ~ tags = { + + "karpenter.sh/discovery" = "prod-midwest-mighty-crab" + # (6 unchanged elements hidden) + } + ~ tags_all = { + + "karpenter.sh/discovery" = "prod-midwest-mighty-crab" + # (6 unchanged elements hidden) + } + # (9 unchanged attributes hidden) + + # (1 unchanged block hidden) + } + + # module.eks.aws_launch_configuration.workers[0] must be replaced ++/- resource "aws_launch_configuration" "workers" { + ~ arn = "arn:aws:autoscaling:us-east-1:***:launchConfiguration:223aaff3-fb33-47e8-ac0d-82df46010a9a:launchConfigurationName/prod-midwest-mighty-crab-apps20211116020406559000000001" -> (known after apply) + ~ id = "prod-midwest-mighty-crab-apps20211116020406559000000001" -> (known after apply) + + key_name = (known after apply) + ~ name = "prod-midwest-mighty-crab-apps20211116020406559000000001" -> (known after apply) + ~ user_data_base64 = "IyEvYmluL2Jhc2ggLXhlCgojIEFsbG93IHVzZXIgc3VwcGxpZWQgcHJlIHVzZXJkYXRhIGNvZGUKCgojIEJvb3RzdHJhcCBhbmQgam9pbiB0aGUgY2x1c3RlcgovZXRjL2Vrcy9ib290c3RyYXAuc2ggLS1iNjQtY2x1c3Rlci1jYSAnTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVTjVSRU5EUVdKRFowRjNTVUpCWjBsQ1FVUkJUa0puYTNGb2EybEhPWGN3UWtGUmMwWkJSRUZXVFZKTmQwVlJXVVJXVVZGRVJYZHdjbVJYU213S1kyMDFiR1JIVm5wTlFqUllSRlJKZDAxVVFYaE9SRVY2VFhwamVFNHhiMWhFVkUxM1RWUkJlRTFxUlhwTmVtTjRUakZ2ZDBaVVJWUk5Ra1ZIUVRGVlJRcEJlRTFMWVROV2FWcFlTblZhV0ZKc1kzcERRMEZUU1hkRVVWbEtTMjlhU1doMlkwNUJVVVZDUWxGQlJHZG5SVkJCUkVORFFWRnZRMmRuUlVKQlRrYzFDbGxOY21sVVp6QmlhMGcyVmxaMVRVNXJNbVV5YkVJMVZtNDVUVXRNU0RKamExaE1OemN2SzA1RlpVNXRlalpuTHpKU1YyWlpaMGx1Y25WbVkzZ3hWVEVLWkc5eVFWVTVRVTFXVDBsbkx6aExjMmxuY21oa2NISnZRelpCY21SM2FFbHdSaTh2Y0U1Sk5qUnlWR053WmtGS1RIQklZVGRJTTBsWlFTdGhUMGt3YXdvM1JEbHlhR1p6VTJOM2NYZGtSbmRuTjNneFZTODRjM2xrWTFjM1ptSXdRelkwVFhCdWJUUTJNbkp1U1d0c1RrNU5kbnBwZEVaRFZETnRObE5rTnk5MUNrRjJSVUpKYTAxSVFXcFZhblpEY0UxaEx6bEhabFl6Vm1wdFN6UlpiR3RJYlZaSFExY3dNVGh6YVdOaU5EUXhhMnM0V2xadVUzWXpObFZ6UVdRM1NFVUtVbTlKSzBSQlNYUlNkamxSUjBSQ2NVSnNWRlpDVTJscWJYQmhRak0zVGt0RWEwTmtXbE5NZGk5NmF6WjZNVXRwYm5SYU9GVkhaM1F3ZDNsSEt6SlVUUXBSTDNjdldWazBjVTFsYW5CdlJXaENTWFpyUTBGM1JVRkJZVTFxVFVORmQwUm5XVVJXVWpCUVFWRklMMEpCVVVSQlowdHJUVUU0UjBFeFZXUkZkMFZDQ2k5M1VVWk5RVTFDUVdZNGQwUlJXVXBMYjFwSmFIWmpUa0ZSUlV4Q1VVRkVaMmRGUWtGTGJGWlFRVVlyU1hjeVRVSkVUbmxSUmpRNFNHcFdTRmxIVEdFS1dYTTBSVlpVWW1SbVRHTkdWRkIyUTBKdVJuUjRiRlIxT1ZCWE5qTXZPVmRxU25ScVNsVmFRMnhtVDIxVVRHWkxSRnB5YjFjMlpVMXhUalpHVm05RlVncE5TRUp6YmpSNVJrVmFMekJETmtWd2JXSk5SR2hTZW5CT00yNUJhbGsxUmxkbU4zbEVkSGhXUzJ0V1UwMW1WbTlRU1doT1J5OW5ja1pxWW1ZNWNETlhDbmh5UW05a2FXdHpLelEyT0ROVFVrdE1hbkZoUWtKeFJWQllUM2hPT0dkMFUzbEhNelpOZFZaSGVWUmlaVlJEYjFSd1VEUnFVR05EVFhOMVlVNHdlWFVLZDFwWGVDdEtLMWxxVm5CbVoyTk9Na3hITURCRlFUUTJTRFZsSzBOMk5GUkVjV1JqUW5Wa1IwdHZZblpYT1RObFlXOVBjWEZRYjNCNFQzSnFZMGh2ZHdweWEwWnNWazVRVjJwYVUyVXpibW8xVUdGUWNGQlZaM1l6TDBKbmFpdDBjMUprUlRNNE5rWkVSVEUxTjFaTmVVTkZVbGRhYkhKWWQwZEpORDBLTFMwdExTMUZUa1FnUTBWU1ZFbEdTVU5CVkVVdExTMHRMUW89JyAtLWFwaXNlcnZlci1lbmRwb2ludCAnaHR0cHM6Ly81MjgwMkMyNTQyODdDMDEyRjAzNDk5OUU0QjM2QTM3Ny5ncjcudXMtZWFzdC0xLmVrcy5hbWF6b25hd3MuY29tJyAgLS1rdWJlbGV0LWV4dHJhLWFyZ3MgIiIgJ3Byb2QtbWlkd2VzdC1taWdodHktY3JhYicKCiMgQWxsb3cgdXNlciBzdXBwbGllZCB1c2VyZGF0YSBjb2RlCiMgUG9zdCBFS1MgYm9vdHN0cmFwIHVzZXItZGF0YQojIEluY3JlbWVudCB0byB0cmlnZ2VyIHJlYnVpbGRpbmcgRUtTIEFTR3M6IDEKCiMgUmVzdHJpY3QgcG9kIGFjY2VzcyB0byB0aGUgZWMyIG1ldGFkYXRhIEFQSS4gUG9kcyBzaG91bGQgaW5zdGVhZCBwcmVmZXIgdG8gdXNlIFNlcnZpY2UgQWNjb3VudHMgYW5ub3RhdGVkIHdpdGggQVdTIFJvbGVzLgojIEZvciBtb3JlIGluZm9ybWF0aW9uLCBzZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL2VuX3B2L2Vrcy9sYXRlc3QvdXNlcmd1aWRlL3Jlc3RyaWN0LWVjMi1jcmVkZW50aWFsLWFjY2Vzcy5odG1sCnl1bSBpbnN0YWxsIC15IGlwdGFibGVzLXNlcnZpY2VzCmlwdGFibGVzIC0taW5zZXJ0IEZPUldBUkQgMSAtLWluLWludGVyZmFjZSBlbmkrIC0tZGVzdGluYXRpb24gMTY5LjI1NC4xNjkuMjU0LzMyIC0tanVtcCBEUk9QCmlwdGFibGVzLXNhdmUgfCB0ZWUgL2V0Yy9zeXNjb25maWcvaXB0YWJsZXMKc3lzdGVtY3RsIGVuYWJsZSAtLW5vdyBpcHRhYmxlcwoKIyBJbnN0YWxsIFNTTQp5dW0gaW5zdGFsbCAteSBodHRwczovL3MzLmFtYXpvbmF3cy5jb20vZWMyLWRvd25sb2Fkcy13aW5kb3dzL1NTTUFnZW50L2xhdGVzdC9saW51eF9hbWQ2NC9hbWF6b24tc3NtLWFnZW50LnJwbQpzeXN0ZW1jdGwgZW5hYmxlIC0tbm93IGFtYXpvbi1zc20tYWdlbnQKCiMgSW5zdGFsbCBrdWJlY3RsCktVQkVDVExfVkVSU0lPTj12MS4yMS4yCmN1cmwgLUxPIGh0dHBzOi8vc3RvcmFnZS5nb29nbGVhcGlzLmNvbS9rdWJlcm5ldGVzLXJlbGVhc2UvcmVsZWFzZS8kS1VCRUNUTF9WRVJTSU9OL2Jpbi9saW51eC9hbWQ2NC9rdWJlY3RsCmNobW9kICt4IC4va3ViZWN0bAptdiAuL2t1YmVjdGwgL3Vzci9iaW4va3ViZWN0bAoKIyBDcmVhdGUga3ViZWN0bCBjb25maWcKYXdzIGVrcyAtLXJlZ2lvbiB1cy1lYXN0LTEgdXBkYXRlLWt1YmVjb25maWcgLS1uYW1lIHByb2QtbWlkd2VzdC1taWdodHktY3JhYiAtLWt1YmVjb25maWcgL29wdC9rdWJlL2NvbmZpZwoKIyBDcmVhdGUgdGhlIGRyYWluLW5vZGUgc2NyaXB0Cm1rZGlyIC1wIC9vcHQvc2NyaXB0cwpjYXQgPDwgJ0VPRicgPiAvb3B0L3NjcmlwdHMvZHJhaW4tbm9kZS5zaAojIS91c3IvYmluL2VudiBiYXNoCgp0cmFwICJ0cmFwIC0gU0lHVEVSTSAmJiBraWxsIC0tIC0kJCIgU0lHSU5UIFNJR1RFUk0KClJFUVVFU1RFRF9JTlNUQU5DRV9JRD0kezE6LW5vbmV9CnJlbWFpbmluZ19oZWFydGJlYXRfZXZlbnRzPSR7MjotM30KCklOU1RBTkNFX0lEPSQoY3VybCAtcyBodHRwOi8vMTY5LjI1NC4xNjkuMjU0L2xhdGVzdC9tZXRhLWRhdGEvaW5zdGFuY2UtaWQpCmlmIFtbICRSRVFVRVNURURfSU5TVEFOQ0VfSUQgIT0gJElOU1RBTkNFX0lEIF1dOyB0aGVuCiAgZWNobyAia3ViZWN0bCBkcmFpbiByZXF1ZXN0ZWQgZm9yICRSRVFVRVNURURfSU5TVEFOQ0VfSUQsIG5vdCBmb3IgJElOU1RBTkNFX0lELiBFeGl0aW5nLi4uIgogIGV4aXQgMApmaQoKc2V0IC1ldQoKSzhTX05PREU9JChjdXJsIC1zIGh0dHA6Ly8xNjkuMjU0LjE2OS4yNTQvbGF0ZXN0L21ldGEtZGF0YS9ob3N0bmFtZSkKUkVHSU9OPSQoY3VybCAtcyBodHRwOi8vMTY5LjI1NC4xNjkuMjU0L2xhdGVzdC9tZXRhLWRhdGEvcGxhY2VtZW50L2F2YWlsYWJpbGl0eS16b25lIHwgc2VkICdzL1thLXpdJC8vJykKQVNHX05BTUU9JChhd3MgZWMyIGRlc2NyaWJlLXRhZ3MgLS1maWx0ZXJzICJOYW1lPXJlc291cmNlLWlkLFZhbHVlcz0ke0lOU1RBTkNFX0lEfSIgIk5hbWU9a2V5LFZhbHVlcz1hd3M6YXV0b3NjYWxpbmc6Z3JvdXBOYW1lIiAtLXJlZ2lvbiAke1JFR0lPTn0gfCBqcSAnLlRhZ3NbMF0uVmFsdWUnIC1yKQpDTURfT1BUUz0iLS1yZWdpb24gJHtSRUdJT059IC0tYXV0by1zY2FsaW5nLWdyb3VwLW5hbWUgJHtBU0dfTkFNRX0gLS1saWZlY3ljbGUtaG9vay1uYW1lIHByb2QtbWlkd2VzdC1taWdodHktY3JhYi13b3JrZXItbm9kZS10ZXJtaW5hdGlvbiAtLWluc3RhbmNlLWlkICR7SU5TVEFOQ0VfSUR9IgoKSEVBUlRCRUFUX1RJTUVPVVQ9JChhd3MgYXV0b3NjYWxpbmcgZGVzY3JpYmUtbGlmZWN5Y2xlLWhvb2tzIC0tcmVnaW9uICR7UkVHSU9OfSAtLWF1dG8tc2NhbGluZy1ncm91cC1uYW1lICR7QVNHX05BTUV9IC0tbGlmZWN5Y2xlLWhvb2stbmFtZXMgcHJvZC1taWR3ZXN0LW1pZ2h0eS1jcmFiLXdvcmtlci1ub2RlLXRlcm1pbmF0aW9uIHwganEgJy5MaWZlY3ljbGVIb29rc1swXS5IZWFydGJlYXRUaW1lb3V0JykKUE9MTF9FVkVOVFNfVU5USUxfSEVBUlRCRUFUPSQoKCAkSEVBUlRCRUFUX1RJTUVPVVQgLyAxMCAtIDMgKSkKCmVjaG8gImRyYWluaW5nIG5vZGU6ICRLOFNfTk9ERSAtICRJTlNUQU5DRV9JRCIKa3ViZWN0bCAtLWt1YmVjb25maWc9Jy9vcHQva3ViZS9jb25maWcnIGRyYWluIC0tZm9yY2UgLS1pZ25vcmUtZGFlbW9uc2V0cyAtLWRlbGV0ZS1sb2NhbC1kYXRhICR7SzhTX05PREV9ICYKUFJPQ19JRD0kIQoKcmVtYWluaW5nX3BvbGxfZXZlbnRzPSRQT0xMX0VWRU5UU19VTlRJTF9IRUFSVEJFQVQKd2hpbGUga2lsbCAtMCAiJFBST0NfSUQiICY+L2Rldi9udWxsOyBkbwogICgocmVtYWluaW5nX3BvbGxfZXZlbnRzLS0pKQoKICBpZiAoKCAkcmVtYWluaW5nX3BvbGxfZXZlbnRzIDw9IDAgKSk7IHRoZW4KICAgIGlmICgoICRyZW1haW5pbmdfaGVhcnRiZWF0X2V2ZW50cyA8PSAwICkpOyB0aGVuCiAgICAgIGF3cyBhdXRvc2NhbGluZyBjb21wbGV0ZS1saWZlY3ljbGUtYWN0aW9uICR7Q01EX09QVFN9IC0tbGlmZWN5Y2xlLWFjdGlvbi1yZXN1bHQgQUJPUlQKICAgICAgZXhpdCAxCiAgICBlbHNlCiAgICAgIGF3cyBhdXRvc2NhbGluZyByZWNvcmQtbGlmZWN5Y2xlLWFjdGlvbi1oZWFydGJlYXQgJHtDTURfT1BUU30KICAgICAgKChyZW1haW5pbmdfaGVhcnRiZWF0X2V2ZW50cy0tKSkKICAgICAgcmVtYWluaW5nX3BvbGxfZXZlbnRzPSRQT0xMX0VWRU5UU19VTlRJTF9IRUFSVEJFQVQKICAgIGZpCiAgZmkKCiAgc2xlZXAgMTAKZG9uZQoKYXdzIGF1dG9zY2FsaW5nIGNvbXBsZXRlLWxpZmVjeWNsZS1hY3Rpb24gJHtDTURfT1BUU30gLS1saWZlY3ljbGUtYWN0aW9uLXJlc3VsdCBDT05USU5VRQpFT0YKCmNobW9kICt4IC9vcHQvc2NyaXB0cy9kcmFpbi1ub2RlLnNoCgo=" -> (known after apply) # forces replacement + - vpc_classic_link_security_groups = [] -> null + # (8 unchanged attributes hidden) + + + ebs_block_device { + + delete_on_termination = (known after apply) + + device_name = (known after apply) + + encrypted = (known after apply) + + iops = (known after apply) + + no_device = (known after apply) + + snapshot_id = (known after apply) + + throughput = (known after apply) + + volume_size = (known after apply) + + volume_type = (known after apply) + } + + + metadata_options { + + http_endpoint = (known after apply) + + http_put_response_hop_limit = (known after apply) + + http_tokens = (known after apply) + } + + ~ root_block_device { + ~ throughput = 0 -> (known after apply) + # (5 unchanged attributes hidden) + } + } + + # module.eks.aws_security_group.cluster[0] will be updated in-place + ~ resource "aws_security_group" "cluster" { + id = "sg-091ec20585b4dadc2" + name = "prod-midwest-mighty-crab20201014132924932200000004" + ~ tags = { + + "karpenter.sh/discovery" = "prod-midwest-mighty-crab" + # (7 unchanged elements hidden) + } + ~ tags_all = { + + "karpenter.sh/discovery" = "prod-midwest-mighty-crab" + # (7 unchanged elements hidden) + } + # (8 unchanged attributes hidden) + } + + # module.eks.aws_security_group.workers[0] will be updated in-place + ~ resource "aws_security_group" "workers" { + id = "sg-0a85a7dc1373ecf6b" + name = "prod-midwest-mighty-crab20201014134016335300000006" + ~ tags = { + + "karpenter.sh/discovery" = "prod-midwest-mighty-crab" + # (8 unchanged elements hidden) + } + ~ tags_all = { + + "karpenter.sh/discovery" = "prod-midwest-mighty-crab" + # (8 unchanged elements hidden) + } + # (8 unchanged attributes hidden) + } + + # module.eks.random_pet.workers[0] must be replaced ++/- resource "random_pet" "workers" { + ~ id = "divine-sloth" -> (known after apply) + ~ keepers = { + - "lc_name" = "prod-midwest-mighty-crab-apps20211116020406559000000001" + } -> (known after apply) # forces replacement + # (2 unchanged attributes hidden) + } + + # module.eks_namespace_botkube.data.aws_iam_policy_document.irsa_arp[0] will be read during apply + # (config refers to values not yet known) + <= data "aws_iam_policy_document" "irsa_arp" { + ~ id = "92955526" -> (known after apply) + ~ json = jsonencode( + { + - Statement = [ + - { + - Action = "sts:AssumeRoleWithWebIdentity" + - Condition = { + - StringLike = { + - oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377:sub = "system:serviceaccount:botkube:*" + } + } + - Effect = "Allow" + - Principal = { + - Federated = "arn:aws:iam::***:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377" + } + - Sid = "" + }, + ] + - Version = "2012-10-17" + } + ) -> (known after apply) + - version = "2012-10-17" -> null + + ~ statement { + - not_actions = [] -> null + - not_resources = [] -> null + - resources = [] -> null + # (2 unchanged attributes hidden) + + + # (2 unchanged blocks hidden) + } + } + + # module.eks_namespace_botkube.data.github_team.namespace_owners[0] will be read during apply + # (config refers to values not yet known) + <= data "github_team" "namespace_owners" { + ~ description = "SRE/Core" -> (known after apply) + ~ id = "2738563" -> (known after apply) + ~ members = [ + - "jcogilvie", + - "bmalinconico", + - "xStatick", + - "cduddikunta", + - "dreinhardt-terminus", + ] -> (known after apply) + ~ name = "SRE" -> (known after apply) + ~ node_id = "MDQ6VGVhbTI3Mzg1NjM=" -> (known after apply) + ~ permission = "pull" -> (known after apply) + ~ privacy = "closed" -> (known after apply) + ~ repositories = [ + - "bff-monitors", + - "blinkin-lights", + - "buildbox-infra", + - "chat-mqtt-infra", + - "cou-config-service", + - "cou-config-service-infra", + - "creative_asset_library_infra", + - "customer_entitlements_infra", + - "devro-infra", + - "drone-ci", + - "drone-terraform", + - "eks-infra", + - "engagement-metrics-infra", + - "entitlements_exporter_infra", + - "envoy-alpine-base", + - "envoy-convox-sds", + - "external_webhook_delivery_infra", + - "federated-infra-template", + - "helm-charts", + - "infra-terminus-ninja", + - "java-ci-image", + - "linkedin_service_infra", + - "monitor-dashboard", + - "my_terminus_infra", + - "ninja-mailcatcher", + - "notification_service_infra", + - "orb-domain-lookup-infra", + - "platform-browser-identity", + - "platform-browser-identity-infra", + - "platform-users-infra", + - "ramble-infra", + - "s3helper", + - "semi_trusted_entity_proxy_infra", + - "sigstr-devops", + - "slackbot", + - "soylent-green", + - "sre-suggestion-box", + - "terminus-github-actions", + - "terraform-aws-eks", + - "terraform-docker", + - "terraform-midwest", + - "terraform-modules-midwest", + - "terraform-provider-couconfig", + - "terraform-provider-kubernetes", + - "web-event-capture-infra", + - "web_tracking", + ] -> (known after apply) + # (1 unchanged attribute hidden) + } + + # module.eks_namespace_cert_manager.data.aws_iam_policy_document.irsa_arp[0] will be read during apply + # (config refers to values not yet known) + <= data "aws_iam_policy_document" "irsa_arp" { + ~ id = "2296982326" -> (known after apply) + ~ json = jsonencode( + { + - Statement = [ + - { + - Action = "sts:AssumeRoleWithWebIdentity" + - Condition = { + - StringLike = { + - oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377:sub = "system:serviceaccount:cert-manager:*" + } + } + - Effect = "Allow" + - Principal = { + - Federated = "arn:aws:iam::***:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377" + } + - Sid = "" + }, + ] + - Version = "2012-10-17" + } + ) -> (known after apply) + - version = "2012-10-17" -> null + + ~ statement { + - not_actions = [] -> null + - not_resources = [] -> null + - resources = [] -> null + # (2 unchanged attributes hidden) + + + # (2 unchanged blocks hidden) + } + } + + # module.eks_namespace_linkerd.data.aws_iam_policy_document.irsa_arp[0] will be read during apply + # (config refers to values not yet known) + <= data "aws_iam_policy_document" "irsa_arp" { + ~ id = "508379009" -> (known after apply) + ~ json = jsonencode( + { + - Statement = [ + - { + - Action = "sts:AssumeRoleWithWebIdentity" + - Condition = { + - StringLike = { + - oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377:sub = "system:serviceaccount:linkerd:*" + } + } + - Effect = "Allow" + - Principal = { + - Federated = "arn:aws:iam::***:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377" + } + - Sid = "" + }, + ] + - Version = "2012-10-17" + } + ) -> (known after apply) + - version = "2012-10-17" -> null + + ~ statement { + - not_actions = [] -> null + - not_resources = [] -> null + - resources = [] -> null + # (2 unchanged attributes hidden) + + + # (2 unchanged blocks hidden) + } + } + + # module.eks_namespace_linkerd_cni.data.aws_iam_policy_document.irsa_arp[0] will be read during apply + # (config refers to values not yet known) + <= data "aws_iam_policy_document" "irsa_arp" { + ~ id = "8469501" -> (known after apply) + ~ json = jsonencode( + { + - Statement = [ + - { + - Action = "sts:AssumeRoleWithWebIdentity" + - Condition = { + - StringLike = { + - oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377:sub = "system:serviceaccount:linkerd-cni:*" + } + } + - Effect = "Allow" + - Principal = { + - Federated = "arn:aws:iam::***:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377" + } + - Sid = "" + }, + ] + - Version = "2012-10-17" + } + ) -> (known after apply) + - version = "2012-10-17" -> null + + ~ statement { + - not_actions = [] -> null + - not_resources = [] -> null + - resources = [] -> null + # (2 unchanged attributes hidden) + + + # (2 unchanged blocks hidden) + } + } + + # module.eks_namespace_linkerd_cni.data.github_team.namespace_owners[0] will be read during apply + # (config refers to values not yet known) + <= data "github_team" "namespace_owners" { + ~ description = "SRE/Core" -> (known after apply) + ~ id = "2738563" -> (known after apply) + ~ members = [ + - "jcogilvie", + - "bmalinconico", + - "xStatick", + - "cduddikunta", + - "dreinhardt-terminus", + ] -> (known after apply) + ~ name = "SRE" -> (known after apply) + ~ node_id = "MDQ6VGVhbTI3Mzg1NjM=" -> (known after apply) + ~ permission = "pull" -> (known after apply) + ~ privacy = "closed" -> (known after apply) + ~ repositories = [ + - "bff-monitors", + - "blinkin-lights", + - "buildbox-infra", + - "chat-mqtt-infra", + - "cou-config-service", + - "cou-config-service-infra", + - "creative_asset_library_infra", + - "customer_entitlements_infra", + - "devro-infra", + - "drone-ci", + - "drone-terraform", + - "eks-infra", + - "engagement-metrics-infra", + - "entitlements_exporter_infra", + - "envoy-alpine-base", + - "envoy-convox-sds", + - "external_webhook_delivery_infra", + - "federated-infra-template", + - "helm-charts", + - "infra-terminus-ninja", + - "java-ci-image", + - "linkedin_service_infra", + - "monitor-dashboard", + - "my_terminus_infra", + - "ninja-mailcatcher", + - "notification_service_infra", + - "orb-domain-lookup-infra", + - "platform-browser-identity", + - "platform-browser-identity-infra", + - "platform-users-infra", + - "ramble-infra", + - "s3helper", + - "semi_trusted_entity_proxy_infra", + - "sigstr-devops", + - "slackbot", + - "soylent-green", + - "sre-suggestion-box", + - "terminus-github-actions", + - "terraform-aws-eks", + - "terraform-docker", + - "terraform-midwest", + - "terraform-modules-midwest", + - "terraform-provider-couconfig", + - "terraform-provider-kubernetes", + - "web-event-capture-infra", + - "web_tracking", + ] -> (known after apply) + # (1 unchanged attribute hidden) + } + + # module.eks_namespace_linkerd_viz.data.aws_iam_policy_document.irsa_arp[0] will be read during apply + # (config refers to values not yet known) + <= data "aws_iam_policy_document" "irsa_arp" { + ~ id = "1696330123" -> (known after apply) + ~ json = jsonencode( + { + - Statement = [ + - { + - Action = "sts:AssumeRoleWithWebIdentity" + - Condition = { + - StringLike = { + - oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377:sub = "system:serviceaccount:linkerd-dashboard:*" + } + } + - Effect = "Allow" + - Principal = { + - Federated = "arn:aws:iam::***:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377" + } + - Sid = "" + }, + ] + - Version = "2012-10-17" + } + ) -> (known after apply) + - version = "2012-10-17" -> null + + ~ statement { + - not_actions = [] -> null + - not_resources = [] -> null + - resources = [] -> null + # (2 unchanged attributes hidden) + + + # (2 unchanged blocks hidden) + } + } + + # module.eks_namespace_linkerd_viz.data.github_team.namespace_owners[0] will be read during apply + # (config refers to values not yet known) + <= data "github_team" "namespace_owners" { + ~ description = "SRE/Core" -> (known after apply) + ~ id = "2738563" -> (known after apply) + ~ members = [ + - "jcogilvie", + - "bmalinconico", + - "xStatick", + - "cduddikunta", + - "dreinhardt-terminus", + ] -> (known after apply) + ~ name = "SRE" -> (known after apply) + ~ node_id = "MDQ6VGVhbTI3Mzg1NjM=" -> (known after apply) + ~ permission = "pull" -> (known after apply) + ~ privacy = "closed" -> (known after apply) + ~ repositories = [ + - "bff-monitors", + - "blinkin-lights", + - "buildbox-infra", + - "chat-mqtt-infra", + - "cou-config-service", + - "cou-config-service-infra", + - "creative_asset_library_infra", + - "customer_entitlements_infra", + - "devro-infra", + - "drone-ci", + - "drone-terraform", + - "eks-infra", + - "engagement-metrics-infra", + - "entitlements_exporter_infra", + - "envoy-alpine-base", + - "envoy-convox-sds", + - "external_webhook_delivery_infra", + - "federated-infra-template", + - "helm-charts", + - "infra-terminus-ninja", + - "java-ci-image", + - "linkedin_service_infra", + - "monitor-dashboard", + - "my_terminus_infra", + - "ninja-mailcatcher", + - "notification_service_infra", + - "orb-domain-lookup-infra", + - "platform-browser-identity", + - "platform-browser-identity-infra", + - "platform-users-infra", + - "ramble-infra", + - "s3helper", + - "semi_trusted_entity_proxy_infra", + - "sigstr-devops", + - "slackbot", + - "soylent-green", + - "sre-suggestion-box", + - "terminus-github-actions", + - "terraform-aws-eks", + - "terraform-docker", + - "terraform-midwest", + - "terraform-modules-midwest", + - "terraform-provider-couconfig", + - "terraform-provider-kubernetes", + - "web-event-capture-infra", + - "web_tracking", + ] -> (known after apply) + # (1 unchanged attribute hidden) + } + + # module.eks_namespace_terminus_system.data.aws_iam_policy_document.irsa_arp[0] will be read during apply + # (config refers to values not yet known) + <= data "aws_iam_policy_document" "irsa_arp" { + ~ id = "3724886838" -> (known after apply) + ~ json = jsonencode( + { + - Statement = [ + - { + - Action = "sts:AssumeRoleWithWebIdentity" + - Condition = { + - StringLike = { + - oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377:sub = "system:serviceaccount:terminus-system:*" + } + } + - Effect = "Allow" + - Principal = { + - Federated = "arn:aws:iam::***:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377" + } + - Sid = "" + }, + ] + - Version = "2012-10-17" + } + ) -> (known after apply) + - version = "2012-10-17" -> null + + ~ statement { + - not_actions = [] -> null + - not_resources = [] -> null + - resources = [] -> null + # (2 unchanged attributes hidden) + + + # (2 unchanged blocks hidden) + } + } + + # module.eks_namespace_traefik.data.aws_iam_policy_document.irsa_arp[0] will be read during apply + # (config refers to values not yet known) + <= data "aws_iam_policy_document" "irsa_arp" { + ~ id = "3390182712" -> (known after apply) + ~ json = jsonencode( + { + - Statement = [ + - { + - Action = "sts:AssumeRoleWithWebIdentity" + - Condition = { + - StringLike = { + - oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377:sub = "system:serviceaccount:traefik:*" + } + } + - Effect = "Allow" + - Principal = { + - Federated = "arn:aws:iam::***:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377" + } + - Sid = "" + }, + ] + - Version = "2012-10-17" + } + ) -> (known after apply) + - version = "2012-10-17" -> null + + ~ statement { + - not_actions = [] -> null + - not_resources = [] -> null + - resources = [] -> null + # (2 unchanged attributes hidden) + + + # (2 unchanged blocks hidden) + } + } + + # module.eks_vpc.aws_subnet.private[0] will be updated in-place + ~ resource "aws_subnet" "private" { + id = "subnet-0dd47e406fc214453" + ~ tags = { + + "karpenter.sh/discovery" = "prod-midwest-mighty-crab" + # (9 unchanged elements hidden) + } + ~ tags_all = { + + "karpenter.sh/discovery" = "prod-midwest-mighty-crab" + # (9 unchanged elements hidden) + } + # (14 unchanged attributes hidden) + } + + # module.eks_vpc.aws_subnet.private[1] will be updated in-place + ~ resource "aws_subnet" "private" { + id = "subnet-04c14856ef9593c5a" + ~ tags = { + + "karpenter.sh/discovery" = "prod-midwest-mighty-crab" + # (9 unchanged elements hidden) + } + ~ tags_all = { + + "karpenter.sh/discovery" = "prod-midwest-mighty-crab" + # (9 unchanged elements hidden) + } + # (14 unchanged attributes hidden) + } + + # module.eks_vpc.aws_subnet.private[2] will be updated in-place + ~ resource "aws_subnet" "private" { + id = "subnet-0c945c0315bb9c9ad" + ~ tags = { + + "karpenter.sh/discovery" = "prod-midwest-mighty-crab" + # (9 unchanged elements hidden) + } + ~ tags_all = { + + "karpenter.sh/discovery" = "prod-midwest-mighty-crab" + # (9 unchanged elements hidden) + } + # (14 unchanged attributes hidden) + } + + # module.external_dns_terminusplatform.aws_iam_role.external_dns[0] will be updated in-place + ~ resource "aws_iam_role" "external_dns" { + ~ assume_role_policy = jsonencode( + { + - Statement = [ + - { + - Action = "sts:AssumeRoleWithWebIdentity" + - Condition = { + - StringLike = { + - oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377:sub = "system:serviceaccount:terminus-system:*" + } + } + - Effect = "Allow" + - Principal = { + - Federated = "arn:aws:iam::***:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377" + } + - Sid = "" + }, + ] + - Version = "2012-10-17" + } + ) -> (known after apply) + id = "terminusplatform-external-dns" + name = "terminusplatform-external-dns" + tags = { + "DeploymentName" = "EKS" + "Environment" = "Production" + "ManagedBy" = "https://github.com/GetTerminus/eks-infra" + "ServiceName" = "EKS" + "Shared" = "True" + "Team" = "SRE" + } + # (9 unchanged attributes hidden) + + # (1 unchanged block hidden) + } + + # module.external_dns_terminustools.aws_iam_role.external_dns[0] will be updated in-place + ~ resource "aws_iam_role" "external_dns" { + ~ assume_role_policy = jsonencode( + { + - Statement = [ + - { + - Action = "sts:AssumeRoleWithWebIdentity" + - Condition = { + - StringLike = { + - oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377:sub = "system:serviceaccount:terminus-system:*" + } + } + - Effect = "Allow" + - Principal = { + - Federated = "arn:aws:iam::***:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/52802C254287C012F034999E4B36A377" + } + - Sid = "" + }, + ] + - Version = "2012-10-17" + } + ) -> (known after apply) + id = "terminustools-external-dns" + name = "terminustools-external-dns" + tags = { + "DeploymentName" = "EKS" + "Environment" = "Production" + "ManagedBy" = "https://github.com/GetTerminus/eks-infra" + "ServiceName" = "EKS" + "Shared" = "True" + "Team" = "SRE" + } + # (9 unchanged attributes hidden) + + # (1 unchanged block hidden) + } + +Plan: 3 to add, 14 to change, 3 to destroy. + +Changes to Outputs: + ~ eks = { + ~ config_map_aws_auth = <<-EOT + apiVersion: v1 + kind: ConfigMap + metadata: + name: aws-auth + namespace: kube-system + data: + mapRoles: | + - rolearn: arn:aws:iam::***:role/prod-midwest-mighty-crab20201014134016318400000005 + username: system:node:{{EC2PrivateDNSName}} + groups: + - system:bootstrappers + - system:nodes + + + - "groups": + - "system:masters" + "rolearn": "arn:aws:iam::***:role/admin" + "username": "admin" + - "groups": + - "system:masters" + "rolearn": "arn:aws:iam::***:role/eks-admin" + "username": "eks-admin" + - "groups": + - "system:readers" + "rolearn": "arn:aws:iam::***:role/administrator" + "username": "eks-readonly" + - "groups": + - "system:bootstrappers" + - "system:nodes" + - "system:node-proxier" + "rolearn": "arn:aws:iam::***:role/eks-fargate-pod-executor" + "username": "system:node:{{SessionName}}" + + + + mapUsers: | + - "groups": + - "system:readers" + - "team-growflare:admins" + - "team-ramble:admins" + - "team-thundercats:admins" + - "team-warriors:admins" + "userarn": "arn:aws:iam::***:user/humans/andrew.bridges" + "username": "andrew.bridges" + - "groups": + - "system:readers" + "userarn": "arn:aws:iam::***:user/humans/bill.jamison" + "username": "bill.jamison" + - "groups": + - "system:readers" + "userarn": "arn:aws:iam::***:user/humans/brendan.erwin" + "username": "brendan.erwin" + - "groups": + - "system:readers" + - "team-service-corps:admins" + - "team-service-corps:prodsupport_access" + - "team-the-a-team:admins" + - "team-thundercats:admins" + - "system:masters" + - "team-sre:admins" + "userarn": "arn:aws:iam::***:user/humans/brian.malinconico" + "username": "brian.malinconico" + - "groups": + - "system:readers" + - "team-growflare:admins" + - "team-ramble:admins" + - "team-thundercats:admins" + - "team-warriors:admins" + "userarn": "arn:aws:iam::***:user/humans/brian.weissler" + "username": "brian.weissler" + - "groups": + - "system:readers" + - "team-rolling-thunder:admins" + "userarn": "arn:aws:iam::***:user/humans/chris.vannoy" + "username": "chris.vannoy" + - "groups": + - "system:readers" + - "team-rolling-thunder:admins" + "userarn": "arn:aws:iam::***:user/humans/jason.steinhauser" + "username": "jason.steinhauser" + - "groups": + - "system:readers" + - "team-growflare:admins" + - "team-ramble:admins" + - "team-thundercats:admins" + - "team-warriors:admins" + - "team-the-a-team:admins" + "userarn": "arn:aws:iam::***:user/humans/john.barton" + "username": "john.barton" + - "groups": + - "system:readers" + - "team-rolling-thunder:admins" + "userarn": "arn:aws:iam::***:user/humans/jonathan.ascenci" + "username": "jonathan.ascenci" + - "groups": + - "system:readers" + - "team-application-backend:admins" + - "team-thundercats:admins" + - "team-service-corps:prodsupport_access" + "userarn": "arn:aws:iam::***:user/humans/matt.miller" + "username": "matt.miller" + - "groups": + - "system:readers" + - "team-rolling-thunder:admins" + "userarn": "arn:aws:iam::***:user/humans/patrick.gibbons" + "username": "patrick.gibbons" + - "groups": + - "system:readers" + - "team-rolling-thunder:admins" + "userarn": "arn:aws:iam::***:user/humans/robb.phillips" + "username": "robb.phillips" + - "groups": + - "system:readers" + - "team-emailx-contractors:admins" + "userarn": "arn:aws:iam::***:user/humans/sergey.kudryk" + "username": "sergey.kudryk" + - "groups": + - "system:readers" + - "team-growflare:admins" + - "team-ramble:admins" + - "team-thundercats:admins" + - "team-warriors:admins" + - "team-the-a-team:admins" + "userarn": "arn:aws:iam::***:user/humans/tyler.hastings" + "username": "tyler.hastings" + + + + EOT -> (known after apply) + ~ kubeconfig = <<-EOT + apiVersion: v1 + preferences: {} + kind: Config + + clusters: + - cluster: + server: https://52802C254287C012F034999E4B36A377.gr7.us-east-1.eks.amazonaws.com + certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJd01UQXhOREV6TXpjeE4xb1hEVE13TVRBeE1qRXpNemN4TjFvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTkc1CllNcmlUZzBia0g2VlZ1TU5rMmUybEI1Vm45TUtMSDJja1hMNzcvK05FZU5tejZnLzJSV2ZZZ0lucnVmY3gxVTEKZG9yQVU5QU1WT0lnLzhLc2lncmhkcHJvQzZBcmR3aElwRi8vcE5JNjRyVGNwZkFKTHBIYTdIM0lZQSthT0kwawo3RDlyaGZzU2N3cXdkRndnN3gxVS84c3lkY1c3ZmIwQzY0TXBubTQ2MnJuSWtsTk5NdnppdEZDVDNtNlNkNy91CkF2RUJJa01IQWpVanZDcE1hLzlHZlYzVmptSzRZbGtIbVZHQ1cwMThzaWNiNDQxa2s4WlZuU3YzNlVzQWQ3SEUKUm9JK0RBSXRSdjlRR0RCcUJsVFZCU2lqbXBhQjM3TktEa0NkWlNMdi96azZ6MUtpbnRaOFVHZ3Qwd3lHKzJUTQpRL3cvWVk0cU1lanBvRWhCSXZrQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFLbFZQQUYrSXcyTUJETnlRRjQ4SGpWSFlHTGEKWXM0RVZUYmRmTGNGVFB2Q0JuRnR4bFR1OVBXNjMvOVdqSnRqSlVaQ2xmT21UTGZLRFpyb1c2ZU1xTjZGVm9FUgpNSEJzbjR5RkVaLzBDNkVwbWJNRGhSenBOM25Balk1RldmN3lEdHhWS2tWU01mVm9QSWhORy9nckZqYmY5cDNXCnhyQm9kaWtzKzQ2ODNTUktManFhQkJxRVBYT3hOOGd0U3lHMzZNdVZHeVRiZVRDb1RwUDRqUGNDTXN1YU4weXUKd1pXeCtKK1lqVnBmZ2NOMkxHMDBFQTQ2SDVlK0N2NFREcWRjQnVkR0tvYnZXOTNlYW9PcXFQb3B4T3JqY0hvdwpya0ZsVk5QV2paU2Uzbmo1UGFQcFBVZ3YzL0Jnait0c1JkRTM4NkZERTE1N1ZNeUNFUldabHJYd0dJND0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= + name: eks_prod-midwest-mighty-crab + + contexts: + - context: + cluster: eks_prod-midwest-mighty-crab + user: eks_prod-midwest-mighty-crab + name: eks_prod-midwest-mighty-crab + + current-context: eks_prod-midwest-mighty-crab + + users: + - name: eks_prod-midwest-mighty-crab + user: + exec: + apiVersion: client.authentication.k8s.io/v1alpha1 + command: aws-iam-authenticator + args: + - "token" + - "-i" + - "prod-midwest-mighty-crab" + + + EOT -> (known after apply) + ~ workers_asg_arns = [ + - "arn:aws:autoscaling:us-east-1:***:autoScalingGroup:73c861f7-ac27-42f1-a435-c60a3a3217fd:autoScalingGroupName/prod-midwest-mighty-crab-apps-divine-sloth20211116020407529900000002", + + (known after apply), + ] + ~ workers_asg_names = [ + - "prod-midwest-mighty-crab-apps-divine-sloth20211116020407529900000002", + + (known after apply), + ] + ~ workers_user_data = [ + - <<-EOT + #!/bin/bash -xe + + # Allow user supplied pre userdata code + + + # Bootstrap and join the cluster + /etc/eks/bootstrap.sh --b64-cluster-ca 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJd01UQXhOREV6TXpjeE4xb1hEVE13TVRBeE1qRXpNemN4TjFvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTkc1CllNcmlUZzBia0g2VlZ1TU5rMmUybEI1Vm45TUtMSDJja1hMNzcvK05FZU5tejZnLzJSV2ZZZ0lucnVmY3gxVTEKZG9yQVU5QU1WT0lnLzhLc2lncmhkcHJvQzZBcmR3aElwRi8vcE5JNjRyVGNwZkFKTHBIYTdIM0lZQSthT0kwawo3RDlyaGZzU2N3cXdkRndnN3gxVS84c3lkY1c3ZmIwQzY0TXBubTQ2MnJuSWtsTk5NdnppdEZDVDNtNlNkNy91CkF2RUJJa01IQWpVanZDcE1hLzlHZlYzVmptSzRZbGtIbVZHQ1cwMThzaWNiNDQxa2s4WlZuU3YzNlVzQWQ3SEUKUm9JK0RBSXRSdjlRR0RCcUJsVFZCU2lqbXBhQjM3TktEa0NkWlNMdi96azZ6MUtpbnRaOFVHZ3Qwd3lHKzJUTQpRL3cvWVk0cU1lanBvRWhCSXZrQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFLbFZQQUYrSXcyTUJETnlRRjQ4SGpWSFlHTGEKWXM0RVZUYmRmTGNGVFB2Q0JuRnR4bFR1OVBXNjMvOVdqSnRqSlVaQ2xmT21UTGZLRFpyb1c2ZU1xTjZGVm9FUgpNSEJzbjR5RkVaLzBDNkVwbWJNRGhSenBOM25Balk1RldmN3lEdHhWS2tWU01mVm9QSWhORy9nckZqYmY5cDNXCnhyQm9kaWtzKzQ2ODNTUktManFhQkJxRVBYT3hOOGd0U3lHMzZNdVZHeVRiZVRDb1RwUDRqUGNDTXN1YU4weXUKd1pXeCtKK1lqVnBmZ2NOMkxHMDBFQTQ2SDVlK0N2NFREcWRjQnVkR0tvYnZXOTNlYW9PcXFQb3B4T3JqY0hvdwpya0ZsVk5QV2paU2Uzbmo1UGFQcFBVZ3YzL0Jnait0c1JkRTM4NkZERTE1N1ZNeUNFUldabHJYd0dJND0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=' --apiserver-endpoint 'https://52802C254287C012F034999E4B36A377.gr7.us-east-1.eks.amazonaws.com' --kubelet-extra-args "" 'prod-midwest-mighty-crab' + + # Allow user supplied userdata code + # Post EKS bootstrap user-data + # Increment to trigger rebuilding EKS ASGs: 1 + + # Restrict pod access to the ec2 metadata API. Pods should instead prefer to use Service Accounts annotated with AWS Roles. + # For more information, see https://docs.aws.amazon.com/en_pv/eks/latest/userguide/restrict-ec2-credential-access.html + yum install -y iptables-services + iptables --insert FORWARD 1 --in-interface eni+ --destination 169.254.169.254/32 --jump DROP + iptables-save | tee /etc/sysconfig/iptables + systemctl enable --now iptables + + # Install SSM + yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm + systemctl enable --now amazon-ssm-agent + + # Install kubectl + KUBECTL_VERSION=v1.21.2 + curl -LO https://storage.googleapis.com/kubernetes-release/release/$KUBECTL_VERSION/bin/linux/amd64/kubectl + chmod +x ./kubectl + mv ./kubectl /usr/bin/kubectl + + # Create kubectl config + aws eks --region us-east-1 update-kubeconfig --name prod-midwest-mighty-crab --kubeconfig /opt/kube/config + + # Create the drain-node script + mkdir -p /opt/scripts + cat << 'EOF' > /opt/scripts/drain-node.sh + #!/usr/bin/env bash + + trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM + + REQUESTED_INSTANCE_ID=${1:-none} + remaining_heartbeat_events=${2:-3} + + INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id) + if [[ $REQUESTED_INSTANCE_ID != $INSTANCE_ID ]]; then + echo "kubectl drain requested for $REQUESTED_INSTANCE_ID, not for $INSTANCE_ID. Exiting..." + exit 0 + fi + + set -eu + + K8S_NODE=$(curl -s http://169.254.169.254/latest/meta-data/hostname) + REGION=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed 's/[a-z]$//') + ASG_NAME=$(aws ec2 describe-tags --filters "Name=resource-id,Values=${INSTANCE_ID}" "Name=key,Values=aws:autoscaling:groupName" --region ${REGION} | jq '.Tags[0].Value' -r) + CMD_OPTS="--region ${REGION} --auto-scaling-group-name ${ASG_NAME} --lifecycle-hook-name prod-midwest-mighty-crab-worker-node-termination --instance-id ${INSTANCE_ID}" + + HEARTBEAT_TIMEOUT=$(aws autoscaling describe-lifecycle-hooks --region ${REGION} --auto-scaling-group-name ${ASG_NAME} --lifecycle-hook-names prod-midwest-mighty-crab-worker-node-termination | jq '.LifecycleHooks[0].HeartbeatTimeout') + POLL_EVENTS_UNTIL_HEARTBEAT=$(( $HEARTBEAT_TIMEOUT / 10 - 3 )) + + echo "draining node: $K8S_NODE - $INSTANCE_ID" + kubectl --kubeconfig='/opt/kube/config' drain --force --ignore-daemonsets --delete-local-data ${K8S_NODE} & + PROC_ID=$! + + remaining_poll_events=$POLL_EVENTS_UNTIL_HEARTBEAT + while kill -0 "$PROC_ID" &>/dev/null; do + ((remaining_poll_events--)) + + if (( $remaining_poll_events <= 0 )); then + if (( $remaining_heartbeat_events <= 0 )); then + aws autoscaling complete-lifecycle-action ${CMD_OPTS} --lifecycle-action-result ABORT + exit 1 + else + aws autoscaling record-lifecycle-action-heartbeat ${CMD_OPTS} + ((remaining_heartbeat_events--)) + remaining_poll_events=$POLL_EVENTS_UNTIL_HEARTBEAT + fi + fi + + sleep 10 + done + + aws autoscaling complete-lifecycle-action ${CMD_OPTS} --lifecycle-action-result CONTINUE + EOF + + chmod +x /opt/scripts/drain-node.sh + + EOT, + + (known after apply), + ] + # (20 unchanged elements hidden) + } + +------------------------------------------------------------------------ + +This plan was saved to: tfplan + +To perform exactly these actions, run the following command to apply: + terraform apply "tfplan" +EOI + +read -r -d '' TMP_INPUT <<'EOI' + ~ resource "aws_iam_role" "ingress_controller" { + ~ assume_role_policy = jsonencode( + { + - Statement = [ + - { + - Action = "sts:AssumeRoleWithWebIdentity" + - Condition = { + - StringLike = { + - oidc.eks.us-east-1.amazonaws.com/id/CF43514C002E188B59EA97EFA3E6282D:sub = "system:serviceaccount:terminus-system:*" + } + } + - Effect = "Allow" + - Principal = { + - Federated = "arn:aws:iam::***:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/CF43514C002E188B59EA97EFA3E6282D" + } + - Sid = "" + }, + ] + - Version = "2012-10-17" + } + +EOI + +read -r -d '' TMP_INPUT_2 <<'EOI' +An execution plan has been generated and is shown below. +Resource actions are indicated with the following symbols: + + create + ~ update in-place ++/- create replacement and then destroy + <= read (data resources) + +Terraform will perform the following actions: + + # aws_iam_instance_profile.karpenter[0] will be created + + resource "aws_iam_instance_profile" "karpenter" { + + arn = (known after apply) + + create_date = (known after apply) + + id = (known after apply) + + name = "KarpenterNodeInstanceProfile-ninja-relaxing-baboon" + + path = "/" + + role = "ninja-relaxing-baboon20191021193910208300000006" + + tags_all = (known after apply) + + unique_id = (known after apply) + } + + # aws_iam_role.external_dns[0] will be updated in-place + ~ resource "aws_iam_role" "external_dns" { + ~ assume_role_policy = jsonencode( + { + - Statement = [ + - { + - Action = "sts:AssumeRoleWithWebIdentity" + - Condition = { + - StringLike = { + - oidc.eks.us-east-1.amazonaws.com/id/0C0B19A5BF0FD097B5DB5796144ADC38:sub = "system:serviceaccount:terminus-system:*" + } + } + - Effect = "Allow" + - Principal = { + - Federated = "arn:aws:iam::***:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/0C0B19A5BF0FD097B5DB5796144ADC38" + } + - Sid = "" + }, + ] + - Version = "2012-10-17" + } + ) -> (known after apply) + id = "external-dns" + name = "external-dns" + tags = { + "DeploymentName" = "EKS" + "Environment" = "Development" + "ManagedBy" = "https://github.com/GetTerminus/eks-infra" + "ServiceName" = "EKS" + "Shared" = "True" + "Team" = "SRE" + } + # (9 unchanged attributes hidden) + + # (1 unchanged block hidden) + } +EOI + +TMP_INPUT_BIG=$(<~/big_plan_no_timestamp.txt) + +# sed is dumb on macos so use perl (yuck) locally +#INPUT=$(echo "$TMP_INPUT" | sed "s/\x1b\[31m-\x1b\[0m/😅/g") +#echo "$INPUT" +INPUT=$(echo "$RAW_INPUT" | perl -pe "s/(?