Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal of refactor to drift detection pipeline #115

Merged
merged 10 commits into from
Oct 2, 2024
Merged
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 87 additions & 75 deletions .github/workflows/infra_drift_detection.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ on:
required: false
default: false


env:
ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
Expand Down Expand Up @@ -47,8 +46,16 @@ jobs:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
steps:
# Exit with error if SLACK_WEBHOOK_URL is not set
- name: Check Slack Webhook
run: |
if [ -z "$SLACK_WEBHOOK_URL" ]; then
echo "SLACK_WEBHOOK_URL is not set. Please set the secret."
exit 1
fi

# Set the directory where the Terraform files are located
# The directory the value is then available in ${{ steps.directory.outputs.dir }}
# The directory value is then available in ${{ steps.directory.outputs.dir }}
- name: Set directory
id: directory
env:
Expand All @@ -61,17 +68,19 @@ jobs:
echo "Environment must be provided."
exit 1
else
# Remove trailing slash from BASE_PATH if present
BASE_PATH="${BASE_PATH%/}"
# The directory is expected to be in the format
# infra/resources/${{ inputs.environment }}
# Example: infra/resources/prod
printf "dir=%q/%q" "$BASE_PATH" "$ENVIRONMENT" >> "$GITHUB_OUTPUT"
fi

- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # pin@v4
name: Checkout

- name: Azure Login
uses: azure/login@v2 # v2.0.0
uses: azure/login@a65d910e8af852a8061c627c456678983e180302 # pin@v2
with:
client-id: ${{ env.ARM_CLIENT_ID }}
tenant-id: ${{ env.ARM_TENANT_ID }}
Expand All @@ -81,19 +90,24 @@ jobs:
id: set-terraform-version
run: |
set -eu
terraform_version=$(cat .terraform-version)
printf "terraform_version=$terraform_version" >> "$GITHUB_OUTPUT"
if [ -f .terraform-version ]; then
terraform_version=$(cat .terraform-version)
else
echo "Terraform version file not found."
exit 1
fi
echo "terraform_version=$terraform_version" >> "$GITHUB_OUTPUT"

- uses: hashicorp/setup-terraform@a1502cd9e758c50496cc9ac5308c4843bcd56d36 # v3.0.0
- uses: hashicorp/setup-terraform@a1502cd9e758c50496cc9ac5308c4843bcd56d36 # pin@v3.0.0
name: Setup Terraform
with:
terraform_version: ${{ steps.set-terraform-version.outputs.terraform_version }}

- name: Terraform Init
working-directory: ${{ steps.directory.outputs.dir }}
run: |
terraform init

# Run Terraform Plan
# The plan output is saved in a file and then processed to remove unnecessary lines
# The step never fails but the result is checked in the next step
Expand All @@ -102,25 +116,34 @@ jobs:
id: plan
working-directory: ${{ steps.directory.outputs.dir }}
run: |
set -uo pipefail
terraform plan -no-color -detailed-exitcode -out=plan.tfplan | grep -v "hidden-link:"

if [ $? -eq 1 ]; then
gunzip marked this conversation as resolved.
Show resolved Hide resolved
EXIT_CODE=${PIPESTATUS[0]}
if [ "$EXIT_CODE" -eq 1 ]; then
echo "::error::Terraform plan exited with an error"
echo "drift_found=false" >> $GITHUB_OUTPUT
exit 1
elif [ "$EXIT_CODE" -eq 2 ]; then
echo "::notice::Terraform plan detected changes"
fi

- name: Drift Detection
id: drift
working-directory: ${{ steps.directory.outputs.dir }}
run: |
set -euo pipefail

if [ ! -f plan.tfplan ]; then
echo "::error::Terraform plan file not found."
exit 1
fi

terraform show -no-color -json plan.tfplan > plan.json
NO_CHANGES=$(jq 'if .resource_changes then [.resource_changes[] | select(.change.actions | index("create") or index("update") or index("delete"))] | length else 0 end' plan.json)

