diff --git a/ansible/disable-runner.yml b/ansible/disable-runner.yml new file mode 100644 index 0000000..f2f11fe --- /dev/null +++ b/ansible/disable-runner.yml @@ -0,0 +1,26 @@ +--- +- name: Disable Gitea Actions runner + hosts: all + become: true + vars: {} + tasks: + - name: Include systemd availability check + ansible.builtin.include_tasks: roles/gitea-runner/tasks/systemd_check.yml + + - name: Stop gitea-runner systemd instance + ansible.builtin.systemd: + name: "gitea-runner@{{ runner_name }}" + state: stopped + daemon_reload: true + when: systemd_available.stat.exists + + - name: Include deregistration + ansible.builtin.include_tasks: roles/gitea-runner/tasks/deregister.yml + when: not skip_runner_registration | default(false) + + - name: Disable gitea-runner systemd instance + ansible.builtin.systemd: + name: "gitea-runner@{{ runner_name }}" + enabled: false + daemon_reload: true + when: systemd_available.stat.exists diff --git a/ansible/enable-runner.yml b/ansible/enable-runner.yml new file mode 100644 index 0000000..351e21d --- /dev/null +++ b/ansible/enable-runner.yml @@ -0,0 +1,15 @@ +--- +- name: Enable Gitea Actions runner + hosts: all + become: true + vars: {} + tasks: + - name: Include systemd availability check + ansible.builtin.include_tasks: roles/gitea-runner/tasks/systemd_check.yml + + - name: Enable gitea-runner systemd instance + ansible.builtin.systemd: + name: "gitea-runner@{{ runner_name }}" + enabled: true + daemon_reload: true + when: systemd_available.stat.exists diff --git a/ansible/remove-runner.yml b/ansible/remove-runner.yml new file mode 100644 index 0000000..1ffe5b1 --- /dev/null +++ b/ansible/remove-runner.yml @@ -0,0 +1,42 @@ +--- +- name: Remove Gitea Actions runner + hosts: all + become: true + vars: {} + tasks: + - name: Include systemd availability check + ansible.builtin.include_tasks: roles/gitea-runner/tasks/systemd_check.yml + + - name: Stop gitea-runner systemd instance + ansible.builtin.systemd: + name: "gitea-runner@{{ runner_name }}" + state: stopped + daemon_reload: true + when: systemd_available.stat.exists + + - name: Disable gitea-runner systemd instance + ansible.builtin.systemd: + name: "gitea-runner@{{ runner_name }}" + enabled: false + daemon_reload: true + when: systemd_available.stat.exists + + - name: Include deregistration + ansible.builtin.include_tasks: roles/gitea-runner/tasks/deregister.yml + when: not skip_runner_registration | default(false) + + - name: Remove systemd unit file (last instance) + ansible.builtin.file: + path: "/etc/systemd/system/gitea-runner@.service" + state: absent + when: remove_systemd_template | default(false) + + - name: Remove runner data directory + ansible.builtin.file: + path: "{{ gitea_runner_data_dir | default('/var/lib/gitea-runner/' ~ runner_name) }}" + state: absent + + - name: Remove runner config directory + ansible.builtin.file: + path: "{{ gitea_runner_config_dir | default('/etc/gitea-runner/' ~ runner_name) }}" + state: absent diff --git a/ansible/roles/gitea-runner/defaults/main.yml b/ansible/roles/gitea-runner/defaults/main.yml index 52f3cf2..eed3ea6 100644 --- a/ansible/roles/gitea-runner/defaults/main.yml +++ b/ansible/roles/gitea-runner/defaults/main.yml @@ -5,9 +5,11 @@ 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" +# Base paths (instance-scoped via runner_name) +gitea_runner_base_data_dir: "/var/lib/gitea-runner" +gitea_runner_base_config_dir: "/etc/gitea-runner" +gitea_runner_data_dir: "{{ gitea_runner_base_data_dir }}/{{ runner_name }}" +gitea_runner_config_dir: "{{ gitea_runner_base_config_dir }}/{{ runner_name }}" gitea_runner_binary_path: "/usr/local/bin/gitea_runner" # Prune configuration diff --git a/ansible/roles/gitea-runner/handlers/main.yml b/ansible/roles/gitea-runner/handlers/main.yml index 9f49376..cff7f5c 100644 --- a/ansible/roles/gitea-runner/handlers/main.yml +++ b/ansible/roles/gitea-runner/handlers/main.yml @@ -6,6 +6,6 @@ - name: Restart gitea-runner ansible.builtin.systemd: - name: "gitea-runner-{{ runner_name }}" + name: "gitea-runner@{{ runner_name }}" state: restarted when: ansible_facts is defined and ansible_facts['service_mgr'] | default('') == 'systemd' diff --git a/ansible/roles/gitea-runner/tasks/binary_update.yml b/ansible/roles/gitea-runner/tasks/binary_update.yml index dde72a1..1f18081 100644 --- a/ansible/roles/gitea-runner/tasks/binary_update.yml +++ b/ansible/roles/gitea-runner/tasks/binary_update.yml @@ -2,8 +2,8 @@ - name: Include gitea_runner download ansible.builtin.include_tasks: download_gitea_runner.yml -- name: Restart gitea-runner service +- name: Restart gitea-runner systemd instance ansible.builtin.systemd: - name: "gitea-runner-{{ runner_name }}" + name: "gitea-runner@{{ runner_name }}" state: restarted daemon_reload: true diff --git a/ansible/roles/gitea-runner/tasks/deregister.yml b/ansible/roles/gitea-runner/tasks/deregister.yml new file mode 100644 index 0000000..ce8cecc --- /dev/null +++ b/ansible/roles/gitea-runner/tasks/deregister.yml @@ -0,0 +1,62 @@ +--- +- name: Check if runner registration file exists + ansible.builtin.stat: + path: "{{ gitea_runner_data_dir }}/.runner" + register: runner_file_stat + +- name: Read runner registration file + ansible.builtin.slurp: + src: "{{ gitea_runner_data_dir }}/.runner" + register: runner_file_content + when: runner_file_stat.stat.exists | default(false) | bool + +- name: Parse runner registration data + ansible.builtin.set_fact: + runner_reg: > + {{ (runner_file_content.content | b64decode | from_json) + if (runner_file_content is defined and runner_file_content.content is defined) + else {} }} + when: runner_file_stat.stat.exists | default(false) | bool + +- name: Deregister runner with Gitea via CLI + ansible.builtin.command: > + {{ gitea_runner_binary_path }} delete + --token {{ registration_token }} + --name {{ runner_name }} + --instance {{ gitea_url }} + --no-interactive + args: + chdir: "{{ gitea_runner_data_dir }}" + when: + - runner_file_stat.stat.exists | default(false) | bool + - not skip_runner_registration + - runner_mode == 'binary' + register: deregister_output + changed_when: deregister_output.rc == 0 + failed_when: false + +- name: Deregister runner with Gitea via Docker + ansible.builtin.command: > + docker run --rm + --entrypoint /usr/local/bin/gitea-runner + -v {{ gitea_runner_data_dir }}:/data + -w /data + {{ gitea_runner_docker_image }}:{{ gitea_runner_version | regex_replace('^v', '') }} + delete + --token {{ registration_token }} + --name {{ runner_name }} + --instance {{ gitea_url }} + --no-interactive + when: + - runner_file_stat.stat.exists | default(false) | bool + - not skip_runner_registration + - runner_mode == 'docker' + register: deregister_docker_output + changed_when: deregister_docker_output.rc == 0 + failed_when: false + +- name: Remove runner registration file + ansible.builtin.file: + path: "{{ gitea_runner_data_dir }}/.runner" + state: absent + when: runner_file_stat.stat.exists | default(false) | bool diff --git a/ansible/roles/gitea-runner/tasks/docker_mode.yml b/ansible/roles/gitea-runner/tasks/docker_mode.yml index 853e74d..b636aa1 100644 --- a/ansible/roles/gitea-runner/tasks/docker_mode.yml +++ b/ansible/roles/gitea-runner/tasks/docker_mode.yml @@ -44,26 +44,5 @@ changed_when: "'already exists' not in register_output.stdout | default('')" timeout: 60 -- name: Check if gitea_runner container exists - ansible.builtin.command: docker inspect -f '{{ '{{' }} .State.Running {{ '}}' }}' gitea-runner-{{ runner_name }} - register: container_check - changed_when: false - failed_when: container_check.rc != 0 and 'no such object' not in container_check.stderr - -- name: Run gitea_runner daemon container - ansible.builtin.command: > - docker run -d - --name gitea-runner-{{ runner_name }} - --restart unless-stopped - --entrypoint /usr/local/bin/gitea-runner - -v /var/run/docker.sock:/var/run/docker.sock - -v {{ gitea_runner_data_dir }}:/data - -w /data - {{ gitea_runner_docker_image }}:{{ gitea_runner_version | regex_replace('^v', '') }} - daemon - --config /data/config.yaml - when: - - container_check.rc != 0 - - not skip_runner_registration - register: docker_run - changed_when: docker_run.rc == 0 +- name: Include service setup + ansible.builtin.include_tasks: service.yml diff --git a/ansible/roles/gitea-runner/tasks/docker_update.yml b/ansible/roles/gitea-runner/tasks/docker_update.yml index a598735..549d322 100644 --- a/ansible/roles/gitea-runner/tasks/docker_update.yml +++ b/ansible/roles/gitea-runner/tasks/docker_update.yml @@ -4,20 +4,9 @@ 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.yaml - register: docker_run - changed_when: docker_run.rc == 0 +- name: Restart gitea-runner systemd instance + ansible.builtin.systemd: + name: "gitea-runner@{{ runner_name }}" + state: restarted + daemon_reload: true + when: systemd_available.stat.exists diff --git a/ansible/roles/gitea-runner/tasks/integration_test.yml b/ansible/roles/gitea-runner/tasks/integration_test.yml index 8e5a170..4999c6c 100644 --- a/ansible/roles/gitea-runner/tasks/integration_test.yml +++ b/ansible/roles/gitea-runner/tasks/integration_test.yml @@ -27,7 +27,7 @@ - name: Verify runner service active (Binary mode) ansible.builtin.systemd: - name: gitea-runner + name: "gitea-runner@{{ runner_name }}" state: started register: service_check when: runner_mode == 'binary' diff --git a/ansible/roles/gitea-runner/tasks/service.yml b/ansible/roles/gitea-runner/tasks/service.yml index 9a158ba..c40cfa6 100644 --- a/ansible/roles/gitea-runner/tasks/service.yml +++ b/ansible/roles/gitea-runner/tasks/service.yml @@ -1,16 +1,16 @@ --- -- name: Create systemd service file +- name: Create systemd template service file ansible.builtin.template: - src: gitea-runner.service.j2 - dest: "/etc/systemd/system/gitea-runner-{{ runner_name }}.service" + src: gitea-runner@.service.j2 + dest: "/etc/systemd/system/gitea-runner@.service" mode: "0644" notify: - Reload systemd - Restart gitea-runner -- name: Enable and start gitea-runner service +- name: Enable and start gitea-runner instance ansible.builtin.systemd: - name: "gitea-runner-{{ runner_name }}" + name: "gitea-runner@{{ runner_name }}" state: started enabled: true daemon_reload: true 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..52ee713 --- /dev/null +++ b/ansible/roles/gitea-runner/templates/gitea-runner@.service.j2 @@ -0,0 +1,33 @@ +[Unit] +Description=Gitea Actions Runner %i ({% if runner_mode == 'docker' %}docker{% else %}binary{% endif %}) +After=network.target{% if runner_mode == 'docker' %} docker.service +Requires=docker.service{% endif %} + +[Service] +Type=simple +{% if runner_mode == 'docker' %} +ExecStartPre=-/usr/bin/docker rm -f gitea-runner-%i +ExecStart=/usr/bin/docker run -d --name gitea-runner-%i \ + --restart=no \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v {{ gitea_runner_base_data_dir }}/%i:/data \ + -w /data \ + {{ gitea_runner_docker_image }}:{{ gitea_runner_version | regex_replace('^v', '') }} \ + daemon --config /data/config.yaml +ExecStop=/usr/bin/docker stop -t 30 gitea-runner-%i +ExecStopPost=-/usr/bin/docker rm -f gitea-runner-%i +Restart=on-failure +RestartSec={{ gitea_runner_service_restart_sec }} +{% else %} +ExecStart={{ gitea_runner_binary_path }} daemon --config {{ gitea_runner_base_config_dir }}/%i/config.yaml +WorkingDirectory={{ gitea_runner_base_data_dir }}/%i +ExecStop=/bin/kill -TERM $MAINPID +TimeoutStopSec=30 +Restart=on-failure +RestartSec={{ gitea_runner_service_restart_sec }} +User={{ gitea_runner_service_user }} +Group=docker +{% endif %} + +[Install] +WantedBy=multi-user.target diff --git a/ansible/start-runner.yml b/ansible/start-runner.yml new file mode 100644 index 0000000..4008620 --- /dev/null +++ b/ansible/start-runner.yml @@ -0,0 +1,26 @@ +--- +- name: Start Gitea Actions runner + hosts: all + become: true + vars: {} + tasks: + - name: Include systemd availability check + ansible.builtin.include_tasks: roles/gitea-runner/tasks/systemd_check.yml + + - name: Check if runner is already registered + ansible.builtin.stat: + path: "{{ gitea_runner_data_dir | default('/var/lib/gitea-runner/' ~ runner_name) }}/.runner" + register: runner_registered + + - name: Include registration if not registered + ansible.builtin.include_tasks: roles/gitea-runner/tasks/register.yml + when: + - not runner_registered.stat.exists + - not skip_runner_registration | default(false) + + - name: Start gitea-runner systemd instance + ansible.builtin.systemd: + name: "gitea-runner@{{ runner_name }}" + state: started + daemon_reload: true + when: systemd_available.stat.exists diff --git a/ansible/status-runner.yml b/ansible/status-runner.yml new file mode 100644 index 0000000..8ccb666 --- /dev/null +++ b/ansible/status-runner.yml @@ -0,0 +1,44 @@ +--- +- name: Status of Gitea Actions runner + hosts: all + become: true + vars: {} + tasks: + - name: Include systemd availability check + ansible.builtin.include_tasks: roles/gitea-runner/tasks/systemd_check.yml + + - name: Check systemd status + ansible.builtin.systemd: + name: "gitea-runner@{{ runner_name }}" + register: service_status + when: systemd_available.stat.exists + + - name: Report systemd status + ansible.builtin.debug: + msg: > + Service gitea-runner@{{ runner_name }}: + ActiveState={{ service_status.status.ActiveState | default('unknown') }}, + SubState={{ service_status.status.SubState | default('unknown') }}, + LoadState={{ service_status.status.LoadState | default('unknown') }} + when: systemd_available.stat.exists + + - name: Check runner registration file + ansible.builtin.stat: + path: "{{ gitea_runner_data_dir | default('/var/lib/gitea-runner/' ~ runner_name) }}/.runner" + register: runner_file_stat + + - name: Report runner registration + ansible.builtin.debug: + msg: "Runner registration file exists: {{ runner_file_stat.stat.exists | default(false) }}" + + - name: Check container status (Docker mode) + ansible.builtin.shell: | + docker ps --filter "name=gitea-runner-{{ runner_name }}" --format "{{ '{{.Status}}' }}" + register: docker_check + changed_when: false + when: runner_mode | default('docker') == 'docker' + + - name: Report container status + ansible.builtin.debug: + msg: "Container status: {{ docker_check.stdout | default('not running') }}" + when: runner_mode | default('docker') == 'docker' diff --git a/ansible/stop-runner.yml b/ansible/stop-runner.yml new file mode 100644 index 0000000..a30ec06 --- /dev/null +++ b/ansible/stop-runner.yml @@ -0,0 +1,15 @@ +--- +- name: Stop Gitea Actions runner + hosts: all + become: true + vars: {} + tasks: + - name: Include systemd availability check + ansible.builtin.include_tasks: roles/gitea-runner/tasks/systemd_check.yml + + - name: Stop gitea-runner systemd instance + ansible.builtin.systemd: + name: "gitea-runner@{{ runner_name }}" + state: stopped + daemon_reload: true + when: systemd_available.stat.exists