Chore/migrate ansible logic to workflow steps (#44)
Deploy / deploy (push) Successful in 14s

- Move logic from ansible to bash / gitea workflow
- **TODO:** test `add-new-service` deployment logic

---------

Co-authored-by: Benjamin Labrecque <labrecque.benji@gmail.com>
Reviewed-on: #44
This commit was merged in pull request #44.
This commit is contained in:
2026-07-30 13:34:53 +02:00
co-authored by Benjamin Labrecque
parent 03b00da0c6
commit ab5534f974
21 changed files with 102 additions and 120 deletions
+33
View File
@@ -0,0 +1,33 @@
#!/bin/bash
SERVICE_NAME=$1
AGEBD_ENV=$2
echo "=========================================="
echo "Deploying service: $SERVICE_NAME (${AGEBD_ENV})"
echo "=========================================="
SERVICE_NAME_LOWER=$(echo "$SERVICE_NAME" | tr '[:upper:]' '[:lower:]')
SERVICE_NAME_UPPER=$(echo "$SERVICE_NAME" | tr '[:lower:]' '[:upper:]')
SERVICE_DIR=/sls/bd/hla/${AGEBD_ENV}/services/${SERVICE_NAME_LOWER}/current
SYSTEMD_UNIT_NAME=AGEBD-SERVICE-${SERVICE_NAME_UPPER}.service
SYSTEMD_UNIT_FILE_PATH=${SERVICE_DIR}/systemd/${SYSTEMD_UNIT_NAME}
mkdir -p ${SERVICE_DIR}
rsync -avz --delete --exclude='.venv' \
./services/${SERVICE_NAME_LOWER}/current/ \
${SERVICE_DIR}/
if [ -f "${SYSTEMD_UNIT_FILE_PATH}" ]; then
sed -i "s/{{ *agebd_env* }}/${AGEBD_ENV}/g" "${SYSTEMD_UNIT_FILE_PATH}"
fi
mkdir -p ${HOME}/.config/systemd/user
ln -sf "${SYSTEMD_UNIT_FILE_PATH}" "${HOME}/.config/systemd/user/${SYSTEMD_UNIT_NAME}"
export XDG_RUNTIME_DIR="/run/user/$(id -u)"
systemctl --user daemon-reload
systemctl --user enable "${SYSTEMD_UNIT_NAME}"
systemctl --user restart "${SYSTEMD_UNIT_NAME}"
+11 -31
View File
@@ -10,9 +10,6 @@ jobs:
deploy:
runs-on: hla-dev
env:
ANSIBLE_CONFIG: "${{ github.workspace }}/ansible/ansible.cfg"
steps:
- name: Checkout repository
uses: actions/checkout@v4
@@ -38,36 +35,19 @@ jobs:
SERVICE_NAME="${BRANCH#feature/add-service-}"
echo "service_name_lower=$SERVICE_NAME" >> $GITHUB_OUTPUT
# TODO: look into venv caching (will do later in case we move from uv to pixi)
# - name: Cache Python Virtual Environment
# uses: actions/cache@v4
# with:
# path: .venv
# # Changes uv.lock will automatically invalidate the cache and rebuild
# key: ${{ runner.os }}-uv-cli-venv-${{ hashFiles('cli/uv.lock') }}
# restore-keys: |
# ${{ runner.os }}-uv-cli-venv-
# - name: Install Master IOC
# # Only create the venv if the cache didn't restore an existing one
# if [ ! -d ".venv" ]; then
# echo "Building new .venv"
# uv venv .venv
# fi
- name: Initialize Virtual Environment from cli/uv.lock
run: |
uv venv .venv
uv sync --directory cli
# - name: Restart Master IOC
- name: Install Ansible Galaxy Collections
- name: Deploy and Restart Master Service
run: |
uv run ansible-galaxy collection install -r ansible/collections/requirements.yml -p ./ansible/installed-collections
./.gitea/scripts/deploy-and-restart-service.sh "master" "dev"
# TODO: dev/prod
- name: Run New Service Playbook
working-directory: ansible
# - name: Install New IOC
# - name: Start New IOC
- name: Deploy and Restart New Service
run: |
uv run ansible-playbook playbooks/add-new-service.yml \
-i "inventories/dev/hosts.yml" \
--extra-vars="repo_root=${{ github.workspace }}" \
--extra-vars="service_name_lower=${{ steps.parse_branch.outputs.service_name_lower }}" \
-v
SERVICE_NAME=${{ steps.parse_branch.outputs.service_name_lower }}
./.gitea/scripts/deploy-and-restart-service.sh "${SERVICE_NAME}" "dev"
-13
View File
@@ -1,13 +0,0 @@
# name: Deploy agebd python package to gitea/pypi
#
# # TODO: services depend on this workflow
# on:
# push:
# branches:
# - main
# paths:
# - 'packages/agebd/**'
#
# jobs:
# deploy:
# runs-on: hla-dev
+41 -59
View File
@@ -13,23 +13,27 @@ on:
- 'qt/**'
- 'services/**'
# Cancel previous runs if a new commit is pushed to the same branch
concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: true
env:
# commit tagged ? yes->prod : no->dev
AGEBD_ENV: ${{ github.ref_type == 'tag' && 'prod' || 'dev' }}
jobs:
deploy:
runs-on: hla-dev
env:
# commit tagged ? yes->prod : no->dev
AGEBD_ENV: ${{ github.ref_type == 'tag' && 'prod' || 'dev' }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 2 # needed for git diff tracking
fetch-depth: 0 # Needed for git diff in service detection
- name: Defined filter paths
uses: actions/paths-filter@v3 # see: https://gitea.psi.ch/actions/paths-filter
- name: Define filter paths
uses: actions/paths-filter@v3
id: filter
with:
filters: |
@@ -43,7 +47,7 @@ jobs:
- 'services/**'
- name: Install uv
uses: actions/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
uses: actions/setup-uv@v5
- name: Install Python 3.10
run: uv python install 3.10
@@ -52,76 +56,54 @@ jobs:
run: |
cd scripts && uv run pytest
# TODO: maybe this is better: `rsync -av --delete ./ "${DEST_DIR}/"` # Sync everything perfectly, including hidden files, and delete old stale files
# -----------------------------------------------------------------
# Directory Deployments
# -----------------------------------------------------------------
- name: Bin - deploy
if: steps.filter.outputs.bin == 'true'
env:
# commit tagged ? yes->prod : no->dev
DEST_DIR: /sls/bd/hla/${{ github.ref_type == 'tag' && 'prod' || 'dev' }}/bin
working-directory: bin
DEST_DIR: /sls/bd/hla/${{ env.AGEBD_ENV }}/bin
run: |
mkdir -p ${DEST_DIR}
cp -r ./* ${DEST_DIR}
mkdir -p "${DEST_DIR}"
rsync -av --delete --exclude='.nfs*' ./bin/ "${DEST_DIR}/"
# TODO: maybe this is better: `rsync -av --delete ./ "${DEST_DIR}/"` # Sync everything perfectly, including hidden files, and delete old stale files
- name: Agebd - deploy
if: steps.filter.outputs.agebd == 'true'
env:
# commit tagged ? yes->prod : no->dev
DEST_DIR: /sls/bd/hla/${{ github.ref_type == 'tag' && 'prod' || 'dev' }}/packages/agebd
working-directory: packages/agebd
DEST_DIR: /sls/bd/hla/${{ env.AGEBD_ENV }}/packages/agebd
run: |
mkdir -p ${DEST_DIR}
cp -r ./* ${DEST_DIR}
mkdir -p "${DEST_DIR}"
rsync -av --delete --exclude='.nfs*' ./packages/agebd/ "${DEST_DIR}/"
# TODO: maybe this is better: `rsync -av --delete ./ "${DEST_DIR}/"` # Sync everything perfectly, including hidden files, and delete old stale files
- name: Qt - deploy
if: steps.filter.outputs.qt == 'true'
env:
# commit tagged ? yes->prod : no->dev
DEST_DIR: /sls/bd/hla/${{ github.ref_type == 'tag' && 'prod' || 'dev' }}/qt
working-directory: qt
DEST_DIR: /sls/bd/hla/${{ env.AGEBD_ENV }}/qt
run: |
mkdir -p ${DEST_DIR}
cp -r ./* ${DEST_DIR}
mkdir -p "${DEST_DIR}"
rsync -av --delete --exclude='.nfs*' ./qt/ "${DEST_DIR}/"
# TODO: (when) do we need to restart the master service or reinstall/restart the master ioc?
- name: Services - Initialize Virtual Environment from cli/uv.lock
# -----------------------------------------------------------------
# Services Deployment
# -----------------------------------------------------------------
- name: Deploy Changed Services
if: steps.filter.outputs.services == 'true'
run: |
uv venv .venv
uv sync --directory cli
# 1. Determine git comparison point
BEFORE="${{ github.event.before }}"
if [ -z "$BEFORE" ] || [ "$BEFORE" = "0000000000000000000000000000000000000000" ]; then
BEFORE="HEAD~1"
fi
- name: Services - Install Ansible Galaxy Collections
if: steps.filter.outputs.services == 'true'
run: |
uv run ansible-galaxy collection install -r ansible/collections/requirements.yml -p ./ansible/installed-collections
# 2. Extract list of modified service folder names
CHANGED_SERVICES=$(git diff --name-only "$BEFORE" "${{ github.sha }}" | awk -F/ '$1=="services" && $2!="" {print $2}' | sort -u)
- name: Services - Run Ansible Orchestrator
if: steps.filter.outputs.services == 'true'
working-directory: ansible
run: |
set -x
# Disable pipefail temporarily or add an '|| true' fallback so grep doesn't kill the script
set +e
CHANGED_FILES=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }})
set -e
# 1. Parse changed directory names into space-separated string (e.g. "master other-service")
CHANGED_SVC=$(echo "$CHANGED_FILES" | awk -F/ '$1=="services" {print $2}' | sort -u | xargs)
echo "Detected changed services: '$CHANGED_SVC'"
# Safely halt the execution if there is nothing to pass to Ansible
if [ -z "$CHANGED_SVC" ]; then
echo "No services changed in this commit range. Skipping deployment smoothly."
if [ -z "$CHANGED_SERVICES" ]; then
echo "No service directory changes detected in diff."
exit 0
fi
# 3. Fire the playbook passing variables down
ansible-playbook playbooks/deploy-and-restart-modified-services.yml \
-i "inventories/$AGEBD_ENV/hosts.yml" \
--extra-vars="changed_services_raw='$CHANGED_SVC'" \
-v
# 3. Loop through changed services and invoke deployment script
echo "$CHANGED_SERVICES" | while read -r SERVICE; do
./.gitea/scripts/deploy-and-restart-service.sh "${SERVICE}" "${AGEBD_ENV}"
done
+1 -1
View File
@@ -42,4 +42,4 @@ source ${APP_DIR}/.venv/bin/activate
# TODO: use `exec python3 ...` here?
python -u -B -m agebd_${SVC_NAME_LOWER_UNDERSCORES}.main
# TODO: remove: cicd test 10
# TODO: remove: cicd test 26
+1 -1
View File
@@ -1,6 +1,6 @@
from agebd.pv import PVLink
# TODO: remove: cicd test 10
# TODO: remove: cicd test 26
class BasePVs:
@@ -6,7 +6,7 @@ from agebd.utils import init_logging
from agebd_dbpm3curr import PVs, Service
from agebd_dbpm3curr.service import SERVICE_NAME
# TODO: remove: cicd test 10
# TODO: remove: cicd test 26
def main(
@@ -6,7 +6,7 @@ from agebd.utils import init_logging
from agebd_injectionguard import PVs, Service
from agebd_injectionguard.service import SERVICE_NAME
# TODO: remove: cicd test 10
# TODO: remove: cicd test 26
def main(
@@ -6,7 +6,7 @@ from agebd.utils import init_logging
from agebd_master import PVs, Service
from agebd_master.service import SERVICE_NAME
# TODO: remove: cicd test 10
# TODO: remove: cicd test 26
def main(
@@ -6,7 +6,7 @@ from agebd.utils import init_logging
from agebd_plots import PVs, Service
from agebd_plots.service import SERVICE_NAME
# TODO: remove: cicd test 10
# TODO: remove: cicd test 26
def main(
@@ -6,7 +6,7 @@ from agebd.utils import init_logging
from agebd_postmortemlog import PVs, Service
from agebd_postmortemlog.service import SERVICE_NAME
# TODO: remove: cicd test 10
# TODO: remove: cicd test 26
def main(
@@ -6,7 +6,7 @@ from agebd_scrubbing import PVs, Service
from agebd_scrubbing.runner import Runner
from agebd_scrubbing.service import SERVICE_NAME
# TODO: remove: cicd test 10
# TODO: remove: cicd test 26
def main(
@@ -6,7 +6,7 @@ from agebd.utils import init_logging
from agebd_shifttool import PVs, Service
from agebd_shifttool.service import SERVICE_NAME
# TODO: remove: cicd test 10
# TODO: remove: cicd test 26
def main(
@@ -6,7 +6,7 @@ from agebd.utils import init_logging
from agebd_taubpm import PVs, Service
from agebd_taubpm.service import SERVICE_NAME
# TODO: remove: cicd test 10
# TODO: remove: cicd test 26
def main(
@@ -6,7 +6,7 @@ from agebd.utils import init_logging
from agebd_taupct import PVs, Service
from agebd_taupct.service import SERVICE_NAME
# TODO: remove: cicd test 10
# TODO: remove: cicd test 26
def main(
@@ -6,7 +6,7 @@ from agebd.utils import init_logging
from agebd_timing import PVs, Service
from agebd_timing.service import SERVICE_NAME
# TODO: remove: cicd test 10
# TODO: remove: cicd test 26
def main(
@@ -6,7 +6,7 @@ from agebd_topuptool import PVs, Service
from agebd_topuptool.runner import Runner
from agebd_topuptool.service import SERVICE_NAME
# TODO: remove: cicd test 10
# TODO: remove: cicd test 26
def main(
@@ -6,7 +6,7 @@ from agebd.utils import init_logging
from agebd_tune import PVs, Service
from agebd_tune.service import SERVICE_NAME
# TODO: remove: cicd test 10
# TODO: remove: cicd test 26
def main(
@@ -6,7 +6,7 @@ from agebd.utils import init_logging
from agebd_tunebump import PVs, Service
from agebd_tunebump.service import SERVICE_NAME
# TODO: remove: cicd test 10
# TODO: remove: cicd test 26
def main(
@@ -6,7 +6,7 @@ from agebd.utils import init_logging
from agebd_tunefbx import PVs, Service
from agebd_tunefbx.service import SERVICE_NAME
# TODO: remove: cicd test 10
# TODO: remove: cicd test 26
def main(
@@ -7,7 +7,7 @@ from agebd_tunefby import PVs, Service
from agebd_tunefby.service import SERVICE_NAME
# TODO: remove: cicd test 10
# TODO: remove: cicd test 26
def main(
log_level: LogLevel = typer.Option(