When provisioning servers, not all software is available through your distribution’s package manager, and some may be outdated or unavailable for your platform/architecture. Thanks to tools like GoReleaser, many of the modern tools written in Go provide binaries for a variety of platforms and architectures. So if a package is not available, I usually pull the release directly from GitHub.
But hard-coding versions and keeping them up to date can be tedious, and sometimes you’d rather “fail forward” than accidentally stay on an outdated and potentially vulnerable version. In these cases, you can query the GitHub API at /repos/{owner}/{repo}/releases/latest
to retrieve the tag_name
of the latest release (removing the “v” prefix to normalize the result).
This code snippet also allows you to pin a release explicitly by specifying – in this example prometheus_version
– in your playbook (e.g. prometheus_version: 2.32.0
) to skip automatic version detection:
- block:
- name: Determine latest GitHub release (local)
delegate_to: localhost
become: false
uri:
url: "https://api.github.com/repos/prometheus/prometheus/releases/latest"
body_format: json
register: _github_release
until: _github_release.status == 200
retries: 5
- name: Set prometheus_version
set_fact:
prometheus_version: "{{ _github_release.json.tag_name
| regex_replace('^v?(.*)$', '\\1') }}"
when: (prometheus_version is not defined) or (prometheus_version == 'latest')
run_once: true
Then download the release matching the version you want. It is always a good practice to check the SHA256 hash of the file (if provided by the repository) to ensure that the downloaded archive has not been tampered with.
- name: Download and verify SHA256 checksum
delegate_to: localhost
become: false
get_url:
url: "https://github.com/prometheus/prometheus/releases/download/v{{ prometheus_version }}
/prometheus-{{ prometheus_version }}.{{ ansible_system | lower }}-amd64.tar.gz"
dest: "/your/download/path/and/filename.tar.gz"
checksum: "sha256:https://github.com/prometheus/prometheus/releases/download
/v{{ prometheus_version }}/sha256sums.txt"
The above method is ideal for repositories whose releases always have an increasing version number. However, some projects maintain multiple versions in parallel (e.g. LTS releases) or also release critical security fixes for older versions. In this case, the “latest” release does not necessarily mean the “highest version number”.
For these repositories, we can instead retrieve a list of releases (by default, the last 30), filtering out pre-releases/drafts and using a version-specific sorting method to determine the highest version number. (It is important not to use regular alphanumeric sorting in this case, as e.g. v1.2
would be considered higher than v1.12
- we don’t want that!)
- block:
- name: Determine latest GitHub release (local)
delegate_to: localhost
become: false
uri:
url: "https://api.github.com/repos/hashicorp/consul/releases"
body_format: json
register: _github_releases
until: _github_releases.status == 200
retries: 5
- name: Set consul_version
set_fact:
consul_version: "{{ _github_releases.json
| json_query('[?prerelease==`false` && draft==`false`].tag_name')
| community.general.version_sort
| last | regex_replace('^v?(.*)$', '\\1') }}"
when: (consul_version is not defined) or (consul_version == 'latest')
run_once: true
The version_sort
filter is part of the community.general
collection that comes pre-installed with the default Ansible installation. If you use the ansible-core
package instead, you need to install it separately with ansible-galaxy collection install community.general
.