if [ "$NO_CHANGES" -eq 0 ]; then
echo "No drifts in this configuration"
echo "drift_found=false" >> $GITHUB_OUTPUT
exit 0
else
echo "Drift detected:"

Expand All @@ -130,101 +153,90 @@ jobs:
TO_ADD=$(jq '[.resource_changes[] | select(.change.actions | index("create"))] | length' plan.json)
TO_CHANGE=$(jq '[.resource_changes[] | select(.change.actions | index("update"))] | length' plan.json)
TO_DESTROY=$(jq '[.resource_changes[] | select(.change.actions | index("delete"))] | length' plan.json)

echo " - Resources to add: $TO_ADD"
echo " - Resources to change: $TO_CHANGE"
echo " - Resources to destroy: $TO_DESTROY"
# Salva le variabili nell'ambiente per l'utilizzo nei passaggi successivi

# Save the variables in the environment for use in the next steps
echo "TO_ADD=$TO_ADD" >> $GITHUB_ENV
echo "TO_CHANGE=$TO_CHANGE" >> $GITHUB_ENV
echo "TO_DESTROY=$TO_DESTROY" >> $GITHUB_ENV

exit 1
fi
continue-on-error: true

- name: Get workflow data
- name: Get Workflow Data in order to send notifications
gunzip marked this conversation as resolved.
Show resolved Hide resolved
id: workflow_data
run: |
workflow=$(gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/repos/${{ github.repository }}/actions/runs/${{ github.run_id }})

workflow_url=$(echo $workflow | jq -r '.html_url')
workflow_name=$(echo $workflow | jq -r '.display_title')
repo_url=$(echo $workflow | jq -r '.repository.html_url')
repo_name=$(echo $workflow | jq -r '.repository.full_name')
commit_sha=$(echo $workflow | jq -r '.head_sha')
commit_message=$(echo $workflow | jq -r '.head_commit.message')
committer_name=$(echo $workflow | jq -r '.head_commit.committer.name')

echo "workflow_url=${workflow_url}" >> $GITHUB_OUTPUT
echo "workflow_name=${workflow_name}" >> $GITHUB_OUTPUT
echo "repo_url=${repo_url}" >> $GITHUB_OUTPUT
echo "repo_name=${repo_name}" >> $GITHUB_OUTPUT
echo "commit_sha=${commit_sha}" >> $GITHUB_OUTPUT
echo "commit_url=${repo_url}/commit/${commit_sha}" >> $GITHUB_OUTPUT
echo "commit_message=${commit_message}" >> $GITHUB_OUTPUT
echo "committer_name=${committer_name}" >> $GITHUB_OUTPUT
env:
GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }}

uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # pin@v7
with:
script: |
const run = await github.actions.getWorkflowRun({
mamu0 marked this conversation as resolved.
Show resolved Hide resolved
gunzip marked this conversation as resolved.
Show resolved Hide resolved
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.runId
});
const data = run.data;
return {
workflow_url: data.html_url,
workflow_name: data.display_title,
repo_url: data.repository.html_url,
repo_name: data.repository.full_name,
commit_sha: data.head_sha,
commit_message: data.head_commit.message,
commit_url: `${data.repository.html_url}/commit/${data.head_sha}`,
committer_name: data.head_commit.committer.name
};
result-encoding: json
gunzip marked this conversation as resolved.
Show resolved Hide resolved

