2026-10-02 09:23:39 +03:00
|
|
|
|
---
|
|
|
|
|
|
# --- на jump-хосте (один раз) -------------------------------------------
|
|
|
|
|
|
- name: Check that the env file exists on the jump host
|
|
|
|
|
|
ansible.builtin.stat:
|
|
|
|
|
|
path: "{{ local_env_file }}"
|
|
|
|
|
|
delegate_to: localhost
|
|
|
|
|
|
become: false
|
|
|
|
|
|
run_once: true
|
|
|
|
|
|
check_mode: false
|
|
|
|
|
|
register: env_file_stat
|
|
|
|
|
|
|
|
|
|
|
|
- name: Fail early without an env file
|
|
|
|
|
|
ansible.builtin.assert:
|
|
|
|
|
|
that: env_file_stat.stat.exists
|
|
|
|
|
|
fail_msg: >-
|
|
|
|
|
|
Нет env-файла {{ local_env_file }}. Создайте его:
|
|
|
|
|
|
cp env/validator-agent.env.example env/validator-agent.env и заполните.
|
|
|
|
|
|
quiet: true
|
|
|
|
|
|
run_once: true
|
|
|
|
|
|
|
|
|
|
|
|
# Содержимое файла (в нём токен) не выводится: разбор идёт в задаче с no_log,
|
|
|
|
|
|
# а проверка и её сообщение — по готовым булевым значениям.
|
|
|
|
|
|
- name: Inspect the env file without printing it
|
|
|
|
|
|
ansible.builtin.set_fact:
|
|
|
|
|
|
env_url_set: "{{ env_file_text is regex('(?m)^VALIDATOR_AGENT_CONTROL_API_URL=\\S+') }}"
|
|
|
|
|
|
env_url_is_example: "{{ env_file_text is regex('(?m)^VALIDATOR_AGENT_CONTROL_API_URL=\\S*example\\.com') }}"
|
|
|
|
|
|
vars:
|
|
|
|
|
|
env_file_text: "{{ lookup('ansible.builtin.file', local_env_file) }}"
|
|
|
|
|
|
run_once: true
|
|
|
|
|
|
no_log: true
|
|
|
|
|
|
|
|
|
|
|
|
- name: Check that the env file sets the control-api address
|
|
|
|
|
|
ansible.builtin.assert:
|
|
|
|
|
|
that:
|
|
|
|
|
|
- env_url_set | bool
|
|
|
|
|
|
- not (env_url_is_example | bool)
|
|
|
|
|
|
fail_msg: >-
|
|
|
|
|
|
В {{ local_env_file }} не задан VALIDATOR_AGENT_CONTROL_API_URL
|
|
|
|
|
|
(или остался адрес-пример example.com).
|
|
|
|
|
|
quiet: true
|
|
|
|
|
|
run_once: true
|
|
|
|
|
|
|
|
|
|
|
|
# --- на каждом валидаторе -----------------------------------------------
|
|
|
|
|
|
- name: Check that Docker answers
|
|
|
|
|
|
ansible.builtin.command: docker version --format {% raw %}'{{.Server.Version}}'{% endraw %}
|
|
|
|
|
|
changed_when: false
|
|
|
|
|
|
check_mode: false
|
|
|
|
|
|
|
|
|
|
|
|
- name: Check that git is installed
|
|
|
|
|
|
ansible.builtin.command: git --version
|
|
|
|
|
|
changed_when: false
|
|
|
|
|
|
check_mode: false
|
|
|
|
|
|
|
|
|
|
|
|
- name: Check that the git clone exists
|
|
|
|
|
|
ansible.builtin.stat:
|
|
|
|
|
|
path: "{{ repo_dir }}/.git"
|
|
|
|
|
|
check_mode: false
|
|
|
|
|
|
register: clone_stat
|
|
|
|
|
|
|
|
|
|
|
|
- name: Fail without a clone
|
|
|
|
|
|
ansible.builtin.assert:
|
|
|
|
|
|
that: clone_stat.stat.exists
|
|
|
|
|
|
fail_msg: "Нет git-клона {{ repo_dir }} на {{ inventory_hostname }}."
|
|
|
|
|
|
quiet: true
|
|
|
|
|
|
|
|
|
|
|
|
- name: Read the CPU architecture
|
|
|
|
|
|
ansible.builtin.command: uname -m
|
|
|
|
|
|
changed_when: false
|
|
|
|
|
|
check_mode: false
|
|
|
|
|
|
register: arch
|
|
|
|
|
|
|
|
|
|
|
|
- name: The image is linux/amd64 only
|
|
|
|
|
|
ansible.builtin.assert:
|
|
|
|
|
|
that: arch.stdout in ['x86_64', 'amd64']
|
|
|
|
|
|
fail_msg: "Архитектура {{ arch.stdout }}: образ {{ platform }} здесь не запустится (exec format error)."
|
|
|
|
|
|
quiet: true
|
|
|
|
|
|
|
|
|
|
|
|
- name: Look at the current container
|
|
|
|
|
|
ansible.builtin.command: >-
|
|
|
|
|
|
docker container inspect --format
|
|
|
|
|
|
{% raw %}'{{.Config.Image}} {{.State.Status}}'{% endraw %}
|
|
|
|
|
|
{{ container_name }}
|
|
|
|
|
|
register: current_container
|
|
|
|
|
|
changed_when: false
|
|
|
|
|
|
failed_when: false
|
|
|
|
|
|
check_mode: false
|
|
|
|
|
|
|
2026-10-02 10:01:05 +03:00
|
|
|
|
# Защита от второго агента: если на хосте уже есть другой контейнер этого
|
|
|
|
|
|
# агента (по имени или по образу), сценарий остановится, а не запустит
|
|
|
|
|
|
# рядом ещё один с тем же validator_id.
|
|
|
|
|
|
- name: List containers on the validator
|
|
|
|
|
|
ansible.builtin.command: docker ps -a --format {% raw %}'{{.Names}}|{{.Image}}'{% endraw %}
|
|
|
|
|
|
register: all_containers
|
|
|
|
|
|
changed_when: false
|
|
|
|
|
|
check_mode: false
|
|
|
|
|
|
|
|
|
|
|
|
- name: Check that there is no other agent container
|
|
|
|
|
|
ansible.builtin.assert:
|
|
|
|
|
|
that: (other_agents | from_json) | length == 0
|
|
|
|
|
|
fail_msg: >-
|
|
|
|
|
|
{{ inventory_hostname }}: найден другой контейнер агента: {{ (other_agents | from_json) | join(', ') }}.
|
|
|
|
|
|
Сценарий заменяет только контейнер {{ container_name }}. Проверьте container_name в
|
|
|
|
|
|
inventory/group_vars/validators.yml или удалите лишний контейнер вручную.
|
|
|
|
|
|
quiet: true
|
|
|
|
|
|
vars:
|
|
|
|
|
|
other_agents: >-
|
|
|
|
|
|
{%- set found = [] -%}
|
|
|
|
|
|
{%- for line in all_containers.stdout_lines -%}
|
|
|
|
|
|
{%- set row = line.split('|') -%}
|
|
|
|
|
|
{%- if row[0] != container_name and ('validator-agent' in row[0] or row[1] == image_name or row[1].startswith(image_name ~ ':')) -%}
|
|
|
|
|
|
{%- set _ = found.append(row[0] ~ ' (' ~ row[1] ~ ')') -%}
|
|
|
|
|
|
{%- endif -%}
|
|
|
|
|
|
{%- endfor -%}
|
|
|
|
|
|
{{- found | to_json -}}
|
|
|
|
|
|
|
2026-10-02 09:23:39 +03:00
|
|
|
|
# validator_id работающего контейнера — эталон: если он отличается от
|
|
|
|
|
|
# inventory, заменять контейнер нельзя (агент зарегистрировался бы под чужим
|
|
|
|
|
|
# именем, адреса привязывались бы к порту другой ВМ). Выводится только он,
|
|
|
|
|
|
# а не все переменные окружения (там токен).
|
|
|
|
|
|
- name: Read validator_id of the running container
|
|
|
|
|
|
ansible.builtin.shell: |
|
|
|
|
|
|
set -o pipefail
|
|
|
|
|
|
docker container inspect --format '{% raw %}{{range .Config.Env}}{{println .}}{{end}}{% endraw %}' {{ container_name }} \
|
|
|
|
|
|
| sed -n 's/^VALIDATOR_AGENT_VALIDATOR_ID=//p'
|
|
|
|
|
|
args:
|
|
|
|
|
|
executable: /bin/bash
|
|
|
|
|
|
register: running_validator_id
|
|
|
|
|
|
changed_when: false
|
|
|
|
|
|
failed_when: false
|
|
|
|
|
|
check_mode: false
|
|
|
|
|
|
when: current_container.rc == 0
|
|
|
|
|
|
|
|
|
|
|
|
- name: Check validator_id against the running container
|
|
|
|
|
|
ansible.builtin.assert:
|
|
|
|
|
|
that: >-
|
|
|
|
|
|
current_container.rc != 0
|
|
|
|
|
|
or (running_validator_id.stdout | trim) == ''
|
|
|
|
|
|
or (running_validator_id.stdout | trim) == effective_validator_id
|
|
|
|
|
|
fail_msg: >-
|
|
|
|
|
|
{{ inventory_hostname }}: в запущенном контейнере validator_id={{ running_validator_id.stdout | default('') | trim }},
|
|
|
|
|
|
а в inventory {{ effective_validator_id }}. Проверьте соответствие имени ВМ и validator_id
|
|
|
|
|
|
в inventory/hosts.yml; контейнер не тронут.
|
|
|
|
|
|
quiet: true
|
|
|
|
|
|
|
|
|
|
|
|
- name: Report the current container
|
|
|
|
|
|
ansible.builtin.debug:
|
|
|
|
|
|
msg: >-
|
|
|
|
|
|
{{ container_name }}:
|
|
|
|
|
|
{{ current_container.stdout if current_container.rc == 0 else 'контейнера нет (будет создан)' }};
|
|
|
|
|
|
validator_id для запуска: {{ effective_validator_id }}
|