commit 290eb872b787cbb3363cadd5faa59a05407173bf Author: mathieu Date: Sun May 24 17:13:36 2026 +0200 feat: initial installation role for semaphore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a8b42eb --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.retry diff --git a/README.md b/README.md new file mode 100644 index 0000000..47f1bd6 --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +# ansible-role-semaphore + +Installs Ansible Semaphore from GitHub releases as a `.deb` package on +Debian-based distributions. A systemd service is created but left stopped +by default: Semaphore requires a `config.json` before it can start. + +The service user and group must be created beforehand. + +## Requirements + +- Ansible >= 2.14 +- Debian or Ubuntu + +## Role Variables + +| Variable | Default | Description | +|---|---|---| +| `semaphore_version` | `""` | Version to install (empty = latest) | +| `semaphore_user` | `semaphore` | User to run Semaphore | +| `semaphore_group` | `semaphore` | Group to run Semaphore | +| `semaphore_install_dir` | `/usr/local/bin` | Binary location after .deb install | +| `semaphore_config_dir` | `/etc/semaphore` | Directory for `config.json` | +| `semaphore_data_dir` | `/var/lib/semaphore` | Working/project directory | +| `semaphore_service_enabled` | `false` | Enable service at boot | +| `semaphore_service_state` | `stopped` | Service state (needs config first) | + +## Example Playbook + +```yaml +- hosts: automation_servers + roles: + - role: ansible-role-semaphore +``` + +## License + +MIT diff --git a/defaults/main.yml b/defaults/main.yml new file mode 100644 index 0000000..816abeb --- /dev/null +++ b/defaults/main.yml @@ -0,0 +1,9 @@ +--- +semaphore_version: "" +semaphore_user: semaphore +semaphore_group: semaphore +semaphore_install_dir: /usr/local/bin +semaphore_config_dir: /etc/semaphore +semaphore_data_dir: /var/lib/semaphore +semaphore_service_enabled: false +semaphore_service_state: stopped diff --git a/handlers/main.yml b/handlers/main.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/handlers/main.yml @@ -0,0 +1 @@ +--- diff --git a/meta/main.yml b/meta/main.yml new file mode 100644 index 0000000..f590321 --- /dev/null +++ b/meta/main.yml @@ -0,0 +1,15 @@ +--- +galaxy_info: + author: mathieu + description: Install Ansible Semaphore binary on Linux + license: MIT + min_ansible_version: "2.14" + platforms: + - name: Debian + versions: [bullseye, bookworm] + - name: Ubuntu + versions: [focal, jammy, noble] + - name: EL + versions: ["8", "9"] + galaxy_tags: [semaphore, ansible, automation] +dependencies: [] diff --git a/tasks/main.yml b/tasks/main.yml new file mode 100644 index 0000000..47a9418 --- /dev/null +++ b/tasks/main.yml @@ -0,0 +1,112 @@ +--- +- name: Assert Debian-based distribution + ansible.builtin.assert: + that: + - ansible_os_family == 'Debian' + fail_msg: "ansible-role-semaphore .deb installation only supports Debian-based distributions" + +- name: Set architecture fact + ansible.builtin.set_fact: + _semaphore_arch: "{{ {'x86_64': 'amd64', 'aarch64': 'arm64', 'armv7l': 'arm'}.get(ansible_architecture, 'amd64') }}" + +- name: Get Semaphore release info from GitHub + ansible.builtin.uri: + url: >- + {{ 'https://api.github.com/repos/semaphoreui/semaphore/releases/latest' + if semaphore_version == '' + else 'https://api.github.com/repos/semaphoreui/semaphore/releases/tags/v' + semaphore_version }} + headers: + Accept: "application/vnd.github.v3+json" + return_content: true + register: _semaphore_release + +- name: Set version and download URL facts + ansible.builtin.set_fact: + _semaphore_version_tag: "{{ _semaphore_release.json.tag_name }}" + _semaphore_deb_url: >- + {{ _semaphore_release.json.assets + | selectattr('name', 'search', 'linux_' + _semaphore_arch + '.deb') + | map(attribute='browser_download_url') + | first }} + +- name: Read installed version + ansible.builtin.command: + cmd: semaphore version + register: _semaphore_installed_raw + changed_when: false + ignore_errors: true + become: true + +- name: Set installed version fact + ansible.builtin.set_fact: + _semaphore_installed_version: >- + {{ ('v' + (_semaphore_installed_raw.stdout | trim)) + if _semaphore_installed_raw is not failed else '' }} + +- name: Install or upgrade Semaphore + when: _semaphore_installed_version != _semaphore_version_tag + block: + - name: Download Semaphore .deb package + ansible.builtin.get_url: + url: "{{ _semaphore_deb_url }}" + dest: /tmp/semaphore.deb + mode: '0644' + + - name: Install Semaphore .deb package + ansible.builtin.apt: + deb: /tmp/semaphore.deb + state: present + become: true + + - name: Remove downloaded .deb package + ansible.builtin.file: + path: /tmp/semaphore.deb + state: absent + +- name: Create Semaphore config directory + ansible.builtin.file: + path: "{{ semaphore_config_dir }}" + state: directory + owner: "{{ semaphore_user }}" + group: "{{ semaphore_group }}" + mode: '0750' + become: true + +- name: Create Semaphore data directory + ansible.builtin.file: + path: "{{ semaphore_data_dir }}" + state: directory + owner: "{{ semaphore_user }}" + group: "{{ semaphore_group }}" + mode: '0750' + become: true + +- name: Create Semaphore systemd service + ansible.builtin.copy: + content: | + [Unit] + Description=Ansible Semaphore + After=network.target + + [Service] + Type=simple + User={{ semaphore_user }} + Group={{ semaphore_group }} + WorkingDirectory={{ semaphore_data_dir }} + ExecStart=/usr/bin/semaphore server --config {{ semaphore_config_dir }}/config.json + Restart=on-failure + RestartSec=10 + + [Install] + WantedBy=multi-user.target + dest: /etc/systemd/system/semaphore.service + mode: '0644' + become: true + +- name: Enable and start Semaphore service + ansible.builtin.systemd: + name: semaphore + enabled: "{{ semaphore_service_enabled }}" + state: "{{ semaphore_service_state }}" + daemon_reload: true + become: true