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

Terraform + Ansible Github Actions #1

Merged
merged 63 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
be566f1
Run terraform fmt
hellais Feb 2, 2024
72a8510
Remove one level of nesting
hellais Feb 2, 2024
676bac7
Add production deploy github action
hellais Feb 2, 2024
4718462
Add terraform cloud provider
hellais Feb 2, 2024
745ab37
Migrate state from cloud over to s3
hellais Feb 2, 2024
9162cd0
Workaround bug https://github.com/hashicorp/setup-terraform/issues/150
hellais Feb 2, 2024
8b50ece
Fix missing variable
hellais Feb 2, 2024
05637d0
Also run apply as part of action
hellais Feb 2, 2024
c9835f4
Start fleshing out ansible integration
hellais Feb 2, 2024
9e1c62a
Add support for commiting terraform outputs and skipping terraform
hellais Feb 2, 2024
0340464
Add job that runs ansible automatically
hellais Feb 2, 2024
d4e9804
Comment out broken ansible run stage
hellais Feb 2, 2024
b3f18b7
Terraform apply needs to be run with auto approve
hellais Feb 2, 2024
14f7d7b
Improve log output
hellais Feb 2, 2024
eacfbc8
Add write permission to repo
hellais Feb 2, 2024
9ad8b55
Change key to deploy key stored in github actions env vars
hellais Feb 4, 2024
399ef11
skip-terraform: autoupdate terraform outputs
Feb 2, 2024
b26af8b
Better pattern for writing to github output
hellais Feb 4, 2024
c46439f
Add pull-request write permission to ansible job
hellais Feb 4, 2024
c48b86a
Move the setup of clickhouse into ansible
hellais Feb 4, 2024
800a782
Add script for dumping and restoring table
hellais Feb 4, 2024
6d5c138
Add support for generating known_hosts
hellais Feb 5, 2024
1c6b839
Bump terraform lock file
hellais Feb 5, 2024
b410861
Make ansible task idempotent
hellais Feb 5, 2024
7851664
Improve the comment outputs
hellais Feb 5, 2024
fcb0e8c
Small cosmetic improvements
hellais Feb 5, 2024
74387c9
Run terraform fmt
hellais Feb 5, 2024
5bf121e
Fix typo in function
hellais Feb 5, 2024
78c78c8
Tidy up of script calling
hellais Feb 5, 2024
2dda818
Refactoring of ansible roles into separate roles
hellais Feb 5, 2024
831a873
Terraform fmt
hellais Feb 5, 2024
014fc03
move cache update into install package operation
hellais Feb 5, 2024
9ad2d24
Fix parsing of play recap
hellais Feb 5, 2024
7850614
Add support for TLS cert validation
hellais Feb 5, 2024
523139e
Public-ish records should not contain tier1 in them
hellais Feb 5, 2024
a6d2880
Allow 443 traffic on load balancer
hellais Feb 5, 2024
40b4b08
Use terraform vars to bump versions of software
hellais Feb 5, 2024
1843195
Set specific version
hellais Feb 5, 2024
0867020
Bump dev tag
hellais Feb 5, 2024
1e8738c
Update branch names, zap reverse-proxy code
hellais Feb 6, 2024
834e088
Remove unused commented code and commment commented code that should …
hellais Feb 6, 2024
82a5b13
auto: update oonidataapi package version to v24.2.0-dev.2
Feb 5, 2024
f13aeb3
auto: update oonidataapi package version to v24.2.0-dev.3
Feb 6, 2024
140bcef
skip-terraform: Fix ansible recap regexp
hellais Feb 6, 2024
79c02de
auto: update oonidataapi package version to v24.2.0.dev3
Feb 6, 2024
b05181a
auto: update oonidataapi package version to v24.2.0.dev4
Feb 6, 2024
dfb3267
Install ansible and terraform from deb repo
hellais Feb 6, 2024
f7d3205
WIP code to implement update-deploy-status on PR
hellais Feb 6, 2024
d8d2268
Fix version pinning of ansible
hellais Feb 7, 2024
50b6510
auto: update oonidataapi package version to v0.2.0.dev1
Feb 7, 2024
a622d72
The version pinning happens at the ppa layer
hellais Feb 7, 2024
4a18d0c
Merge branch 'tf-actions' of github.com:ooni/devops into tf-actions
hellais Feb 7, 2024
7217c49
Convert the deploy action into a check action, which just perform a d…
hellais Feb 7, 2024
a2f43e3
Push on all is redundant when the pull_request filter is setup
hellais Feb 7, 2024
12741f0
Update .github/workflows/check_deploy.yml
hellais Feb 13, 2024
c60bac7
Update .github/workflows/check_deploy.yml
hellais Feb 13, 2024
462857d
Update scripts/dump-tables-ch.sh
hellais Feb 13, 2024
3ea0f79
Update tf/environments/production/scripts/update_known_hosts.sh
hellais Feb 13, 2024
ca6ec3e
Add editorconfig
hellais Feb 13, 2024
e97ca90
Add newlines at end of file
hellais Feb 13, 2024
0cbaff1
Update scripts/restore-dumps.sh
hellais Feb 13, 2024
6ae5801
Drop fetch depth 2
hellais Feb 13, 2024
bdbacbc
Merge branch 'tf-actions' of github.com:ooni/devops into tf-actions
hellais Feb 13, 2024
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
13 changes: 13 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
root = true