# Reference: https://github.com/slackapi/slack-github-action
- name: Drift Notification
if: ${{ always() && env.SLACK_WEBHOOK_URL && steps.drift.outputs.drift_found == 'true' }}
if: ${{ always() && steps.drift.outputs.drift_found == 'true' }}
id: drift_notify
uses: slackapi/slack-github-action@70cd7be8e40a46e8b0eced40b0de447bdb42f68e #v1.26.0
uses: slackapi/slack-github-action@70cd7be8e40a46e8b0eced40b0de447bdb42f68e # pin@v1.26.0
with:
payload: |
{
"text":"${{ job.status }}",
"blocks":[
"text": "Drift Detected",
"blocks": [
{
"type":"section",
"text":{
"type":"mrkdwn",
"text":":x: Drift detected! *${{ steps.workflow_data.outputs.workflow_name }}* action is ${{ job.status }}"
}
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":x: Drift detected! *${{ steps.workflow_data.outputs.workflow_name }}* has detected drift."
gunzip marked this conversation as resolved.
Show resolved Hide resolved
}
},
{
"type":"section",
"text":{
"type":"mrkdwn",
"text":"* ${{ steps.workflow_data.outputs.workflow_name }}* results:\n:shipit: *Owner*: ${{ steps.workflow_data.outputs.committer_name }}\n:diamond_shape_with_a_dot_inside: *Commit URL*: <${{ steps.workflow_data.outputs.commit_url }}|${{ steps.workflow_data.outputs.commit_sha }}>\n:envelope: *Commit message*: ${{ steps.workflow_data.outputs.commit_message }}\n:page_with_curl: *Terraform* plan results:\n:heavy_plus_sign: Resource to add: ${{ env.TO_ADD }}\n:wavy_dash: Resource to change: ${{ env.TO_CHANGE }}\n:heavy_minus_sign: Resource to destroy: ${{ env.TO_DESTROY }}\n *Linked Repo*: <${{ steps.workflow_data.outputs.repo_url }}|${{ steps.workflow_data.outputs.repo_name }}>\n"
}
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*${{ steps.workflow_data.outputs.workflow_name }}* results:\n:shipit: *Owner*: ${{ steps.workflow_data.outputs.committer_name }}\n:diamond_shape_with_a_dot_inside: *Commit URL*: <${{ steps.workflow_data.outputs.commit_url }}|${{ steps.workflow_data.outputs.commit_sha }}>\n:envelope: *Commit message*: ${{ steps.workflow_data.outputs.commit_message }}\n:page_with_curl: *Terraform* plan results:\n:heavy_plus_sign: Resource to add: ${{ env.TO_ADD }}\n:wavy_dash: Resource to change: ${{ env.TO_CHANGE }}\n:heavy_minus_sign: Resource to destroy: ${{ env.TO_DESTROY }}\n *Linked Repo*: <${{ steps.workflow_data.outputs.repo_url }}|${{ steps.workflow_data.outputs.repo_name }}>"
}
}
]
}
env:
gunzip marked this conversation as resolved.
Show resolved Hide resolved
SLACK_WEBHOOK_URL: ${{ env.SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK_TYPE: ${{ env.SLACK_WEBHOOK_TYPE }}

- name: Failure Notification
if: ${{ failure() && env.SLACK_WEBHOOK_URL }}
if: ${{ failure() }}
id: failure_notify
uses: slackapi/slack-github-action@70cd7be8e40a46e8b0eced40b0de447bdb42f68e #v1.26.0
uses: slackapi/slack-github-action@70cd7be8e40a46e8b0eced40b0de447bdb42f68e # pin@v1.26.0
with:
payload: |
{
"text":"${{ job.status }}",
"blocks":[
"text": "Workflow Failed",
"blocks": [
{
"type":"section",
"text":{
"type":"mrkdwn",
"text":":x: Something went wrong! *${{ steps.workflow_data.outputs.workflow_name }}* action is ${{ job.status }}"
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":x: The workflow *${{ steps.workflow_data.outputs.workflow_name }}* has failed."
}
},
{
"type":"section",
"text":{
"type":"mrkdwn",
"text":"Check the Workflow:\n *URL*: ${{ steps.workflow_data.outputs.workflow_url }}\n *Linked Repo*: <${{ steps.workflow_data.outputs.repo_url }}|${{ steps.workflow_data.outputs.repo_name }}>\n"
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Check the Workflow:\n *URL*: ${{ steps.workflow_data.outputs.workflow_url }}\n *Linked Repo*: <${{ steps.workflow_data.outputs.repo_url }}|${{ steps.workflow_data.outputs.repo_name }}>\n"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ env.SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK_TYPE: ${{ env.SLACK_WEBHOOK_TYPE }}