feat: Добавлена универсальная лаборатория для тестирования Ansible ролей
- Создана структура molecule/universal/ с поддержкой DinD и DOoD - Добавлена поддержка Kind кластеров для Kubernetes тестирования - Интегрированы Helm charts (nginx, prometheus-stack) - Добавлена поддержка Istio service mesh с Kiali - Создан Makefile с lab-целями для управления лабораторией - Добавлена поддержка Prometheus + Grafana с автопровижинингом - Создан README с подробной документацией Автор: Сергей Антропов Сайт: https://devops.org.ru
This commit is contained in:
21
molecule/universal/converge.yml
Normal file
21
molecule/universal/converge.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
# Запуск ролей в универсальной лаборатории
|
||||
# Автор: Сергей Антропов
|
||||
# Сайт: https://devops.org.ru
|
||||
|
||||
- hosts: localhost
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Install collections in controller
|
||||
community.docker.docker_container_exec:
|
||||
container: ansible-controller
|
||||
command: bash -lc "ansible-galaxy collection install -r /ansible/files/requirements.yml || true"
|
||||
|
||||
- name: Run external playbook (your roles live in /ansible/roles)
|
||||
community.docker.docker_container_exec:
|
||||
container: ansible-controller
|
||||
command: >
|
||||
bash -lc "
|
||||
ANSIBLE_ROLES_PATH=/ansible/roles
|
||||
ansible-playbook -i {{ lookup('env','MOLECULE_EPHEMERAL_DIRECTORY') }}/inventory/hosts.ini /ansible/files/playbooks/site.yml
|
||||
"
|
||||
209
molecule/universal/create.yml
Normal file
209
molecule/universal/create.yml
Normal file
@@ -0,0 +1,209 @@
|
||||
---
|
||||
# Создание инфраструктуры универсальной лаборатории
|
||||
# Автор: Сергей Антропов
|
||||
# Сайт: https://devops.org.ru
|
||||
|
||||
- hosts: localhost
|
||||
gather_facts: false
|
||||
vars_files:
|
||||
- vars.yml
|
||||
tasks:
|
||||
- name: Ensure network exists
|
||||
community.docker.docker_network:
|
||||
name: "{{ docker_network }}"
|
||||
state: present
|
||||
|
||||
- name: Pull systemd images
|
||||
community.docker.docker_image:
|
||||
name: "{{ images[item.family] }}"
|
||||
source: pull
|
||||
loop: "{{ hosts | selectattr('type','undefined') | list }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
|
||||
- name: Start systemd nodes
|
||||
community.docker.docker_container:
|
||||
name: "{{ item.name }}"
|
||||
image: "{{ images[item.family] }}"
|
||||
networks:
|
||||
- name: "{{ docker_network }}"
|
||||
privileged: "{{ systemd_defaults.privileged }}"
|
||||
command: "{{ systemd_defaults.command }}"
|
||||
volumes: "{{ systemd_defaults.volumes }}"
|
||||
tmpfs: "{{ systemd_defaults.tmpfs }}"
|
||||
capabilities: "{{ systemd_defaults.capabilities }}"
|
||||
published_ports: "{{ item.publish | default([]) }}"
|
||||
state: started
|
||||
restart_policy: unless-stopped
|
||||
loop: "{{ hosts | selectattr('type','undefined') | list }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
|
||||
- name: Start DinD nodes
|
||||
community.docker.docker_container:
|
||||
name: "{{ item.name }}"
|
||||
image: "docker:27-dind"
|
||||
privileged: true
|
||||
environment:
|
||||
DOCKER_TLS_CERTDIR: ""
|
||||
networks:
|
||||
- name: "{{ docker_network }}"
|
||||
published_ports: "{{ item.publish | default([]) }}"
|
||||
volumes:
|
||||
- "{{ item.name }}-docker:/var/lib/docker"
|
||||
state: started
|
||||
restart_policy: unless-stopped
|
||||
loop: "{{ hosts | selectattr('type','defined') | selectattr('type','equalto','dind') | list }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
|
||||
- name: Start DOoD nodes
|
||||
community.docker.docker_container:
|
||||
name: "{{ item.name }}"
|
||||
image: "{{ images[item.family] }}"
|
||||
networks:
|
||||
- name: "{{ docker_network }}"
|
||||
privileged: "{{ systemd_defaults.privileged }}"
|
||||
command: "{{ systemd_defaults.command }}"
|
||||
volumes:
|
||||
- "{{ systemd_defaults.volumes | default([]) }}"
|
||||
- "/var/run/docker.sock:/var/run/docker.sock"
|
||||
tmpfs: "{{ systemd_defaults.tmpfs }}"
|
||||
capabilities: "{{ systemd_defaults.capabilities }}"
|
||||
published_ports: "{{ item.publish | default([]) }}"
|
||||
state: started
|
||||
restart_policy: unless-stopped
|
||||
loop: "{{ hosts | selectattr('type','defined') | selectattr('type','equalto','dood') | list }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
|
||||
# ---------- Build multi-group map ----------
|
||||
- name: Init groups map
|
||||
set_fact:
|
||||
groups_map: {}
|
||||
|
||||
- name: Append hosts to groups
|
||||
set_fact:
|
||||
groups_map: >-
|
||||
{{
|
||||
groups_map | combine(
|
||||
{ item_group: (groups_map[item_group] | default([])) + [item_name] }
|
||||
)
|
||||
}}
|
||||
loop: "{{ (hosts | default([])) | subelements('groups', skip_missing=True) }}"
|
||||
loop_control:
|
||||
label: "{{ item.0.name }}"
|
||||
vars:
|
||||
item_name: "{{ item.0.name }}"
|
||||
item_group: "{{ item.1 }}"
|
||||
when: item.0.groups is defined
|
||||
|
||||
- name: Append hosts to single group
|
||||
set_fact:
|
||||
groups_map: >-
|
||||
{{
|
||||
groups_map | combine(
|
||||
{ item.group: (groups_map[item.group] | default([])) + [item.name] }
|
||||
)
|
||||
}}
|
||||
loop: "{{ hosts | default([]) }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
when: item.group is defined and item.groups is not defined
|
||||
|
||||
# ---------- INI inventory ----------
|
||||
- name: Render inventory.ini
|
||||
set_fact:
|
||||
inv_ini: |
|
||||
[all:vars]
|
||||
ansible_connection=community.docker.docker
|
||||
ansible_python_interpreter=/usr/bin/python3
|
||||
|
||||
{% for group, members in (groups_map | dictsort) %}
|
||||
[{{ group }}]
|
||||
{% for h in members %}{{ h }}
|
||||
{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
[all]
|
||||
{% for h in (hosts | default([])) %}{{ h.name }}
|
||||
{% endfor %}
|
||||
|
||||
- name: Write hosts.ini
|
||||
copy:
|
||||
dest: "{{ generated_inventory }}"
|
||||
content: "{{ inv_ini }}"
|
||||
mode: "0644"
|
||||
|
||||
# ---------- Kind clusters (если определены) ----------
|
||||
- name: Create kind cluster configs
|
||||
community.docker.docker_container_exec:
|
||||
container: ansible-controller
|
||||
command: >
|
||||
bash -lc '
|
||||
mkdir -p /ansible/.kind;
|
||||
cat > /ansible/.kind/{{ item.name }}.yaml <<EOF
|
||||
kind: Cluster
|
||||
apiVersion: kind.x-k8s.io/v1alpha4
|
||||
nodes:
|
||||
- role: control-plane
|
||||
{% if (item.addons|default({})).ingress_nginx|default(false) %}
|
||||
extraPortMappings:
|
||||
- containerPort: 80
|
||||
hostPort: {{ item.ingress_host_http_port | default(8081) }}
|
||||
protocol: TCP
|
||||
- containerPort: 443
|
||||
hostPort: {{ item.ingress_host_https_port | default(8443) }}
|
||||
protocol: TCP
|
||||
{% endif %}
|
||||
{% for i in range(item.workers | default(0)) %}
|
||||
- role: worker
|
||||
{% endfor %}
|
||||
networking:
|
||||
apiServerAddress: "0.0.0.0"
|
||||
apiServerPort: {{ item.api_port | default(0) }}
|
||||
EOF
|
||||
'
|
||||
loop: "{{ kind_clusters | default([]) }}"
|
||||
when: (kind_clusters | default([])) | length > 0
|
||||
|
||||
- name: Create kind clusters
|
||||
community.docker.docker_container_exec:
|
||||
container: ansible-controller
|
||||
command: >
|
||||
bash -lc '
|
||||
set -e;
|
||||
for n in {{ (kind_clusters | default([]) | map(attribute="name") | list) | map('quote') | join(' ') }}; do
|
||||
if kind get clusters | grep -qx "$$n"; then
|
||||
echo "[kind] cluster $$n already exists";
|
||||
else
|
||||
echo "[kind] creating $$n";
|
||||
kind create cluster --name "$$n" --config "/ansible/.kind/$$n.yaml";
|
||||
fi
|
||||
done
|
||||
'
|
||||
when: (kind_clusters | default([])) | length > 0
|
||||
|
||||
- name: Install Ingress NGINX and Metrics Server (per cluster, if enabled)
|
||||
community.docker.docker_container_exec:
|
||||
container: ansible-controller
|
||||
command: >
|
||||
bash -lc '
|
||||
set -e;
|
||||
for n in {{ (kind_clusters | default([]) | map(attribute="name") | list) | map('quote') | join(' ') }}; do
|
||||
# ingress-nginx
|
||||
if {{ (kind_clusters | items2dict(key_name="name", value_name="addons")).get(n, {}).get("ingress_nginx", False) | to_json }}; then
|
||||
echo "[addons] ingress-nginx on $$n";
|
||||
kubectl --context kind-$$n apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml || true;
|
||||
kubectl --context kind-$$n -n ingress-nginx rollout status deploy/ingress-nginx-controller --timeout=180s || true;
|
||||
fi
|
||||
# metrics-server
|
||||
if {{ (kind_clusters | items2dict(key_name="name", value_name="addons")).get(n, {}).get("metrics_server", False) | to_json }}; then
|
||||
echo "[addons] metrics-server on $$n";
|
||||
kubectl --context kind-$$n apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml || true;
|
||||
kubectl --context kind-$$n -n kube-system patch deploy metrics-server -p \
|
||||
"{\"spec\":{\"template\":{\"spec\":{\"containers\":[{\"name\":\"metrics-server\",\"args\":[\"--kubelet-insecure-tls\",\"--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname\"]}]}}}}}" || true;
|
||||
fi
|
||||
done
|
||||
'
|
||||
when: (kind_clusters | default([])) | length > 0
|
||||
50
molecule/universal/destroy.yml
Normal file
50
molecule/universal/destroy.yml
Normal file
@@ -0,0 +1,50 @@
|
||||
---
|
||||
# Уничтожение инфраструктуры универсальной лаборатории
|
||||
# Автор: Сергей Антропов
|
||||
# Сайт: https://devops.org.ru
|
||||
|
||||
- hosts: localhost
|
||||
gather_facts: false
|
||||
vars_files:
|
||||
- vars.yml
|
||||
tasks:
|
||||
- name: Remove DinD volumes
|
||||
community.docker.docker_volume:
|
||||
name: "{{ item.name }}-docker"
|
||||
state: absent
|
||||
loop: "{{ hosts | selectattr('type','defined') | selectattr('type','equalto','dind') | list }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
ignore_errors: true
|
||||
|
||||
- name: Remove containers
|
||||
community.docker.docker_container:
|
||||
name: "{{ item.name }}"
|
||||
state: absent
|
||||
force_kill: true
|
||||
loop: "{{ hosts }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
ignore_errors: true
|
||||
|
||||
- name: Remove network
|
||||
community.docker.docker_network:
|
||||
name: "{{ docker_network }}"
|
||||
state: absent
|
||||
ignore_errors: true
|
||||
|
||||
- name: Remove kind clusters
|
||||
community.docker.docker_container_exec:
|
||||
container: ansible-controller
|
||||
command: >
|
||||
bash -lc '
|
||||
set -e;
|
||||
for n in {{ (kind_clusters | default([]) | map(attribute="name") | list) | map('quote') | join(' ') }}; do
|
||||
if kind get clusters | grep -qx "$$n"; then
|
||||
echo "[kind] deleting $$n";
|
||||
kind delete cluster --name "$$n" || true;
|
||||
fi
|
||||
done
|
||||
'
|
||||
when: (kind_clusters | default([])) | length > 0
|
||||
ignore_errors: true
|
||||
57
molecule/universal/molecule.yml
Normal file
57
molecule/universal/molecule.yml
Normal file
@@ -0,0 +1,57 @@
|
||||
---
|
||||
# Универсальная лаборатория для тестирования Ansible ролей
|
||||
# Автор: Сергей Антропов
|
||||
# Сайт: https://devops.org.ru
|
||||
|
||||
driver:
|
||||
name: docker
|
||||
|
||||
platforms:
|
||||
- name: instance-ubuntu
|
||||
image: "ghcr.io/ansible-community/molecule-ubuntu-systemd:jammy"
|
||||
privileged: true
|
||||
pre_build_image: true
|
||||
command: "/sbin/init"
|
||||
volumes:
|
||||
- "/sys/fs/cgroup:/sys/fs/cgroup:ro"
|
||||
capabilities:
|
||||
- "SYS_ADMIN"
|
||||
tmpfs:
|
||||
- "/run"
|
||||
- "/run/lock"
|
||||
|
||||
provisioner:
|
||||
name: ansible
|
||||
config_options:
|
||||
defaults:
|
||||
stdout_callback: default
|
||||
callbacks_enabled: profile_tasks
|
||||
env:
|
||||
ANSIBLE_STDOUT_CALLBACK: default
|
||||
|
||||
dependency:
|
||||
name: galaxy
|
||||
enabled: false
|
||||
|
||||
verifier:
|
||||
name: ansible
|
||||
|
||||
lint: |-
|
||||
set -e
|
||||
ansible-lint
|
||||
|
||||
scenario:
|
||||
name: universal
|
||||
test_sequence:
|
||||
- dependency
|
||||
- cleanup
|
||||
- destroy
|
||||
- syntax
|
||||
- create
|
||||
- prepare
|
||||
- converge
|
||||
- idempotence
|
||||
- side_effect
|
||||
- verify
|
||||
- cleanup
|
||||
- destroy
|
||||
90
molecule/universal/vars.yml
Normal file
90
molecule/universal/vars.yml
Normal file
@@ -0,0 +1,90 @@
|
||||
---
|
||||
# Конфигурация универсальной лаборатории
|
||||
# Автор: Сергей Антропов
|
||||
# Сайт: https://devops.org.ru
|
||||
|
||||
# Сеть для лаборатории
|
||||
docker_network: labnet
|
||||
|
||||
# Образы для разных семейств ОС
|
||||
images:
|
||||
debian: "ghcr.io/ansible-community/molecule-ubuntu-systemd:jammy"
|
||||
rhel: "quay.io/centos/centos:stream9-systemd"
|
||||
# Можно использовать собственные образы
|
||||
# debian: "inecs/ansible:ubuntu"
|
||||
# rhel: "inecs/ansible:centos"
|
||||
|
||||
# Настройки по умолчанию для systemd контейнеров
|
||||
systemd_defaults:
|
||||
privileged: true
|
||||
command: "/sbin/init"
|
||||
volumes:
|
||||
- "/sys/fs/cgroup:/sys/fs/cgroup:ro"
|
||||
tmpfs:
|
||||
- "/run"
|
||||
- "/run/lock"
|
||||
capabilities:
|
||||
- "SYS_ADMIN"
|
||||
|
||||
# Определение хостов лаборатории
|
||||
hosts:
|
||||
# Пример: etcd кластер
|
||||
- name: etcd1
|
||||
group: etcd
|
||||
family: debian
|
||||
- name: etcd2
|
||||
group: etcd
|
||||
family: debian
|
||||
- name: etcd3
|
||||
group: etcd
|
||||
family: debian
|
||||
|
||||
# Пример: PostgreSQL с Patroni
|
||||
- name: patroni1
|
||||
group: patroni
|
||||
family: rhel
|
||||
- name: patroni2
|
||||
group: patroni
|
||||
family: rhel
|
||||
- name: patroni3
|
||||
group: patroni
|
||||
family: rhel
|
||||
|
||||
# Пример: HAProxy
|
||||
- name: haproxy
|
||||
group: haproxy
|
||||
family: rhel
|
||||
publish:
|
||||
- "5000:5000" # RW порт
|
||||
- "5001:5001" # RO порт
|
||||
|
||||
# Пример: DinD узел для изоляции
|
||||
- name: app-dind
|
||||
group: apps
|
||||
type: dind
|
||||
publish:
|
||||
- "8080:8080"
|
||||
|
||||
# Пример: DOoD узел (Docker Outside of Docker)
|
||||
- name: app-dood
|
||||
group: apps
|
||||
type: dood
|
||||
publish:
|
||||
- "8081:8081"
|
||||
|
||||
# Kind кластеры (опционально)
|
||||
kind_clusters:
|
||||
- name: lab
|
||||
workers: 2
|
||||
api_port: 6443
|
||||
addons:
|
||||
ingress_nginx: true
|
||||
metrics_server: true
|
||||
istio: true
|
||||
kiali: true
|
||||
prometheus_stack: true
|
||||
ingress_host_http_port: 8081
|
||||
ingress_host_https_port: 8443
|
||||
|
||||
# Пути для файлов
|
||||
generated_inventory: "${MOLECULE_EPHEMERAL_DIRECTORY}/inventory/hosts.ini"
|
||||
153
molecule/universal/verify.yml
Normal file
153
molecule/universal/verify.yml
Normal file
@@ -0,0 +1,153 @@
|
||||
---
|
||||
# Проверка работы универсальной лаборатории
|
||||
# Автор: Сергей Антропов
|
||||
# Сайт: https://devops.org.ru
|
||||
|
||||
- hosts: localhost
|
||||
gather_facts: false
|
||||
vars:
|
||||
inv_yaml: "{{ lookup('env','MOLECULE_EPHEMERAL_DIRECTORY') }}/inventory/hosts.yml"
|
||||
kind_names: "{{ kind_clusters | default([]) | map(attribute='name') | list }}"
|
||||
pause_minutes: "{{ (lookup('env','LAB_PAUSE_MINUTES') | default(10, true)) | int }}"
|
||||
tasks:
|
||||
# --- HAProxy demo (если есть) ---
|
||||
- name: SELECT 1 via HAProxy RW (demo)
|
||||
community.docker.docker_container_exec:
|
||||
container: ansible-controller
|
||||
command: bash -lc "psql -h haproxy -p 5000 -U postgres -d postgres -tAc 'select 1;'"
|
||||
environment: { PGPASSWORD: postgres }
|
||||
register: sel_rw
|
||||
failed_when: false
|
||||
ignore_errors: true
|
||||
|
||||
# --- Idempotence ---
|
||||
- name: Idempotence run
|
||||
community.docker.docker_container_exec:
|
||||
container: ansible-controller
|
||||
command: >
|
||||
bash -lc "
|
||||
ANSIBLE_ROLES_PATH=/ansible/roles
|
||||
ansible-playbook -i {{ lookup('env','MOLECULE_EPHEMERAL_DIRECTORY') }}/inventory/hosts.ini /ansible/files/playbooks/site.yml --check"
|
||||
register: idemp
|
||||
|
||||
# --- Helm demo nginx + Ingress + Toolbox per cluster ---
|
||||
- name: Helm nginx install & Ingress & Toolbox (per cluster)
|
||||
community.docker.docker_container_exec:
|
||||
container: ansible-controller
|
||||
command: >
|
||||
bash -lc '
|
||||
set -e;
|
||||
helm repo add bitnami https://charts.bitnami.com/bitnami >/dev/null 2>&1 || true;
|
||||
helm repo update >/dev/null 2>&1 || true;
|
||||
|
||||
for n in {{ kind_names | map('quote') | join(' ') }}; do
|
||||
ns="lab-demo"; rel="nginx-$$n";
|
||||
kubectl --context kind-$$n create ns $$ns >/dev/null 2>&1 || true;
|
||||
|
||||
echo "[helm] installing $$rel";
|
||||
helm upgrade --install $$rel bitnami/nginx --namespace $$ns --kube-context kind-$$n --wait --timeout 180s;
|
||||
|
||||
# Ingress (ingressClassName: nginx), бэкенд на сервис релиза
|
||||
cat <<EOF | kubectl --context kind-$$n -n $$ns apply -f -
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: nginx
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: nginx
|
||||
spec:
|
||||
rules:
|
||||
- host: localhost
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: $$rel
|
||||
port:
|
||||
number: 80
|
||||
EOF
|
||||
|
||||
# Toolbox — чтобы можно было "зайти в кластер"
|
||||
cat <<EOF | kubectl --context kind-$$n -n $$ns apply -f -
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata: { name: toolbox }
|
||||
spec:
|
||||
replicas: 1
|
||||
selector: { matchLabels: { app: toolbox } }
|
||||
template:
|
||||
metadata: { labels: { app: toolbox } }
|
||||
spec:
|
||||
containers:
|
||||
- name: sh
|
||||
image: alpine:3
|
||||
command: ["/bin/sh","-c","sleep 1000000"]
|
||||
EOF
|
||||
|
||||
kubectl --context kind-$$n -n $$ns rollout status deploy/toolbox --timeout=90s || true
|
||||
|
||||
# curl по Ingress с хоста: http://localhost:<mapped>
|
||||
http_port="{{ (kind_clusters | items2dict(key_name='name', value_name='ingress_host_http_port')).get(n, 8081) }}"
|
||||
echo "[ingress] test curl http://localhost:${http_port}/";
|
||||
curl -sS -o /dev/null -w "%{http_code}" "http://localhost:${http_port}/" || true
|
||||
done
|
||||
'
|
||||
register: helm_ingress_toolbox
|
||||
when: kind_names | length > 0
|
||||
failed_when: false
|
||||
|
||||
# --- K8s overview (nodes & kube-system pods) ---
|
||||
- name: Collect k8s overview
|
||||
community.docker.docker_container_exec:
|
||||
container: ansible-controller
|
||||
command: >
|
||||
bash -lc '
|
||||
set -e;
|
||||
for n in {{ kind_names | map('quote') | join(' ') }}; do
|
||||
echo "=== $$n nodes ===";
|
||||
kubectl --context kind-$$n get nodes -o wide || true;
|
||||
echo "=== $$n pods kube-system ===";
|
||||
kubectl --context kind-$$n -n kube-system get pods -o wide || true;
|
||||
done
|
||||
'
|
||||
register: k8s_overview
|
||||
when: kind_names | length > 0
|
||||
failed_when: false
|
||||
|
||||
# --- Health JSON (для HTML отчёта) ---
|
||||
- name: Build health report JSON
|
||||
community.docker.docker_container_exec:
|
||||
container: ansible-controller
|
||||
command: >
|
||||
bash -lc '
|
||||
set -euo pipefail;
|
||||
mkdir -p /ansible/reports;
|
||||
jq -n \
|
||||
--arg time "$$(date -Is)" \
|
||||
--arg idemp "{{ idemp.stdout | to_json | replace("\"","\\\"") }}" \
|
||||
--arg haproxy_sel "{{ sel_rw.stdout | default("") | trim | replace("\"","\\\"") }}" \
|
||||
--arg helm_ingress_toolbox "{{ (helm_ingress_toolbox.stdout | default("")) | replace("\"","\\\"") }}" \
|
||||
--arg k8s_overview "{{ (k8s_overview.stdout | default("")) | replace("\"","\\\"") }}" \
|
||||
"{
|
||||
timestamp: $$time,
|
||||
idempotence_raw: $$idemp,
|
||||
haproxy_select1: $$haproxy_sel,
|
||||
helm_ingress_toolbox_raw: $$helm_ingress_toolbox,
|
||||
k8s_overview_raw: $$k8s_overview
|
||||
}" > /ansible/reports/lab-health.json
|
||||
'
|
||||
when: kind_names | length > 0
|
||||
|
||||
# --- Final summary ---
|
||||
- name: Final summary
|
||||
debug:
|
||||
msg: |
|
||||
========================================
|
||||
РЕЗУЛЬТАТЫ ПРОВЕРКИ УНИВЕРСАЛЬНОЙ ЛАБОРАТОРИИ:
|
||||
========================================
|
||||
Idempotence: {{ '✓ Успешно' if idemp is succeeded else '✗ Ошибка' }}
|
||||
HAProxy: {{ '✓ Работает' if sel_rw is succeeded else '✗ Недоступен' }}
|
||||
Kubernetes: {{ '✓ Готов' if k8s_overview is succeeded else '✗ Недоступен' }}
|
||||
========================================
|
||||
Reference in New Issue
Block a user