Files
cloud-ip-validator/deploy/ansible/roles/validator_agent/tasks/preflight.yml
T
ayurishchevandClaude Sonnet 5.5 cf4a883363 ansible: fix container name and git user, refuse to start a second agent
The real container on the validators is named validator-agent (the image
is cloud-ip-validator-validator-agent); the playbook used the image name
as the container name, so it would have started a second agent next to
the old one with the same validator_id. The clone on the validators is
owned by root, so git must run as root (git_user), otherwise fetch fails
with "cannot open .git/FETCH_HEAD: Permission denied".

Preflight now stops when the host has another container of this agent
(by name or image) besides container_name.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 10:01:05 +03:00

151 lines
6.2 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
# --- на 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
# Защита от второго агента: если на хосте уже есть другой контейнер этого
# агента (по имени или по образу), сценарий остановится, а не запустит
# рядом ещё один с тем же 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 -}}
# 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 }}