[*]
end_of_line = lf
charset = utf-8
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true

[*.{yml,yaml}]
indent_style = space
indent_size = 2
219 changes: 219 additions & 0 deletions .github/workflows/check_deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
# For docs on this see:
# * https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions
# * https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request
# * https://docs.github.com/en/webhooks/webhook-events-and-payloads?actionType=synchronize#pull_request
on:
push:
branches:
- main
pull_request:
types:
- opened
- synchronize # when commits are pushed to the PR
- reopened
- edited # title or body of a pull request was edited, or the base branch of a pull request was changed

env:
tf_actions_working_dir: "./tf/environments/production"
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

jobs:
ansible:
needs: terraform
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ env.tf_actions_working_dir }}/ansible
permissions:
pull-requests: write
steps:
- uses: actions/checkout@v4

- name: Install Ansible
run: |
sudo apt update
sudo apt install software-properties-common
sudo add-apt-repository --yes --update ppa:ansible/ansible-9
sudo apt install -y ansible

- name: Write devops ssh key to .ssh
run: |
mkdir -p ~/.ssh/
chmod 700 ~/.ssh/
echo "${{ secrets.AWS_SSH_KEY }}" > ~/.ssh/ooni-devops-prod.pem
chmod 600 ~/.ssh/ooni-devops-prod.pem

- name: Run Ansible Playbook
id: playbook
env:
ANSIBLE_SSH_ARGS: "-o UserKnownHostsFile=known_hosts"
run: |
echo "ansible_playbook<<EOF" >> "$GITHUB_OUTPUT"
echo "\$ ansible-playbook playbook.yml --check --diff -i inventory.ini" >> "$GITHUB_OUTPUT"
ansible-playbook playbook.yml --check --diff -i inventory.ini --key-file ~/.ssh/ooni-devops-prod.pem 2>&1 | tee -a "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
continue-on-error: true
hellais marked this conversation as resolved.
Show resolved Hide resolved

# This can be uncommmented to make it possible to ssh into the container to debug the run
#- name: Setup tmate session
# uses: mxschmitt/action-tmate@v3

- uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const commentTitle = "Ansible Run Output";
const ansiblePlaybookOutput = `${{ steps.playbook.outputs.ansible_playbook}}`;
const parts = ansiblePlaybookOutput.split(/PLAY RECAP \*+/);
const ansiblePlaybookRecap = parts.length > 1 ? parts[1].trim() : '';

const commentBody = `
#### Ansible Playbook Recap 🔍

\`\`\`\n
${ansiblePlaybookRecap}
\`\`\`

#### Ansible playbook output 📖\`${{ steps.playbook.outcome }}\`

<details><summary>Show Execution</summary>

\`\`\`\n
${ansiblePlaybookOutput}
\`\`\`

</details>

| | |
|-------------------|------------------------------------|
| Pusher | @${{ github.actor }} |
| Action | ${{ github.event_name }} |
| Working Directory | ${{ env.tf_actions_working_dir }} |
| Workflow | ${{ github.workflow }} |
| Last updated | ${(new Date()).toUTCString()} |
`;

// Call the script to write the comment
const script = require('./scripts/ghactions/comment-on-pr.js');
await script({github, context, core, commentTitle, commentBody});

terraform:
runs-on: ubuntu-latest
if: ${{ !startsWith(github.event.head_commit.message, 'skip-terraform:') }}
defaults:
run:
working-directory: ${{ env.tf_actions_working_dir }}
permissions:
contents: write
pull-requests: write
env:
TF_VAR_aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
TF_VAR_aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
TF_VAR_datadog_api_key: ${{ secrets.DATADOG_API_KEY }}

steps:
- uses: actions/checkout@v4

- name: Install Terraform
run: |
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" \
| sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform

- name: Terraform fmt
id: fmt
run: terraform fmt -check
continue-on-error: true

- name: Terraform Init
id: init
run: terraform init

- name: Terraform Validate
id: validate
run: |
echo "terraform_validate<<EOF" >> "$GITHUB_OUTPUT"
echo "\$ terraform validate" >> "$GITHUB_OUTPUT"
terraform validate -no-color | tee -a "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"

- name: Terraform Plan
id: plan
run: |
echo "terraform_plan<<EOF" >> "$GITHUB_OUTPUT"
echo "\$ terraform plan" >> "$GITHUB_OUTPUT"
terraform plan -no-color | tee -a "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
continue-on-error: true

# Temporarily disabled, probably should be moved to a deploy action with stricter checks
#- name: Terraform Apply
# id: apply
# run: |
# echo "terraform_apply<<EOF" >> "$GITHUB_OUTPUT"
# echo "\$ terraform apply -auto-approve" >> "$GITHUB_OUTPUT"
# terraform apply -auto-approve -no-color | tee -a "$GITHUB_OUTPUT"
# echo "EOF" >> "$GITHUB_OUTPUT"
# continue-on-error: true

- uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const terraformPlanOutput = `${{ steps.plan.outputs.terraform_plan }}`;
const terraformApplyOutput = `${{ steps.apply.outputs.terraform_apply }}`;

const terraformPlanPlanLine = terraformPlanOutput.split('\n').find(line => line.startsWith('Plan:'));
const terraformApplyPlanLine = terraformApplyOutput.split('\n').find(line => line.startsWith('Plan:'));
const terraformApplyApplyLine = terraformApplyOutput.split('\n').find(line => line.startsWith('Apply complete!'));

const commentTitle = "Terraform Run Output";
const commentBody = `
#### Format and Style 🖌\`${{ steps.fmt.outcome }}\`
#### Initialization ⚙️\`${{ steps.init.outcome }}\`
#### Validation 🤖\`${{ steps.validate.outcome }}\`
<details><summary>Validation Output</summary>

\`\`\`\n
${{ steps.validate.outputs.terraform_validate }}
\`\`\`

</details>

#### Plan 📖\`${{ steps.plan.outcome }}\`
* **${terraformPlanPlanLine}**

<details><summary>Show Plan</summary>

\`\`\`\n
${terraformPlanOutput}
\`\`\`

</details>

#### Apply 📖\`${{ steps.apply.outcome }}\`
* **${terraformApplyPlanLine}**
* **${terraformApplyApplyLine}**

<details><summary>Show Apply</summary>

\`\`\`\n
${terraformApplyOutput}
\`\`\`

</details>

| | |
|-------------------|------------------------------------|
| Pusher | @${{ github.actor }} |
| Action | ${{ github.event_name }} |
| Working Directory | ${{ env.tf_actions_working_dir }} |
| Workflow | ${{ github.workflow }} |
| Last updated | ${ (new Date()).toUTCString() } |
`;

// Call the script to write the comment
const script = require('./scripts/ghactions/comment-on-pr.js');
await script({github, context, core, commentTitle, commentBody});
17 changes: 16 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,16 @@
.terraform
# Local .terraform directories
**/.terraform/*

# .tfstate files
*.tfstate
*.tfstate.*

# Crash log files
crash.log
crash.*.log

# Ignore override files as they are usually used to override resources locally
override.tf
override.tf.json
*_override.tf
*_override.tf.json
2 changes: 0 additions & 2 deletions reverse-proxy/Dockerfile

This file was deleted.

16 changes: 0 additions & 16 deletions reverse-proxy/haproxy.cfg

This file was deleted.

46 changes: 46 additions & 0 deletions scripts/dump-tables-ch.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/bin/bash
hellais marked this conversation as resolved.
Show resolved Hide resolved
set -euxo pipefail
# This is to be run manually on the clickhouse host to dump schemas and table dumps
# You may want to make some tweaks to the dumping rules in order avoid dumping
# too much data (eg. fastpath)
# You should then scp the data over to the target host manually, by running:
# $ scp * clickhouse-instance2:/var/lib/clickhouse/ooni-dumps/
TABLES=(
"fastpath"
"jsonl"
"url_priorities"
"citizenlab"
"citizenlab_flip"
"test_groups"
"accounts"
"session_expunge"
"msmt_feedback"
"fingerprints_dns"
"fingerprints_http"
"asnmeta"
"counters_test_list"
"counters_asn_test_list"
"incidents"
"oonirun"
)

dump_dir="./dumps"
current_date=$(date +%Y%m%d)

# Directory to store the dumps
mkdir -p "$dump_dir"

# Iterate over each table
for table in "${TABLES[@]}"; do
# Define file names for schema and data dump
schema_file="${dump_dir}/${current_date}-${table}_schema.sql"
data_file="${dump_dir}/${current_date}-${table}_dump.clickhouse"

# Dump the table schema
echo "[+] dumping schema $schema_file"
clickhouse-client --query="SHOW CREATE TABLE ${table} FORMAT TabSeparatedRaw" > "$schema_file"

# Dump the table data in ClickHouse native format
echo "[+] dumping table data $data_file"
clickhouse-client --query="SELECT * FROM ${table} INTO OUTFILE '${data_file}' FORMAT Native"
done
44 changes: 44 additions & 0 deletions scripts/ghactions/comment-on-pr.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module.exports = async ({
github,
context,
core,
commentTitle,
commentBody,
}) => {
const body = `## ${commentTitle} 🤖
${commentBody}
`;

const prNumber = context.payload.pull_request.number;

if (prNumber) {
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
});
const existingBotComment = comments.find((comment) => {
return (
comment.user.type === "Bot" &&
comment.body.includes(`## ${commentTitle}`)
);
});

if (existingBotComment) {
await github.rest.issues.updateComment({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existingBotComment.id,
body,
});
} else {
await github.rest.issues.createComment({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body,
});
}
}
};
Loading
Loading