Инициализация канона общих ролей с ролью eget
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
# eget
|
||||
|
||||
Устанавливает утилиту [eget](https://github.com/zyedidia/eget) и через неё —
|
||||
пиновые бинарники релизов с GitHub (restic, rclone, btop, zellij и т.п.).
|
||||
|
||||
Роль общая для всех серверных репозиториев; канон живёт в `ansible-roles`,
|
||||
копии вендорятся через `inv roles-pull`.
|
||||
|
||||
## Что делает
|
||||
|
||||
1. **Bootstrap eget.** Если нужной версии `eget` нет — качает архив релиза с
|
||||
GitHub напрямую (сам себя eget обновить не может — chicken-and-egg),
|
||||
распаковывает во временную директорию, ставит бинарник и убирает мусор.
|
||||
Идемпотентно: сверяет `eget --version` с `eget_version`.
|
||||
2. **Установка пакетов.** Идёт по декларативному списку `eget_packages` и для
|
||||
каждого вызывает `eget <repo> --tag <tag> --upgrade-only …`.
|
||||
|
||||
## Идемпотентность и статус изменений
|
||||
|
||||
`--upgrade-only` заставляет eget скачивать бинарник, только если релиз новее
|
||||
установленного файла (сравнение по mtime). Когда обновление не нужно, eget
|
||||
пишет в stderr `… requested release is not more recent than current version`
|
||||
и выходит с кодом 0.
|
||||
|
||||
Роль **не** глушит вывод (`--quiet` убран намеренно) и по наличию этой
|
||||
подстроки (`eget_no_upgrade_marker`) выставляет `changed_when`: реальная
|
||||
установка → `changed`, пропуск → `ok`. Ненулевой код выхода eget (реальная
|
||||
ошибка) роняет таск штатно.
|
||||
|
||||
> Ограничения `--upgrade-only` (сравнение по дате релиза vs mtime бинарника, а
|
||||
> не по версии — поэтому это **не** строгий пиннинг тега):
|
||||
>
|
||||
> - Бамп тега на релиз, опубликованный раньше текущей установки, и любой
|
||||
> **даунгрейд** eget сочтёт «не новее» и не поставит (роль покажет `ok`).
|
||||
> На практике теги двигают только вперёд на свежие релизы; откат версии —
|
||||
> вручную (удалить бинарник, затем прогнать роль).
|
||||
> - Если имя бинарника не совпадает с последним сегментом `repo` (напр.
|
||||
> `BurntSushi/ripgrep` → `rg`), eget не находит установленный файл, и роль
|
||||
> будет **переустанавливать пакет каждый прогон** (рапортуя `changed`). Все
|
||||
> текущие пакеты этим не задеты; для таких репозиториев ставь бинарник в
|
||||
> отдельную директорию либо не полагайся на статус `changed`.
|
||||
|
||||
## Переменные
|
||||
|
||||
Полный список и значения по умолчанию — в `defaults/main.yml`.
|
||||
|
||||
| Переменная | По умолчанию | Назначение |
|
||||
|------------|--------------|------------|
|
||||
| `eget_version` | `1.3.4` | Версия самой утилиты eget. |
|
||||
| `eget_install_path` | `/usr/bin/eget` | Куда ставить бинарник eget. |
|
||||
| `eget_download_url` | ссылка на релиз | URL архива eget (собирается из версии). |
|
||||
| `eget_download_checksum` | `""` | Необязательная проверка архива eget (формат `get_url.checksum`). |
|
||||
| `eget_packages_to` | `/usr/local/bin` | Директория для бинарников пакетов по умолчанию. |
|
||||
| `eget_packages` | `[]` | Декларативный список пакетов (см. ниже). |
|
||||
|
||||
### Схема элемента `eget_packages`
|
||||
|
||||
| Ключ | Обяз. | Назначение |
|
||||
|------|:----:|------------|
|
||||
| `repo` | да | `owner/repo` на GitHub, напр. `restic/restic`. |
|
||||
| `tag` | да | Пиновка версии, напр. `v0.18.1`. |
|
||||
| `to` | нет | Целевая директория; по умолчанию `eget_packages_to`. |
|
||||
| `asset` | нет | Один фильтр ассета, напр. `zip` или `^musl` (`^` — анти-матч). |
|
||||
| `assets` | нет | Список фильтров (каждый → свой `--asset`); приоритетнее `asset`. |
|
||||
| `file` | нет | `--file` glob для выбора файла из архива. |
|
||||
|
||||
## Пример
|
||||
|
||||
```yaml
|
||||
- name: "Install eget and pinned binaries"
|
||||
hosts: all
|
||||
tasks:
|
||||
- name: "Install eget and tools"
|
||||
ansible.builtin.import_role:
|
||||
name: eget
|
||||
vars:
|
||||
eget_install_path: "/usr/local/bin/eget"
|
||||
eget_packages_to: "/usr/local/bin"
|
||||
eget_packages:
|
||||
- {repo: "restic/restic", tag: "v0.18.1"}
|
||||
- {repo: "rclone/rclone", tag: "v1.73.4", asset: "zip"}
|
||||
- {repo: "bootandy/dust", tag: "v1.2.4", asset: "gnu"}
|
||||
- {repo: "creativeprojects/resticprofile", tag: "v0.32.0", asset: "^no_self_update"}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
# defaults file for eget
|
||||
|
||||
# --- Сам eget ---
|
||||
# Версия утилиты eget и путь установки её бинарника.
|
||||
eget_version: "1.3.4"
|
||||
eget_install_path: "/usr/bin/eget"
|
||||
eget_download_url: "https://github.com/zyedidia/eget/releases/download/v{{ eget_version }}/eget-{{ eget_version }}-linux_amd64.tar.gz" # yamllint disable-line rule:line-length
|
||||
|
||||
# Необязательная проверка целостности архива eget при bootstrap.
|
||||
# Формат — как у аргумента checksum модуля get_url
|
||||
# (напр. "sha256:<hex>"). Пусто — проверка пропускается.
|
||||
eget_download_checksum: ""
|
||||
|
||||
# --- Пакеты, устанавливаемые через eget ---
|
||||
# Директория по умолчанию для бинарников пакетов
|
||||
# (переопределяется в eget_packages[*].to).
|
||||
eget_packages_to: "/usr/local/bin"
|
||||
|
||||
# Декларативный список пакетов. Каждый элемент — объект:
|
||||
# repo (обязательно) — "owner/repo" на GitHub, напр. "restic/restic".
|
||||
# tag (обязательно) — пиновка версии, напр. "v0.18.1".
|
||||
# to (опц.) — целевая директория; по умолчанию eget_packages_to.
|
||||
# asset (опц.) — один фильтр ассета, напр. "zip" или "^musl" (^ = анти-матч).
|
||||
# assets (опц.) — список фильтров (каждый добавляет свой --asset); имеет
|
||||
# приоритет над asset, если заданы оба.
|
||||
# file (опц.) — --file glob для выбора файла из архива.
|
||||
# Пример:
|
||||
# eget_packages:
|
||||
# - {repo: "restic/restic", tag: "v0.18.1"}
|
||||
# - {repo: "bootandy/dust", tag: "v1.2.4", asset: "gnu"}
|
||||
eget_packages: []
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
galaxy_info:
|
||||
role_name: eget
|
||||
author: "Anton Vakhrushev"
|
||||
description: "Установка утилиты eget и загрузка через неё пиновых бинарников с GitHub"
|
||||
license: "MIT"
|
||||
min_ansible_version: "2.14"
|
||||
platforms:
|
||||
- name: Ubuntu
|
||||
versions:
|
||||
- all
|
||||
- name: Debian
|
||||
versions:
|
||||
- all
|
||||
galaxy_tags:
|
||||
- eget
|
||||
- binaries
|
||||
- github
|
||||
- cli
|
||||
|
||||
dependencies: []
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
# Bootstrap самого eget: скачать релиз с GitHub, распаковать, поставить бинарник.
|
||||
# Идемпотентность — по версии уже установленного eget; чужой eget нельзя обновить
|
||||
# им самим (chicken-and-egg), поэтому качаем архив релиза напрямую.
|
||||
|
||||
- name: "Check installed eget version"
|
||||
ansible.builtin.command:
|
||||
cmd: "{{ eget_install_path }} --version"
|
||||
register: eget_version_check
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
check_mode: false # read-only проба: нужна и в --check, чтобы gate ниже был честным
|
||||
|
||||
- name: "Install eget from GitHub release"
|
||||
when: >-
|
||||
eget_version_check.rc != 0
|
||||
or eget_version not in eget_version_check.stdout
|
||||
block:
|
||||
- name: "Download eget release archive"
|
||||
ansible.builtin.get_url:
|
||||
url: "{{ eget_download_url }}"
|
||||
dest: "{{ eget_download_dest }}"
|
||||
checksum: "{{ eget_download_checksum or omit }}"
|
||||
mode: "0600"
|
||||
|
||||
- name: "Extract eget release archive"
|
||||
ansible.builtin.unarchive:
|
||||
src: "{{ eget_download_dest }}"
|
||||
dest: "/tmp"
|
||||
remote_src: true
|
||||
|
||||
- name: "Install eget binary"
|
||||
ansible.builtin.copy:
|
||||
src: '{{ (eget_unarchive_dest, "eget") | path_join }}'
|
||||
dest: "{{ eget_install_path }}"
|
||||
mode: "0755"
|
||||
remote_src: true
|
||||
|
||||
always:
|
||||
- name: "Remove eget bootstrap artifacts"
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: absent
|
||||
loop:
|
||||
- "{{ eget_download_dest }}"
|
||||
- "{{ eget_unarchive_dest }}"
|
||||
@@ -0,0 +1,40 @@
|
||||
---
|
||||
# tasks file for eget
|
||||
|
||||
- name: "Validate eget_packages entries"
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- item.repo is defined and item.repo is string and item.repo | length > 0
|
||||
- item.tag is defined and item.tag is string and item.tag | length > 0
|
||||
- item.to is not defined or item.to is string
|
||||
- item.file is not defined or item.file is string
|
||||
- item.asset is not defined or item.asset is string
|
||||
- item.assets is not defined or (item.assets is sequence and item.assets is not string)
|
||||
fail_msg: >-
|
||||
Некорректный элемент eget_packages (repo/tag — непустые строки;
|
||||
asset/file/to — строки; assets — список строк): {{ item }}
|
||||
quiet: true
|
||||
loop: "{{ eget_packages }}"
|
||||
loop_control:
|
||||
label: "{{ item.repo | default('?') }}"
|
||||
|
||||
- name: "Ensure eget is installed"
|
||||
ansible.builtin.import_tasks: install_eget.yml
|
||||
|
||||
- name: "Install pinned binaries with eget"
|
||||
ansible.builtin.command:
|
||||
argv: "{{ _eget_argv }}"
|
||||
vars:
|
||||
_eget_to: "{{ item.to | default(eget_packages_to) }}"
|
||||
_eget_assets: >-
|
||||
{{ item.assets | default([item.asset] if item.asset is defined else []) }}
|
||||
_eget_argv: >-
|
||||
{{ [eget_install_path, item.repo, '--upgrade-only',
|
||||
'--to=' ~ _eget_to, '--tag=' ~ item.tag]
|
||||
+ (['--file=' ~ item.file] if item.file is defined else [])
|
||||
+ (['--asset'] | product(_eget_assets) | map('join', '=') | list) }}
|
||||
register: eget_install
|
||||
changed_when: eget_no_upgrade_marker not in eget_install.stderr
|
||||
loop: "{{ eget_packages }}"
|
||||
loop_control:
|
||||
label: "{{ item.repo }} {{ item.tag }}"
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
# vars file for eget — внутренние значения роли, не предназначены для переопределения.
|
||||
|
||||
# Куда скачивается и распаковывается архив eget при bootstrap.
|
||||
eget_download_dest: '/tmp/{{ eget_download_url | split("/") | last }}'
|
||||
eget_unarchive_dest: '{{ eget_download_dest | regex_replace("(\.tar\.gz|\.zip)$", "") }}'
|
||||
|
||||
# Подстрока из текста ошибки ErrNoUpgrade в eget: печатается в stderr, когда
|
||||
# установленный бинарник уже не старше запрошенного релиза (--upgrade-only).
|
||||
# По ней роль отличает «ничего не делали» от реальной установки.
|
||||
# См. find.go: errors.New("requested release is not more recent than current version").
|
||||
eget_no_upgrade_marker: "not more recent than current version"
|
||||
Reference in New Issue
Block a user