diff --git a/ansible/roles/gitea-runner/defaults/main.yml b/ansible/roles/gitea-runner/defaults/main.yml new file mode 100644 index 0000000..52f3cf2 --- /dev/null +++ b/ansible/roles/gitea-runner/defaults/main.yml @@ -0,0 +1,28 @@ +--- +runner_mode: "docker" +gitea_runner_version: "1.0.8" +gitea_runner_docker_image: "gitea/runner" +runner_labels: "ubuntu-latest:docker://runner-images:ubuntu-22.04" +skip_runner_registration: false + +# Paths +gitea_runner_data_dir: "/var/lib/gitea-runner" +gitea_runner_config_dir: "/etc/gitea-runner" +gitea_runner_binary_path: "/usr/local/bin/gitea_runner" + +# Prune configuration +gitea_runner_prune_until: "24h" +gitea_runner_prune_schedule: "daily" +gitea_runner_prune_label: "gitea-runner=true" + +# Service configuration +gitea_runner_service_restart_sec: "5" +gitea_runner_service_user: "{{ ansible_user | default('root') }}" + +# Runner configuration +gitea_runner_log_level: "info" +gitea_runner_container_label: "gitea-runner=true" +gitea_runner_file: ".runner" + +# Docker installation +docker_gpg_key_path: "/etc/apt/keyrings/docker.asc" diff --git a/ansible/roles/gitea-runner/molecule/binary/verify.yml b/ansible/roles/gitea-runner/molecule/binary/verify.yml new file mode 100644 index 0000000..0dc3187 --- /dev/null +++ b/ansible/roles/gitea-runner/molecule/binary/verify.yml @@ -0,0 +1,56 @@ +--- +- name: Verify + hosts: all + become: true + pre_tasks: + - name: Load role defaults + ansible.builtin.include_vars: + dir: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/defaults" + tasks: + - name: Check gitea_runner binary exists + ansible.builtin.stat: + path: "{{ gitea_runner_binary_path }}" + register: gitea_runner_stat + + - name: Assert gitea_runner binary exists + ansible.builtin.assert: + that: + - gitea_runner_stat.stat.exists + fail_msg: "gitea_runner binary is missing at {{ gitea_runner_binary_path }}" + + - name: Check Docker is installed + ansible.builtin.command: docker --version + changed_when: false + + - name: Check systemd service file exists + ansible.builtin.stat: + path: "/etc/systemd/system/gitea-runner-molecule-test-runner.service" + register: service_stat + + - name: Assert service file exists + ansible.builtin.assert: + that: + - service_stat.stat.exists + fail_msg: "Systemd service file is missing" + + - name: Check prune timer exists + ansible.builtin.stat: + path: /etc/systemd/system/docker-prune.timer + register: timer_stat + + - name: Assert prune timer exists + ansible.builtin.assert: + that: + - timer_stat.stat.exists + fail_msg: "Docker prune timer is missing" + + - name: Check config file exists + ansible.builtin.stat: + path: "{{ gitea_runner_config_dir }}/config.toml" + register: config_stat + + - name: Assert config file exists + ansible.builtin.assert: + that: + - config_stat.stat.exists + fail_msg: "Config file is missing" diff --git a/ansible/roles/gitea-runner/molecule/default/verify.yml b/ansible/roles/gitea-runner/molecule/default/verify.yml index 2d44aa2..8d3e49a 100644 --- a/ansible/roles/gitea-runner/molecule/default/verify.yml +++ b/ansible/roles/gitea-runner/molecule/default/verify.yml @@ -2,32 +2,25 @@ - name: Verify hosts: all become: true + pre_tasks: + - name: Load role defaults + ansible.builtin.include_vars: + dir: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/defaults" tasks: - - name: Check act_runner binary exists - ansible.builtin.stat: - path: /usr/local/bin/act_runner - register: act_runner_stat - - - name: Assert act_runner binary exists - ansible.builtin.assert: - that: - - act_runner_stat.stat.exists - fail_msg: "act_runner binary is missing" - - name: Check Docker is installed ansible.builtin.command: docker --version changed_when: false - - name: Check systemd service file exists - ansible.builtin.stat: - path: "/etc/systemd/system/act-runner-molecule-test-runner.service" - register: service_stat + - name: Check runner image was pulled + ansible.builtin.command: docker images gitea/runner --format '{{ '{{' }} .Repository {{ '}}' }}:{{ '{{' }} .Tag {{ '}}' }}' + register: image_list + changed_when: false - - name: Assert service file exists + - name: Assert runner image exists locally ansible.builtin.assert: that: - - service_stat.stat.exists - fail_msg: "Systemd service file is missing" + - "'gitea/runner' in image_list.stdout" + fail_msg: "Runner Docker image was not pulled" - name: Check prune timer exists ansible.builtin.stat: @@ -40,9 +33,9 @@ - timer_stat.stat.exists fail_msg: "Docker prune timer is missing" - - name: Check config file exists + - name: Check config file exists in data directory ansible.builtin.stat: - path: /etc/act-runner/config.toml + path: "{{ gitea_runner_data_dir }}/config.toml" register: config_stat - name: Assert config file exists diff --git a/ansible/roles/gitea-runner/tasks/binary_update.yml b/ansible/roles/gitea-runner/tasks/binary_update.yml new file mode 100644 index 0000000..dde72a1 --- /dev/null +++ b/ansible/roles/gitea-runner/tasks/binary_update.yml @@ -0,0 +1,9 @@ +--- +- name: Include gitea_runner download + ansible.builtin.include_tasks: download_gitea_runner.yml + +- name: Restart gitea-runner service + ansible.builtin.systemd: + name: "gitea-runner-{{ runner_name }}" + state: restarted + daemon_reload: true diff --git a/ansible/roles/gitea-runner/tasks/config.yml b/ansible/roles/gitea-runner/tasks/config.yml index 8f6d5b9..0d6087c 100644 --- a/ansible/roles/gitea-runner/tasks/config.yml +++ b/ansible/roles/gitea-runner/tasks/config.yml @@ -1,13 +1,13 @@ --- - name: Ensure config directory exists ansible.builtin.file: - path: /etc/act-runner + path: "{{ gitea_runner_config_dir }}" state: directory mode: "0755" -- name: Create act_runner config file +- name: Create gitea_runner config file ansible.builtin.template: - src: act-runner-config.toml.j2 - dest: /etc/act-runner/config.toml + src: gitea-runner-config.toml.j2 + dest: "{{ gitea_runner_config_dir }}/config.toml" mode: "0644" - notify: Restart act-runner + notify: Restart gitea-runner diff --git a/ansible/roles/gitea-runner/tasks/docker_update.yml b/ansible/roles/gitea-runner/tasks/docker_update.yml new file mode 100644 index 0000000..a641e4f --- /dev/null +++ b/ansible/roles/gitea-runner/tasks/docker_update.yml @@ -0,0 +1,23 @@ +--- +- name: Pull gitea_runner image + ansible.builtin.command: docker pull {{ gitea_runner_docker_image }}:{{ gitea_runner_version | regex_replace('^v', '') }} + changed_when: "'Downloaded newer image' in pull_result.stdout or 'Status: Downloaded' in pull_result.stdout" + register: pull_result + +- name: Stop and remove existing gitea_runner container + ansible.builtin.command: docker rm -f gitea-runner-{{ runner_name }} + changed_when: remove.rc == 0 + failed_when: remove.rc != 0 and 'No such container' not in remove.stderr + register: remove + +- name: Run updated gitea_runner daemon container + ansible.builtin.command: > + docker run -d + --name gitea-runner-{{ runner_name }} + --restart unless-stopped + -v /var/run/docker.sock:/var/run/docker.sock + -v {{ gitea_runner_data_dir }}:/data + {{ gitea_runner_docker_image }}:{{ gitea_runner_version | regex_replace('^v', '') }} daemon + --config /data/config.toml + register: docker_run + changed_when: docker_run.rc == 0 diff --git a/ansible/roles/gitea-runner/tasks/download_gitea_runner.yml b/ansible/roles/gitea-runner/tasks/download_gitea_runner.yml new file mode 100644 index 0000000..0ae8c21 --- /dev/null +++ b/ansible/roles/gitea-runner/tasks/download_gitea_runner.yml @@ -0,0 +1,41 @@ +--- +- name: Get latest gitea_runner release info + ansible.builtin.uri: + url: https://gitea.com/api/v1/repos/gitea/runner/releases/latest + return_content: true + body_format: json + headers: + Accept: application/json + register: gitea_runner_release + when: gitea_runner_version | default('latest') == 'latest' + changed_when: false + +- name: Set gitea_runner version from latest release + ansible.builtin.set_fact: + gitea_runner_version: "{{ gitea_runner_release.json.tag_name }}" + when: gitea_runner_version | default('latest') == 'latest' + +- name: Set gitea_runner download version (strip v prefix) + ansible.builtin.set_fact: + gitea_runner_download_version: "{{ gitea_runner_version | regex_replace('^v', '') }}" + +- name: Set gitea_runner download URL + ansible.builtin.set_fact: + gitea_runner_url: >- + {{ 'https://gitea.com/gitea/runner/releases/download/v' ~ gitea_runner_download_version + ~ '/gitea-runner-' ~ gitea_runner_download_version ~ '-linux-' + ~ (ansible_facts['architecture'] | regex_replace('x86_64', 'amd64')) }} + +- name: Ensure /usr/local/bin directory exists + ansible.builtin.file: + path: /usr/local/bin + state: directory + mode: "0755" + +- name: Download gitea_runner binary + ansible.builtin.get_url: + url: "{{ gitea_runner_url }}" + dest: "{{ gitea_runner_binary_path }}" + mode: "0755" + force: true + notify: Restart gitea-runner diff --git a/ansible/roles/gitea-runner/tasks/register.yml b/ansible/roles/gitea-runner/tasks/register.yml index b48744c..11ea682 100644 --- a/ansible/roles/gitea-runner/tasks/register.yml +++ b/ansible/roles/gitea-runner/tasks/register.yml @@ -1,25 +1,25 @@ --- - name: Ensure work directory exists ansible.builtin.file: - path: /var/lib/gitea-runner + path: "{{ gitea_runner_data_dir }}" state: directory mode: "0755" - name: Check if runner is already registered ansible.builtin.stat: - path: /var/lib/gitea-runner/.runner + path: "{{ gitea_runner_data_dir }}/.runner" register: runner_registered - name: Register runner with Gitea ansible.builtin.command: > - /usr/local/bin/act_runner register + "{{ gitea_runner_binary_path }}" register --token {{ registration_token }} --name {{ runner_name }} --instance {{ gitea_url }} - --labels ubuntu-latest:docker://node:16-bullseye + --labels {{ runner_labels }} --no-interactive args: - chdir: /var/lib/gitea-runner + chdir: "{{ gitea_runner_data_dir }}" when: not runner_registered.stat.exists register: register_output changed_when: "'already exists' not in register_output.stdout | default('')" diff --git a/ansible/roles/gitea-runner/tasks/validate.yml b/ansible/roles/gitea-runner/tasks/validate.yml index 020897b..564ea0f 100644 --- a/ansible/roles/gitea-runner/tasks/validate.yml +++ b/ansible/roles/gitea-runner/tasks/validate.yml @@ -1,24 +1,20 @@ --- -- name: Check act_runner binary exists +- name: Check gitea_runner binary exists ansible.builtin.stat: - path: /usr/local/bin/act_runner - register: act_runner_stat + path: "{{ gitea_runner_binary_path }}" + register: gitea_runner_stat -- name: Fail if act_runner binary is missing +- name: Fail if gitea_runner binary is missing ansible.builtin.fail: - msg: "act_runner binary not found at /usr/local/bin/act_runner" - when: not act_runner_stat.stat.exists + msg: "gitea_runner binary not found at {{ gitea_runner_binary_path }}" + when: not gitea_runner_stat.stat.exists -- name: Verify act_runner is executable - ansible.builtin.command: /usr/local/bin/act_runner --version - register: act_runner_version_output +- name: Verify gitea_runner is executable + ansible.builtin.command: "{{ gitea_runner_binary_path }} --version" + register: gitea_runner_version_output changed_when: false - name: Verify Docker connectivity ansible.builtin.command: docker version register: docker_version_output changed_when: false - -- name: Set runner_validated fact - ansible.builtin.set_fact: - runner_validated: true diff --git a/ansible/roles/gitea-runner/templates/docker-prune.service.j2 b/ansible/roles/gitea-runner/templates/docker-prune.service.j2 index 8c18a90..20f1744 100644 --- a/ansible/roles/gitea-runner/templates/docker-prune.service.j2 +++ b/ansible/roles/gitea-runner/templates/docker-prune.service.j2 @@ -5,5 +5,5 @@ Requires=docker.service [Service] Type=oneshot -ExecStart=/usr/bin/docker system prune -f --filter "label=gitea-runner=true" --filter "until=24h" -ExecStart=/usr/bin/docker volume prune -f --filter "label=gitea-runner=true" --filter "until=24h" +ExecStart=/usr/bin/docker system prune -f --filter "label={{ gitea_runner_prune_label }}" --filter "until={{ gitea_runner_prune_until }}" +ExecStart=/usr/bin/docker volume prune -f --filter "label={{ gitea_runner_prune_label }}" --filter "until={{ gitea_runner_prune_until }}" diff --git a/ansible/roles/gitea-runner/templates/docker-prune.timer.j2 b/ansible/roles/gitea-runner/templates/docker-prune.timer.j2 index 7231bd3..20f76b5 100644 --- a/ansible/roles/gitea-runner/templates/docker-prune.timer.j2 +++ b/ansible/roles/gitea-runner/templates/docker-prune.timer.j2 @@ -2,7 +2,7 @@ Description=Daily Docker prune for Gitea runner resources [Timer] -OnCalendar=daily +OnCalendar={{ gitea_runner_prune_schedule }} Persistent=true [Install] diff --git a/ansible/roles/gitea-runner/templates/gitea-runner-config.toml.j2 b/ansible/roles/gitea-runner/templates/gitea-runner-config.toml.j2 new file mode 100644 index 0000000..c5641a2 --- /dev/null +++ b/ansible/roles/gitea-runner/templates/gitea-runner-config.toml.j2 @@ -0,0 +1,3 @@ +log.level = "{{ gitea_runner_log_level }}" +runner.file = "{{ gitea_runner_file }}" +container.label = "{{ gitea_runner_container_label }}" diff --git a/ansible/roles/gitea-runner/templates/gitea-runner.service.j2 b/ansible/roles/gitea-runner/templates/gitea-runner.service.j2 new file mode 100644 index 0000000..df463b9 --- /dev/null +++ b/ansible/roles/gitea-runner/templates/gitea-runner.service.j2 @@ -0,0 +1,16 @@ +[Unit] +Description=Gitea Actions Runner ({{ runner_name }}) +After=network.target docker.service +Requires=docker.service + +[Service] +Type=simple +ExecStart={{ gitea_runner_binary_path }} daemon --config {{ gitea_runner_config_dir }}/config.toml +WorkingDirectory={{ gitea_runner_data_dir }} +Restart=always +RestartSec={{ gitea_runner_service_restart_sec }} +User={{ gitea_runner_service_user }} +Group=docker + +[Install] +WantedBy=multi-user.target