Skip to content

Commit

Permalink
feat: pr-lock action (#14)
Browse files Browse the repository at this point in the history
* feat: pr-lock action

* chore: make some change to trigger workflow

* chore: tidy up the repo

* chore(ansible-lint): change the action i used to the maintained one

* fix: linting

* test: upgrade ansible

* fix: use ansible requirements file

* fix: order issue with the action

* fix: local action path

* fix: create branch id doesn't exist

* test: create orphan branch

* fix: orpahn branch creation

* chore: refact the lock mechanism

* fix: do not push the lock right away

* fix: configure commit author

* chore: move the lock out of the  run-playbook

* fis: properly handle case where lock already exist

* fix: ansible must install modules

* fix: missing then in workflow script
  • Loading branch information
xNok authored Aug 3, 2024
1 parent d6f2f0e commit 9fd35bf
Show file tree
Hide file tree
Showing 19 changed files with 167 additions and 42 deletions.
1 change: 1 addition & 0 deletions .ansible-lint
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ exclude_paths:
# This makes linter to fully ignore rules/tags listed below
skip_list:
- 'fqcn-builtins'
- 'fqcn'
- 'role-name'

# List of additional kind:pattern to be added at the top of the default
Expand Down
44 changes: 44 additions & 0 deletions .github/actions/pr-lock/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: 'PR Lock'
description: 'Ensure that only one PR can deploy at a time using a lock file mechanism.'
runs:
using: 'composite'
steps:
- name: Create or checkout lock branch
shell: bash
run: |
git config user.name github-actions
git config user.email [email protected]
# Fetch the lock-branch if it exists, otherwise handle the failure
if git fetch origin lock-branch; then
echo "Lock branch exists. Checking out."
git checkout lock-branch
else
echo "Lock branch does not exist. Creating a new one."
git checkout --orphan lock-branch
git rm -rf .
git clean -fdx
git commit --allow-empty -m "Initialize lock branch"
fi
- name: Check for lock file
id: check-lock
shell: bash
run: |
if [ -f ".deploy-lock" ]; then
# Read the PR number from the lock file
LOCKED_PR=$(cat .deploy-lock)
# Compare it with the current PR number
if [ "$LOCKED_PR" != "${{ github.event.pull_request.number }}" ]; then
echo "Another deployment is in progress by PR #$LOCKED_PR. Exiting..."
exit 1
else
echo "Current PR #${{ github.event.pull_request.number }} already holds the lock. Proceeding with deployment."
fi
else
echo "No lock file found. Creating lock file.."
echo "${{ github.event.pull_request.number }}" > .deploy-lock
git add .deploy-lock
git commit -m "Lock deployment for PR #${{ github.event.pull_request.number }}"
git push origin lock-branch
fi
24 changes: 24 additions & 0 deletions .github/actions/pr-unlock/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: 'PR Lock Remove'
description: 'Remove the deployment lock file after deployment on the main branch.'
runs:
using: 'composite'
steps:
- name: Checkout lock branch
shell: bash
run: |
git fetch origin lock-branch
git checkout lock-branch || git checkout --orphan lock-branch
- name: Remove lock file
id: remove-lock
shell: bash
run: |
if [ -f ".deploy-lock" ]; then
echo "Removing lock file..."
git rm .deploy-lock
git config user.name "github-actions"
git config user.email "[email protected]"
git commit -m "Unlock deployment"
git push origin lock-branch
else
echo "No lock file found."
6 changes: 5 additions & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
version: 2
updates:
- package-ecosystem: "terraform"
directory: "/erraform" # Location of package manifests
directory: "/terraform"
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
31 changes: 24 additions & 7 deletions .github/workflows/ansible.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ on:
- synchronize
paths:
- 'ansible/**'
- requirements.txt

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
Expand All @@ -29,37 +30,53 @@ jobs:
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Run ansible-lint
# replace `main` with any valid ref, or tags like `v6`
uses: ansible-community/[email protected]
uses: ansible/[email protected] # or version tag instead of 'main'
with:
args: "ansible"

lock:
# The type of runner that the job will run on
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
# Lock if this is a PR so two PR cannot deploy at the same time
- name: PR Lock
if: github.event_name == 'pull_request'
uses: ./.github/actions/pr-lock

- name: Clear PR Lock
if: github.ref == 'refs/heads/main'
uses: ./.github/actions/pr-unlock

run-playbook:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# The validate Job need to be sucessfull
needs: [ validate ]
needs: [ validate, lock ]
# The deployement environnement thus provides the secrets for that env
environment: digitalocean

steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Set up Python 3.9
# Setup the environment
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: 3.9
python-version: "3.12"
cache: 'pip' # caching pip dependencies

- name: Install dependencies Including Ansible
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
if [ -f test-requirements.txt ]; then pip install -r test-requirements.txt; fi
if [ -f requirements.yml ]; then ansible-galaxy install -r requirements.yml; fi
- name: write inventory to file
env:
Expand Down
10 changes: 9 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,12 @@ repos:
- repo: https://github.com/adrienverge/yamllint.git
rev: v1.29.0
hooks:
- id: yamllint
- id: yamllint
- repo: https://github.com/ansible/ansible-lint
rev: v24.7.0
hooks:
- id: ansible-lint
args:
- "ansible"
additional_dependencies:
- ansible
File renamed without changes.
16 changes: 10 additions & 6 deletions ansible/docker-swarm-portainer-caddy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
roles:
- utils-affected-roles

# BASE
- name: This is the base requirement for all nodes
hosts: all
become: true

roles:
- name: docker
- role: docker
when: "'docker' in hostvars['localhost']['roles_with_changes']"

# SWARM
- name: This setup the Docker Swarm Manager
hosts: managers
gather_facts: true
Expand All @@ -21,26 +24,27 @@
# NOTE: One node requires python and extra tools to setup the swarm, I call it the controller.
# I case we have an issue all master are setup as potential controller
# this role is for the host running ansible to manage the swarm
- name: docker-swarm-controller
- role: docker-swarm-controller
when: "'docker-swarm-controller' in hostvars['localhost']['roles_with_changes']"
# this role is for creating the swarm and adding host as manager
- name: docker-swarm-manager
- role: docker-swarm-manager
when: "'docker-swarm-manager' in hostvars['localhost']['roles_with_changes']"

- name: This setup nodes to join the Swarm
hosts: nodes

roles:
- name: docker-swarm-node # this role is for host to join the swarm
- role: docker-swarm-node # this role is for host to join the swarm
when: "'docker-swarm-node' in hostvars['localhost']['roles_with_changes']"

# APPS
- name: This install Caddy and Portainer in the Swarm
hosts: managers[0] # Only one manager need to be hit
become: true

roles:
- name: docker-swarm-app-caddy
- role: docker-swarm-app-caddy
when: "'docker-swarm-app-caddy' in hostvars['localhost']['roles_with_changes']"
- name: docker-swarm-app-portainer
- role: docker-swarm-app-portainer
caddy: true
when: "'docker-swarm-app-portainer' in hostvars['localhost']['roles_with_changes']"
11 changes: 7 additions & 4 deletions ansible/docker-swarm-portainer.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
- name: This is the base requirement for all nodes
hosts: all
become: true

roles:
- {name: docker, become: true}
- docker

- name: This setup the Docker Swarm Manager
hosts: managers
become: true

roles:
# NOTE: One node requires python and extra tools to setup the swarm, I call it the controller.
# I case we have an issue all master are setup as potential controller
- {name: docker-swarm-controller, become: true} # this role is for the host running ansible to manage the swarm
- {name: docker-swarm-manager, become: true} # this role is for creating the swarm and adding host as manager
- docker-swarm-controller # this role is for the host running ansible to manage the swarm
- docker-swarm-manager # this role is for creating the swarm and adding host as manager

- name: This setup nodes to join the Swarm
hosts: nodes
Expand All @@ -21,6 +23,7 @@

- name: This install Portainer in the Swarm
hosts: managers[0] # Only one manager need to be hit
become: true

roles:
- {name: docker-swarm-app-portainer, become: true}
- docker-swarm-app-portainer
6 changes: 4 additions & 2 deletions ansible/docker-swarm.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
- name: This is the base requirement for all nodes
hosts: all
become: true

roles:
- {name: docker, become: true}
- docker

- name: This setup the Docker Swarm Manager
hosts: managers
become: true

roles:
- {name: docker-swarm-manager, become: true} # this role is for creating the swarm and adding host as manager
- docker-swarm-manager # this role is for creating the swarm and adding host as manager

- name: This setup nodes to join the Swarm
hosts: nodes
Expand Down
2 changes: 1 addition & 1 deletion ansible/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@
copy:
content: hello-world
dest: /tmp/testfile.txt
mode: 0644
mode: "0644"
2 changes: 1 addition & 1 deletion ansible/hello-world.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
copy:
content: hello-world
dest: /tmp/testfile.txt
mode: 0644
mode: "0644"
9 changes: 6 additions & 3 deletions ansible/roles/docker-swarm-controller/tasks/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@
# GENERAL Setup
###
- name: Install required system packages
apt: name={{ item }} state=present update_cache=yes
apt:
name: "{{ item }}"
state: present
update_cache: true
loop: ['python3-pip', 'virtualenv', 'python3-setuptools']

- name: Install python stuff required
pip:
executable: pip3
name: [jsondiff, passlib, docker]
executable: pip3
name: [jsondiff, passlib, docker]
17 changes: 11 additions & 6 deletions ansible/roles/docker/tasks/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
# GENERAL Setup
###
- name: Install required system packages
become_user: root
apt: name={{ item }} state=present update_cache=yes
apt:
name: "{{ item }}"
state: present
update_cache: true
loop: ['apt-transport-https', 'ca-certificates', 'software-properties-common']

- name: Add Docker GPG apt Key
Expand All @@ -22,7 +24,10 @@
state: present

- name: Update apt and install docker-ce
apt: name={{ item }} state=present update_cache=yes
apt:
name: "{{ item }}"
state: present
update_cache: true
loop: ['docker-ce', 'docker-ce-cli', 'docker-compose', 'containerd.io']

- name: Ensure docker users are added to the docker group.
Expand All @@ -43,17 +48,17 @@
# Pull, start, stop a hello-world container
########
- name: Pull default Docker image for testing
docker_image:
community.docker.docker_image:
name: "hello-world"
source: pull

- name: Create default containers
docker_container:
community.docker.docker_container:
name: "hello-world"
image: "hello-world"
state: present

- name: Stop a container
docker_container:
community.docker.docker_container:
name: "hello-world"
state: stopped
6 changes: 4 additions & 2 deletions ansible/roles/utils-affected-roles/tasks/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@

- name: Extract folders from the diff
set_fact:
changed_folders: "{{ diff.stdout_lines
changed_folders: "{{

Check warning on line 26 in ansible/roles/utils-affected-roles/tasks/main.yaml

View workflow job for this annotation

GitHub Actions / validate

jinja[spacing]

Jinja2 spacing could be improved: {{ diff.stdout_lines | map('regex_replace', '^(.*/).*$' , '\1') | unique }} -> {{ diff.stdout_lines | map('regex_replace', '^(.*/).*$', '\1') | unique }}
diff.stdout_lines
| map('regex_replace', '^(.*/).*$' , '\\1')
| unique }}"
| unique
}}"
when: branch.stdout != default_branch

- name: Filter folders within the roles directory
Expand Down
2 changes: 2 additions & 0 deletions ansible/roles/utils-rotate-docker-secrets/handlers/main.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
- name: List all Docker secrets managed by this role
command: docker secret ls --filter label=managed_by=rotate_docker_secrets --format "{{ '{{ .Name }}' }}"
register: existing_secrets
changed_when: false

- name: Identify secrets to keep
set_fact:
Expand All @@ -14,3 +15,4 @@
when: item not in secrets_to_keep
loop: "{{ existing_secrets.stdout_lines }}"
ignore_errors: true
register: ignore_errors_register
Loading

0 comments on commit 9fd35bf

Please sign in to comment.