feat: Added inputs for tf-init step #2
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | ||
run-name: 'Terraform workflow' | ||
on: | ||
workflow_call: | ||
inputs: | ||
working_directory: | ||
required: true | ||
type: string | ||
description: 'Root directory of the terraform where all resources exist.' | ||
provider: | ||
required: true | ||
type: string | ||
description: 'Cloud provider to run the workflow. e.g. azurerm, aws, gcp or digitalocean' | ||
aws_region: | ||
required: false | ||
type: string | ||
default: us-east-2 | ||
description: 'AWS region of terraform deployment.' | ||
gcp_region: | ||
required: false | ||
type: string | ||
description: 'GCP region of terraform deployment.' | ||
var_file: | ||
required: false | ||
type: string | ||
description: 'Terraform var file directory. e.g. vars/dev.tfvars' | ||
destroy: | ||
required: false | ||
type: boolean | ||
default: false | ||
description: 'Set true to to destroy terraform infrastructure.' | ||
approvers: | ||
required: false | ||
type: string | ||
description: 'Approvals list to approve apply or destroy' | ||
terraform_version: | ||
type: string | ||
default: 1.3.6 | ||
description: 'Required erraform version ' | ||
timeout: | ||
required: false | ||
type: number | ||
default: 10 | ||
description: 'Timeout for approval step' | ||
minimum-approvals: | ||
required: false | ||
type: string | ||
default: 1 | ||
description: 'Minimum approvals required to accept the plan' | ||
token_format: | ||
required: false | ||
type: string | ||
default: access_token | ||
description: 'Output format for the generated authentication token. For OAuth 2.0 access tokens, specify "access_token". For OIDC tokens, specify "id_token". To skip token generation, leave this value empty' | ||
access_token_lifetime: | ||
required: false | ||
type: string | ||
default: 300s | ||
description: 'Desired lifetime duration of the access token, in seconds' | ||
project_id: | ||
required: false | ||
type: string | ||
description: 'ID of the default project to use for future API calls and invocations.' | ||
create_credentials_file: | ||
required: false | ||
type: string | ||
default: true | ||
description: 'If true, the action will securely generate a credentials file which can be used for authentication via gcloud and Google Cloud SDKs.' | ||
backend_bucket_name: | ||
required: false | ||
type: string | ||
errored_tfstate_path: | ||
required: false | ||
type: string | ||
secrets: | ||
AZURE_CREDENTIALS: | ||
required: false | ||
description: 'Azure Credentials to install Azure in github runner.' | ||
AWS_ACCESS_KEY_ID: | ||
required: false | ||
description: 'AWS Access Key ID to install AWS CLI.' | ||
BUILD_ROLE: | ||
required: false | ||
description: 'AWS OIDC role for aws authentication.' | ||
AWS_SECRET_ACCESS_KEY: | ||
required: false | ||
description: 'AWS Secret access key to install AWS CLI' | ||
AWS_SESSION_TOKEN: | ||
required: false | ||
description: 'AWS Session Token to install AWS CLI' | ||
GCP_CREDENTIALS: | ||
required: false | ||
description: 'The Google Cloud JSON service account key to use for authentication' | ||
DIGITALOCEAN_ACCESS_TOKEN: | ||
required: false | ||
description: 'The DigitalOcean Personal Access Token for Application & API' | ||
env-vars: | ||
required: false | ||
description: 'Pass required environment variables' | ||
WORKLOAD_IDENTITY_PROVIDER: | ||
required: false | ||
description: 'The full identifier of the Workload Identity Provider' | ||
SERVICE_ACCOUNT: | ||
required: false | ||
description: 'The service account to be used' | ||
jobs: | ||
terraform-workflow: | ||
runs-on: ubuntu-latest | ||
outputs: | ||
tfplanExitCode: ${{ steps.tf-plan.outputs.exitcode }} | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
- name: Set environment variables | ||
run: | | ||
( | ||
cat <<'_EOT' | ||
${{ secrets.env-vars }} | ||
_EOT | ||
) >> "$GITHUB_ENV" | ||
- name: Install AWS CLI | ||
if: ${{ inputs.provider == 'aws' }} | ||
uses: aws-actions/configure-aws-credentials@v4 | ||
with: | ||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} | ||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | ||
aws-session-token: ${{ secrets.AWS_SESSION_TOKEN }} | ||
role-to-assume: ${{ secrets.BUILD_ROLE }} | ||
aws-region: ${{ inputs.aws_region }} | ||
role-duration-seconds: 900 | ||
role-skip-session-tagging: true | ||
- name: Install Azure CLI | ||
if: ${{ inputs.provider == 'azurerm' }} | ||
uses: azure/login@v2 | ||
with: | ||
creds: ${{ secrets.AZURE_CREDENTIALS }} | ||
- name: 'Authenticate to Google Cloud' | ||
if: ${{ inputs.provider == 'gcp' }} | ||
uses: 'google-github-actions/auth@v2' | ||
with: | ||
credentials_json: '${{ secrets.GCP_CREDENTIALS }}' | ||
create_credentials_file: ${{ inputs.create_credentials_file }} | ||
token_format: ${{ inputs.token_format }} | ||
workload_identity_provider: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER }} | ||
service_account: ${{ secrets.SERVICE_ACCOUNT }} | ||
access_token_lifetime: ${{ inputs.access_token_lifetime }} | ||
project_id: ${{ inputs.project_id }} | ||
- name: Install doctl | ||
if: ${{ inputs.provider == 'digitalocean' }} | ||
uses: digitalocean/action-doctl@v2 | ||
with: | ||
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} | ||
- name: Set up Terraform | ||
uses: hashicorp/setup-terraform@v3 | ||
with: | ||
terraform_version: ${{ inputs.terraform_version }} | ||
- name: 'Terraform Format' | ||
if: ${{ inputs.destroy != true }} | ||
id: fmt | ||
uses: 'dflook/terraform-fmt-check@v1' | ||
with: | ||
actions_subcommand: 'fmt' | ||
path: ${{ inputs.working_directory }} | ||
- name: terraform init | ||
run: | | ||
cd ${{ inputs.working_directory }} | ||
terraform init | ||
- name: 'Terraform validate' | ||
if: ${{ inputs.destroy != true }} | ||
id: validate | ||
uses: dflook/terraform-validate@v1 | ||
with: | ||
path: ${{ inputs.working_directory }} | ||
- name: Terraform Plan | ||
id: tf-plan | ||
run: | | ||
export exitcode=0 | ||
cd ${{ inputs.working_directory }} | ||
if [ "${{ inputs.destroy }}" = true ]; then | ||
if [ -n "${{ inputs.var_file }}" ]; then | ||
terraform plan -destroy -out tfplan --var-file=${{ inputs.var_file }} | ||
else | ||
terraform plan -destroy -out tfplan | ||
fi | ||
else | ||
if [ -n "${{ inputs.var_file }}" ]; then | ||
terraform plan -out tfplan --var-file=${{ inputs.var_file }} | ||
else | ||
terraform plan -out tfplan | ||
fi | ||
fi | ||
- name: Publish Terraform Plan | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: tfplan | ||
path: ${{ inputs.working_directory }}/tfplan | ||
- name: Create String Output | ||
id: tf-plan-string | ||
run: | | ||
cd ${{ inputs.working_directory }} | ||
TERRAFORM_PLAN=$(terraform show -no-color tfplan) | ||
delimiter="$(openssl rand -hex 8)" | ||
echo "summary<<${delimiter}" >> $GITHUB_OUTPUT | ||
echo "## Terraform Plan Output" >> $GITHUB_OUTPUT | ||
echo "<details><summary>Click to expand</summary>" >> $GITHUB_OUTPUT | ||
echo "" >> $GITHUB_OUTPUT | ||
echo '```terraform' >> $GITHUB_OUTPUT | ||
echo "$TERRAFORM_PLAN" >> $GITHUB_OUTPUT | ||
echo '```' >> $GITHUB_OUTPUT | ||
echo "</details>" >> $GITHUB_OUTPUT | ||
echo "${delimiter}" >> $GITHUB_OUTPUT | ||
- name: "Accept plan or deny" | ||
uses: trstringer/manual-approval@v1 | ||
timeout-minutes: ${{ inputs.timeout }} | ||
with: | ||
secret: ${{ github.TOKEN }} | ||
approvers: ${{ inputs.approvers }} | ||
minimum-approvals: ${{ inputs.minimum-approvals }} | ||
issue-title: "Terraform Plan for Infrastructure Update" | ||
# - name: terraform apply | ||
# if: ${{ inputs.destroy != true }} | ||
# run: | | ||
# if [ -n "${{ inputs.var_file }}" ]; then | ||
# cd ${{ inputs.working_directory }} | ||
# terraform apply -var-file="${{ inputs.var_file }}" -auto-approve | ||
# else | ||
# cd ${{ inputs.working_directory }} | ||
# terraform apply -auto-approve | ||
# fi | ||
- name: terraform apply | ||
if: ${{ inputs.destroy != true }} | ||
run: | | ||
cd ${{ inputs.working_directory }} | ||
if [ -f "errored.tfstate" ]; then | ||
echo "Found errored.tfstate, attempting state recovery..." | ||
terraform state push errored.tfstate | ||
# Optionally move or manage the errored.tfstate file | ||
mv errored.tfstate /path/to/backup/location | ||
fi | ||
if [ -n "${{ inputs.var_file }}" ]; then | ||
terraform apply -var-file="${{ inputs.var_file }}" -auto-approve || { | ||
if [ -f "errored.tfstate" ]; then | ||
echo "Copying errored.tfstate to S3..." | ||
aws s3 cp errored.tfstate s3://${{ inputs.backend_s3_bucket }}/${{ inputs.backend_s3_key }}/errored.tfstate | ||
fi | ||
exit 1 | ||
} | ||
else | ||
terraform apply -auto-approve || { | ||
if [ -f "errored.tfstate" ]; then | ||
echo "Copying errored.tfstate to S3..." | ||
aws s3 cp errored.tfstate s3://${{ inputs.backend_s3_bucket }}/${{ inputs.backend_s3_key }}/errored.tfstate | ||
fi | ||
exit 1 | ||
} | ||
} | ||
- name: Terraform destroy | ||
if: ${{ inputs.destroy == true }} | ||
id: destroy | ||
run: | | ||
if [ -n "${{ inputs.var_file }}" ]; then | ||
cd ${{ inputs.working_directory }} | ||
terraform destroy -var-file="${{ inputs.var_file }}" -auto-approve | ||
else | ||
cd ${{ inputs.working_directory }} | ||
terraform destroy -auto-approve | ||
fi | ||
... |