AWS Resource Cost Estimation via Terraform with Infracost and Atlantis on Github PR
Scroll DownInfracost lets you see a cost breakdown and understand costs before making changes. On integration with Atlantis, can see cloud cost estimates for Terraform in pull requests. So teams can understand better the cost of changes before deploy.
Implementation:
- Update your setup to use the infracost-atlantis Docker image
- If you haven't done so already, download Infracost and run
infracost auth login
to get a free API key. - Retrieve your Infracost API key by running
infracost configure get api_key
. - You'll need to pass the following custom env var into the container.
INFRACOST_API_KEY=<your-infracost-api-token>
5. Add infracost yaml spec to repos.yml config file
repos:
- id: /.*/
apply_requirements: [approved, mergeable]
workflow: terragrunt
allowed_overrides: [apply_requirements, workflow]
allow_custom_workflows: true
# workflows lists server-side custom workflows
workflows:
terragrunt:
plan:
steps:
- run: terragrunt init
- run: terragrunt plan -no-color -input=false -out=$SHOWFILE
- env:
name: INFRACOST_OUTPUT
command: 'echo "/tmp/$BASE_REPO_OWNER-$BASE_REPO_NAME-$PULL_NUM-$WORKSPACE-${REPO_REL_DIR//\//-}-infracost.json"'
# Run Infracost breakdown and save to a tempfile, namespaced by this project, PR, workspace and dir
- run: |
infracost breakdown --path=$SHOWFILE \
--format=json \
--log-level=info \
--out-file=$INFRACOST_OUTPUT \
--project-name=$REPO_REL_DIR
- run: |
# Read the breakdown JSON and get costs using jq.
# Note jq comes as standard as part of infracost-atlantis Docker images. If you are using the base atlantis
# image you'll need to manually install jq. e.g:
# curl https://stedolan.github.io/jq/download/linux64/jq > /usr/local/bin/jq; chmod +x /usr/local/bin/jq
past_total_monthly_cost=$(cat $INFRACOST_OUTPUT | jq -r "(.pastTotalMonthlyCost // 0) | tonumber")
total_monthly_cost=$(cat $INFRACOST_OUTPUT | jq -r "(.totalMonthlyCost // 0) | tonumber")
diff_total_monthly_cost=$(cat $INFRACOST_OUTPUT | jq -r "(.diffTotalMonthlyCost // 0) | tonumber")
currency=$(cat $INFRACOST_OUTPUT | jq -r '.currency | select (.!=null)')
if [ "$currency" = "" ] || [ "$currency" = "USD" ]; then
currency="$"
elif [ "$currency" = "EUR" ]; then
currency="€"
elif [ "$currency" = "GBP" ]; then
currency="£"
else
currency="$currency " # Space is needed so output is "INR 123"
fi
# Run infracost output to get the diff output
diff_output=$(infracost output --no-color --format diff --show-skipped --path=$INFRACOST_OUTPUT)
change_symbol () {
local old=$1
local new=$2
local change_symbol="+"
if [ "$(echo "$new < $old" | bc -l)" = 1 ]; then
change_symbol=""
fi
printf "%s" "$change_symbol"
}
percent_display () {
local old=$1
local new=$2
local percent
local sym
percent=$(calculate_percentage "$old" "$new")
sym=$(change_symbol "$old" "$new")
local s=""
if [ -n "$percent" ]; then
s="$(printf "%.0f" "$percent")"
s=" ($sym$s%%)"
fi
printf "%s" "$s"
}
calculate_percentage () {
local old=$1
local new=$2
local percent=""
# If both old and new costs are greater than 0
if [ "$(echo "$old > 0" | bc -l)" = 1 ] && [ "$(echo "$new > 0" | bc -l)" = 1 ]; then
percent="$(echo "scale=6; $new / $old * 100 - 100" | bc)"
fi
# If both old and new costs are less than or equal to 0
if [ "$(echo "$old <= 0" | bc -l)" = 1 ] && [ "$(echo "$new <= 0" | bc -l)" = 1 ]; then
percent="0"
fi
printf "%s" "$percent"
}
format_cost () {
cost=$1
if [ -z "$cost" ] || [ "$cost" = "null" ]; then
echo "-"
elif [ "$(echo "$cost < 100" | bc -l)" = 1 ]; then
printf "$currency%0.2f" "$cost"
else
printf "$currency%0.0f" "$cost"
fi
}
percent=$(percent_display "$past_total_monthly_cost" "$total_monthly_cost" | sed "s/%/%%/g")
change_word="increase"
if [ "$(echo "$past_total_monthly_cost > $total_monthly_cost" | bc -l)" = 1 ]; then
change_word="decrease"
fi
msg="##### Infracost estimate #####"
msg="${msg}\n\n"
msg="${msg}Monthly cost will $change_word by $(format_cost $diff_total_monthly_cost)$percent\n"
msg="${msg}\n"
msg="${msg}Previous monthly cost: $(format_cost $past_total_monthly_cost)\n"
msg="${msg}New monthly cost: $(format_cost $total_monthly_cost)\n"
msg="${msg}\n"
msg="${msg}Infracost output:\n"
msg="${msg}\n"
msg="${msg}$(echo "$diff_output" | sed 's/^/ /' | sed "s/%/%%/g")\n"
printf "$msg"
apply:
steps:
- run: terragrunt apply -no-color -input=false $PLANFILE
Infracost comment on PR:
Increase the allocated_storage from 20 to 100 for one of the db. On running atlantis plan, following details will get append at the end of terraform plan
Infracost calculates the cost of infrastructure already deployed (23€) , the cost of the infrastructure with new changes (34€) and the difference between both (11€).
View Comments