161 lines
6.2 KiB
YAML
161 lines
6.2 KiB
YAML
|
|
---
|
||
|
|
- name: Install Gitea Actions self-hosted runners
|
||
|
|
hosts: all
|
||
|
|
become: true
|
||
|
|
|
||
|
|
pre_tasks:
|
||
|
|
- name: Assert host defines a runners matrix
|
||
|
|
ansible.builtin.assert:
|
||
|
|
that:
|
||
|
|
- runners is defined
|
||
|
|
- runners | length > 0
|
||
|
|
- runner_env is defined
|
||
|
|
fail_msg: "Host {{ inventory_hostname }} is missing host_vars (runners / runner_env)."
|
||
|
|
|
||
|
|
tasks:
|
||
|
|
- name: Ensure runner service user exists
|
||
|
|
ansible.builtin.user:
|
||
|
|
name: "{{ runner_user }}"
|
||
|
|
shell: /bin/bash
|
||
|
|
create_home: true
|
||
|
|
home: "{{ runner_home }}"
|
||
|
|
|
||
|
|
# JS actions (actions/checkout@v4, etc.) execute with `node` on the host
|
||
|
|
# executor. Without it act_runner fails: "Cannot find: node in PATH".
|
||
|
|
# git is needed by checkout for its fetch step.
|
||
|
|
- name: Ensure git is present
|
||
|
|
ansible.builtin.apt:
|
||
|
|
name: git
|
||
|
|
state: present
|
||
|
|
update_cache: true
|
||
|
|
|
||
|
|
- name: Install Node.js {{ node_major_version }}.x (NodeSource)
|
||
|
|
block:
|
||
|
|
# Key is ASCII-armored, so store it as .asc — apt reads .gpg as binary
|
||
|
|
# and .asc as armored; a mismatch fails repo signature verification.
|
||
|
|
- name: Add NodeSource apt key
|
||
|
|
ansible.builtin.get_url:
|
||
|
|
url: https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key
|
||
|
|
dest: /usr/share/keyrings/nodesource.asc
|
||
|
|
mode: "0644"
|
||
|
|
|
||
|
|
- name: Add NodeSource apt repo
|
||
|
|
ansible.builtin.apt_repository:
|
||
|
|
repo: "deb [signed-by=/usr/share/keyrings/nodesource.asc] https://deb.nodesource.com/node_{{ node_major_version }}.x nodistro main"
|
||
|
|
filename: nodesource
|
||
|
|
|
||
|
|
- name: Install nodejs
|
||
|
|
ansible.builtin.apt:
|
||
|
|
name: nodejs
|
||
|
|
state: present
|
||
|
|
update_cache: true
|
||
|
|
|
||
|
|
# Security scanners used by the CI workflows. Pre-installing them (as root)
|
||
|
|
# means the workflow steps find them on PATH and skip their runtime install,
|
||
|
|
# which would otherwise fail writing to /usr/local/bin as the runner user.
|
||
|
|
- name: Check installed Trivy version
|
||
|
|
ansible.builtin.command: trivy --version
|
||
|
|
register: trivy_check
|
||
|
|
changed_when: false
|
||
|
|
failed_when: false
|
||
|
|
|
||
|
|
- name: Install Trivy {{ trivy_version }}
|
||
|
|
ansible.builtin.shell: |
|
||
|
|
set -o pipefail
|
||
|
|
curl -sSfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh \
|
||
|
|
| sh -s -- -b /usr/local/bin v{{ trivy_version }}
|
||
|
|
args:
|
||
|
|
executable: /bin/bash
|
||
|
|
when: trivy_version not in (trivy_check.stdout | default(''))
|
||
|
|
|
||
|
|
- name: Check installed Gitleaks version
|
||
|
|
ansible.builtin.command: gitleaks version
|
||
|
|
register: gitleaks_check
|
||
|
|
changed_when: false
|
||
|
|
failed_when: false
|
||
|
|
|
||
|
|
- name: Install Gitleaks {{ gitleaks_version }}
|
||
|
|
ansible.builtin.unarchive:
|
||
|
|
src: "https://github.com/gitleaks/gitleaks/releases/download/v{{ gitleaks_version }}/gitleaks_{{ gitleaks_version }}_linux_x64.tar.gz"
|
||
|
|
dest: /usr/local/bin
|
||
|
|
remote_src: true
|
||
|
|
include:
|
||
|
|
- gitleaks
|
||
|
|
mode: "0755"
|
||
|
|
when: gitleaks_version not in (gitleaks_check.stdout | default(''))
|
||
|
|
|
||
|
|
# The Docker engine ships without CLI plugins, so `docker compose` (used by
|
||
|
|
# deploy.sh) and `docker buildx` are absent. Install them host-wide; this
|
||
|
|
# path is searched by both docker.io and docker-ce CLIs.
|
||
|
|
- name: Ensure Docker CLI plugins dir exists
|
||
|
|
ansible.builtin.file:
|
||
|
|
path: /usr/libexec/docker/cli-plugins
|
||
|
|
state: directory
|
||
|
|
mode: "0755"
|
||
|
|
|
||
|
|
- name: Check installed Docker Compose plugin version
|
||
|
|
ansible.builtin.command: docker compose version --short
|
||
|
|
register: compose_check
|
||
|
|
changed_when: false
|
||
|
|
failed_when: false
|
||
|
|
|
||
|
|
- name: Install Docker Compose v2 plugin {{ docker_compose_version }}
|
||
|
|
ansible.builtin.get_url:
|
||
|
|
url: "https://github.com/docker/compose/releases/download/v{{ docker_compose_version }}/docker-compose-linux-x86_64"
|
||
|
|
dest: /usr/libexec/docker/cli-plugins/docker-compose
|
||
|
|
mode: "0755"
|
||
|
|
force: true
|
||
|
|
when: docker_compose_version not in (compose_check.stdout | default(''))
|
||
|
|
|
||
|
|
- name: Check installed Docker Buildx plugin version
|
||
|
|
ansible.builtin.command: docker buildx version
|
||
|
|
register: buildx_check
|
||
|
|
changed_when: false
|
||
|
|
failed_when: false
|
||
|
|
|
||
|
|
- name: Install Docker Buildx plugin {{ docker_buildx_version }}
|
||
|
|
ansible.builtin.get_url:
|
||
|
|
url: "https://github.com/docker/buildx/releases/download/v{{ docker_buildx_version }}/buildx-v{{ docker_buildx_version }}.linux-amd64"
|
||
|
|
dest: /usr/libexec/docker/cli-plugins/docker-buildx
|
||
|
|
mode: "0755"
|
||
|
|
force: true
|
||
|
|
when: docker_buildx_version not in (buildx_check.stdout | default(''))
|
||
|
|
|
||
|
|
# Deploy target for each project's compose stack. Owned by the runner so the
|
||
|
|
# deploy job can `cp docker-compose.yml` here; the host-managed .env lives
|
||
|
|
# here too. Basename matches the compose project name, preserving volumes.
|
||
|
|
- name: Ensure app deploy dir exists for each project
|
||
|
|
ansible.builtin.file:
|
||
|
|
path: "{{ app_base_dir }}/{{ item.project }}"
|
||
|
|
state: directory
|
||
|
|
owner: "{{ runner_user }}"
|
||
|
|
group: "{{ runner_user }}"
|
||
|
|
mode: "0755"
|
||
|
|
loop: "{{ runners }}"
|
||
|
|
loop_control:
|
||
|
|
label: "{{ item.project }}"
|
||
|
|
|
||
|
|
- name: Install runners for each project
|
||
|
|
ansible.builtin.include_tasks: tasks/install_project.yml
|
||
|
|
loop: "{{ runners }}"
|
||
|
|
loop_control:
|
||
|
|
loop_var: project_spec
|
||
|
|
label: "{{ project_spec.project }}"
|
||
|
|
|
||
|
|
# The build job runs `docker build` on the host, talking to the daemon via
|
||
|
|
# /var/run/docker.sock. Without docker group membership the runner user gets
|
||
|
|
# "permission denied ... unix:///var/run/docker.sock".
|
||
|
|
- name: Add runner user to the docker group
|
||
|
|
ansible.builtin.user:
|
||
|
|
name: "{{ runner_user }}"
|
||
|
|
groups: docker
|
||
|
|
append: true
|
||
|
|
register: runner_docker_group
|
||
|
|
|
||
|
|
# Group membership is only read at process start, so already-running runner
|
||
|
|
# services must be restarted to gain socket access.
|
||
|
|
- name: Restart runner services to apply docker group membership
|
||
|
|
ansible.builtin.shell: "systemctl restart 'gitea-runner-*.service'"
|
||
|
|
when: runner_docker_group is changed
|
||
|
|
changed_when: true
|