mempool working
This commit is contained in:
parent
8863f800bf
commit
d82c9afbe5
4 changed files with 788 additions and 10 deletions
751
ansible/services/mempool/deploy_mempool_playbook.yml
Normal file
751
ansible/services/mempool/deploy_mempool_playbook.yml
Normal file
|
|
@ -0,0 +1,751 @@
|
||||||
|
- name: Deploy Mempool Block Explorer with Docker
|
||||||
|
hosts: mempool_box_local
|
||||||
|
become: yes
|
||||||
|
vars_files:
|
||||||
|
- ../../infra_vars.yml
|
||||||
|
- ../../services_config.yml
|
||||||
|
- ../../infra_secrets.yml
|
||||||
|
- ./mempool_vars.yml
|
||||||
|
vars:
|
||||||
|
mempool_subdomain: "{{ subdomains.mempool }}"
|
||||||
|
mempool_domain: "{{ mempool_subdomain }}.{{ root_domain }}"
|
||||||
|
uptime_kuma_api_url: "https://{{ subdomains.uptime_kuma }}.{{ root_domain }}"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
# ===========================================
|
||||||
|
# Docker Installation (from 910_docker_playbook.yml)
|
||||||
|
# ===========================================
|
||||||
|
- name: Remove old Docker-related packages
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- docker.io
|
||||||
|
- docker-doc
|
||||||
|
- docker-compose
|
||||||
|
- podman-docker
|
||||||
|
- containerd
|
||||||
|
- runc
|
||||||
|
state: absent
|
||||||
|
purge: yes
|
||||||
|
autoremove: yes
|
||||||
|
|
||||||
|
- name: Update apt cache
|
||||||
|
apt:
|
||||||
|
update_cache: yes
|
||||||
|
|
||||||
|
- name: Install prerequisites
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- ca-certificates
|
||||||
|
- curl
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create directory for Docker GPG key
|
||||||
|
file:
|
||||||
|
path: /etc/apt/keyrings
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Download Docker GPG key
|
||||||
|
get_url:
|
||||||
|
url: https://download.docker.com/linux/debian/gpg
|
||||||
|
dest: /etc/apt/keyrings/docker.asc
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Get Debian architecture
|
||||||
|
command: dpkg --print-architecture
|
||||||
|
register: deb_arch
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Add Docker repository
|
||||||
|
apt_repository:
|
||||||
|
repo: "deb [arch={{ deb_arch.stdout }} signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian {{ ansible_distribution_release }} stable"
|
||||||
|
filename: docker
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
|
||||||
|
- name: Install Docker packages
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- docker-ce
|
||||||
|
- docker-ce-cli
|
||||||
|
- containerd.io
|
||||||
|
- docker-buildx-plugin
|
||||||
|
- docker-compose-plugin
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
|
||||||
|
- name: Ensure Docker is started and enabled
|
||||||
|
systemd:
|
||||||
|
name: docker
|
||||||
|
enabled: yes
|
||||||
|
state: started
|
||||||
|
|
||||||
|
- name: Add user to docker group
|
||||||
|
user:
|
||||||
|
name: "{{ ansible_user }}"
|
||||||
|
groups: docker
|
||||||
|
append: yes
|
||||||
|
|
||||||
|
# ===========================================
|
||||||
|
# Mempool Deployment
|
||||||
|
# ===========================================
|
||||||
|
- name: Create mempool directories
|
||||||
|
file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
owner: "{{ ansible_user }}"
|
||||||
|
group: "{{ ansible_user }}"
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- "{{ mempool_dir }}"
|
||||||
|
- "{{ mempool_data_dir }}"
|
||||||
|
- "{{ mempool_mysql_dir }}"
|
||||||
|
|
||||||
|
- name: Create docker-compose.yml for Mempool
|
||||||
|
copy:
|
||||||
|
dest: "{{ mempool_dir }}/docker-compose.yml"
|
||||||
|
content: |
|
||||||
|
# All containers use host network for Tailscale MagicDNS resolution
|
||||||
|
services:
|
||||||
|
mariadb:
|
||||||
|
image: mariadb:10.11
|
||||||
|
container_name: mempool-db
|
||||||
|
restart: unless-stopped
|
||||||
|
network_mode: host
|
||||||
|
environment:
|
||||||
|
MYSQL_DATABASE: "{{ mariadb_database }}"
|
||||||
|
MYSQL_USER: "{{ mariadb_user }}"
|
||||||
|
MYSQL_PASSWORD: "{{ mariadb_mempool_password }}"
|
||||||
|
MYSQL_ROOT_PASSWORD: "{{ mariadb_mempool_password }}"
|
||||||
|
volumes:
|
||||||
|
- {{ mempool_mysql_dir }}:/var/lib/mysql
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 30s
|
||||||
|
|
||||||
|
mempool-backend:
|
||||||
|
image: mempool/backend:{{ mempool_version }}
|
||||||
|
container_name: mempool-backend
|
||||||
|
restart: unless-stopped
|
||||||
|
network_mode: host
|
||||||
|
environment:
|
||||||
|
# Database (localhost since all containers share host network)
|
||||||
|
DATABASE_ENABLED: "true"
|
||||||
|
DATABASE_HOST: "127.0.0.1"
|
||||||
|
DATABASE_DATABASE: "{{ mariadb_database }}"
|
||||||
|
DATABASE_USERNAME: "{{ mariadb_user }}"
|
||||||
|
DATABASE_PASSWORD: "{{ mariadb_mempool_password }}"
|
||||||
|
# Bitcoin Core/Knots (via Tailnet MagicDNS)
|
||||||
|
CORE_RPC_HOST: "{{ bitcoin_host }}"
|
||||||
|
CORE_RPC_PORT: "{{ bitcoin_rpc_port }}"
|
||||||
|
CORE_RPC_USERNAME: "{{ bitcoin_rpc_user }}"
|
||||||
|
CORE_RPC_PASSWORD: "{{ bitcoin_rpc_password }}"
|
||||||
|
# Electrum (Fulcrum via Tailnet MagicDNS)
|
||||||
|
ELECTRUM_HOST: "{{ fulcrum_host }}"
|
||||||
|
ELECTRUM_PORT: "{{ fulcrum_port }}"
|
||||||
|
ELECTRUM_TLS_ENABLED: "{{ fulcrum_tls }}"
|
||||||
|
# Mempool settings
|
||||||
|
MEMPOOL_NETWORK: "{{ mempool_network }}"
|
||||||
|
MEMPOOL_BACKEND: "electrum"
|
||||||
|
MEMPOOL_CLEAR_PROTECTION_MINUTES: "20"
|
||||||
|
MEMPOOL_INDEXING_BLOCKS_AMOUNT: "52560"
|
||||||
|
volumes:
|
||||||
|
- {{ mempool_data_dir }}:/backend/cache
|
||||||
|
depends_on:
|
||||||
|
mariadb:
|
||||||
|
condition: service_healthy
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:8999/api/v1/backend-info"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 60s
|
||||||
|
|
||||||
|
mempool-frontend:
|
||||||
|
image: mempool/frontend:{{ mempool_version }}
|
||||||
|
container_name: mempool-frontend
|
||||||
|
restart: unless-stopped
|
||||||
|
network_mode: host
|
||||||
|
environment:
|
||||||
|
FRONTEND_HTTP_PORT: "{{ mempool_frontend_port }}"
|
||||||
|
BACKEND_MAINNET_HTTP_HOST: "127.0.0.1"
|
||||||
|
depends_on:
|
||||||
|
- mempool-backend
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:{{ mempool_frontend_port }}"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 30s
|
||||||
|
owner: "{{ ansible_user }}"
|
||||||
|
group: "{{ ansible_user }}"
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Pull Mempool images
|
||||||
|
command: docker compose pull
|
||||||
|
args:
|
||||||
|
chdir: "{{ mempool_dir }}"
|
||||||
|
|
||||||
|
- name: Deploy Mempool containers with docker compose
|
||||||
|
command: docker compose up -d
|
||||||
|
args:
|
||||||
|
chdir: "{{ mempool_dir }}"
|
||||||
|
|
||||||
|
- name: Wait for MariaDB to be healthy
|
||||||
|
command: docker inspect --format='{{ '{{' }}.State.Health.Status{{ '}}' }}' mempool-db
|
||||||
|
register: mariadb_health
|
||||||
|
until: mariadb_health.stdout == 'healthy'
|
||||||
|
retries: 30
|
||||||
|
delay: 10
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Wait for Mempool backend to start
|
||||||
|
uri:
|
||||||
|
url: "http://localhost:{{ mempool_backend_port }}/api/v1/backend-info"
|
||||||
|
method: GET
|
||||||
|
status_code: 200
|
||||||
|
timeout: 10
|
||||||
|
register: backend_check
|
||||||
|
until: backend_check.status == 200
|
||||||
|
retries: 30
|
||||||
|
delay: 10
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Wait for Mempool frontend to be available
|
||||||
|
uri:
|
||||||
|
url: "http://localhost:{{ mempool_frontend_port }}"
|
||||||
|
method: GET
|
||||||
|
status_code: 200
|
||||||
|
timeout: 10
|
||||||
|
register: frontend_check
|
||||||
|
until: frontend_check.status == 200
|
||||||
|
retries: 20
|
||||||
|
delay: 5
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Display deployment status
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Mempool deployment complete!"
|
||||||
|
- "Frontend: http://localhost:{{ mempool_frontend_port }}"
|
||||||
|
- "Backend API: http://localhost:{{ mempool_backend_port }}/api/v1/backend-info"
|
||||||
|
- "Backend check: {{ 'OK' if backend_check.status == 200 else 'Still initializing...' }}"
|
||||||
|
- "Frontend check: {{ 'OK' if frontend_check.status == 200 else 'Still initializing...' }}"
|
||||||
|
|
||||||
|
# ===========================================
|
||||||
|
# Health Check Scripts for Uptime Kuma Push Monitors
|
||||||
|
# ===========================================
|
||||||
|
- name: Create Mempool MariaDB health check script
|
||||||
|
copy:
|
||||||
|
dest: /usr/local/bin/mempool-mariadb-healthcheck-push.sh
|
||||||
|
content: |
|
||||||
|
#!/bin/bash
|
||||||
|
UPTIME_KUMA_PUSH_URL="${UPTIME_KUMA_PUSH_URL}"
|
||||||
|
|
||||||
|
check_container() {
|
||||||
|
local status=$(docker inspect --format='{{ '{{' }}.State.Health.Status{{ '}}' }}' mempool-db 2>/dev/null)
|
||||||
|
[ "$status" = "healthy" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
push_to_uptime_kuma() {
|
||||||
|
local status=$1
|
||||||
|
local msg=$2
|
||||||
|
if [ -z "$UPTIME_KUMA_PUSH_URL" ]; then
|
||||||
|
echo "ERROR: UPTIME_KUMA_PUSH_URL not set"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
curl -s --max-time 10 --retry 2 -o /dev/null \
|
||||||
|
"${UPTIME_KUMA_PUSH_URL}?status=${status}&msg=${msg// /%20}&ping=" || true
|
||||||
|
}
|
||||||
|
|
||||||
|
if check_container; then
|
||||||
|
push_to_uptime_kuma "up" "OK"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
push_to_uptime_kuma "down" "MariaDB container unhealthy"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Create Mempool backend health check script
|
||||||
|
copy:
|
||||||
|
dest: /usr/local/bin/mempool-backend-healthcheck-push.sh
|
||||||
|
content: |
|
||||||
|
#!/bin/bash
|
||||||
|
UPTIME_KUMA_PUSH_URL="${UPTIME_KUMA_PUSH_URL}"
|
||||||
|
BACKEND_PORT={{ mempool_backend_port }}
|
||||||
|
|
||||||
|
check_backend() {
|
||||||
|
curl -sf --max-time 5 "http://localhost:${BACKEND_PORT}/api/v1/backend-info" > /dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
push_to_uptime_kuma() {
|
||||||
|
local status=$1
|
||||||
|
local msg=$2
|
||||||
|
if [ -z "$UPTIME_KUMA_PUSH_URL" ]; then
|
||||||
|
echo "ERROR: UPTIME_KUMA_PUSH_URL not set"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
curl -s --max-time 10 --retry 2 -o /dev/null \
|
||||||
|
"${UPTIME_KUMA_PUSH_URL}?status=${status}&msg=${msg// /%20}&ping=" || true
|
||||||
|
}
|
||||||
|
|
||||||
|
if check_backend; then
|
||||||
|
push_to_uptime_kuma "up" "OK"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
push_to_uptime_kuma "down" "Backend API not responding"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Create Mempool frontend health check script
|
||||||
|
copy:
|
||||||
|
dest: /usr/local/bin/mempool-frontend-healthcheck-push.sh
|
||||||
|
content: |
|
||||||
|
#!/bin/bash
|
||||||
|
UPTIME_KUMA_PUSH_URL="${UPTIME_KUMA_PUSH_URL}"
|
||||||
|
FRONTEND_PORT={{ mempool_frontend_port }}
|
||||||
|
|
||||||
|
check_frontend() {
|
||||||
|
curl -sf --max-time 5 "http://localhost:${FRONTEND_PORT}" > /dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
push_to_uptime_kuma() {
|
||||||
|
local status=$1
|
||||||
|
local msg=$2
|
||||||
|
if [ -z "$UPTIME_KUMA_PUSH_URL" ]; then
|
||||||
|
echo "ERROR: UPTIME_KUMA_PUSH_URL not set"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
curl -s --max-time 10 --retry 2 -o /dev/null \
|
||||||
|
"${UPTIME_KUMA_PUSH_URL}?status=${status}&msg=${msg// /%20}&ping=" || true
|
||||||
|
}
|
||||||
|
|
||||||
|
if check_frontend; then
|
||||||
|
push_to_uptime_kuma "up" "OK"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
push_to_uptime_kuma "down" "Frontend not responding"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
# ===========================================
|
||||||
|
# Systemd Timers for Health Checks
|
||||||
|
# ===========================================
|
||||||
|
- name: Create systemd services for health checks
|
||||||
|
copy:
|
||||||
|
dest: "/etc/systemd/system/mempool-{{ item.name }}-healthcheck.service"
|
||||||
|
content: |
|
||||||
|
[Unit]
|
||||||
|
Description=Mempool {{ item.label }} Health Check
|
||||||
|
After=network.target docker.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
User=root
|
||||||
|
ExecStart=/usr/local/bin/mempool-{{ item.name }}-healthcheck-push.sh
|
||||||
|
Environment=UPTIME_KUMA_PUSH_URL=
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
loop:
|
||||||
|
- { name: "mariadb", label: "MariaDB" }
|
||||||
|
- { name: "backend", label: "Backend" }
|
||||||
|
- { name: "frontend", label: "Frontend" }
|
||||||
|
|
||||||
|
- name: Create systemd timers for health checks
|
||||||
|
copy:
|
||||||
|
dest: "/etc/systemd/system/mempool-{{ item }}-healthcheck.timer"
|
||||||
|
content: |
|
||||||
|
[Unit]
|
||||||
|
Description=Mempool {{ item }} Health Check Timer
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnBootSec=2min
|
||||||
|
OnUnitActiveSec=1min
|
||||||
|
Persistent=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
loop:
|
||||||
|
- mariadb
|
||||||
|
- backend
|
||||||
|
- frontend
|
||||||
|
|
||||||
|
- name: Reload systemd daemon
|
||||||
|
systemd:
|
||||||
|
daemon_reload: yes
|
||||||
|
|
||||||
|
- name: Enable and start health check timers
|
||||||
|
systemd:
|
||||||
|
name: "mempool-{{ item }}-healthcheck.timer"
|
||||||
|
enabled: yes
|
||||||
|
state: started
|
||||||
|
loop:
|
||||||
|
- mariadb
|
||||||
|
- backend
|
||||||
|
- frontend
|
||||||
|
|
||||||
|
# ===========================================
|
||||||
|
# Uptime Kuma Push Monitor Setup
|
||||||
|
# ===========================================
|
||||||
|
- name: Create Uptime Kuma push monitor setup script for Mempool
|
||||||
|
delegate_to: localhost
|
||||||
|
become: no
|
||||||
|
copy:
|
||||||
|
dest: /tmp/setup_mempool_monitors.py
|
||||||
|
content: |
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
import yaml
|
||||||
|
from uptime_kuma_api import UptimeKumaApi, MonitorType
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open('/tmp/ansible_mempool_config.yml', 'r') as f:
|
||||||
|
config = yaml.safe_load(f)
|
||||||
|
|
||||||
|
url = config['uptime_kuma_url']
|
||||||
|
username = config['username']
|
||||||
|
password = config['password']
|
||||||
|
monitors_to_create = config['monitors']
|
||||||
|
|
||||||
|
api = UptimeKumaApi(url, timeout=30)
|
||||||
|
api.login(username, password)
|
||||||
|
|
||||||
|
monitors = api.get_monitors()
|
||||||
|
|
||||||
|
# Find or create "services" group
|
||||||
|
group = next((m for m in monitors if m.get('name') == 'services' and m.get('type') == 'group'), None)
|
||||||
|
if not group:
|
||||||
|
api.add_monitor(type='group', name='services')
|
||||||
|
monitors = api.get_monitors()
|
||||||
|
group = next((m for m in monitors if m.get('name') == 'services' and m.get('type') == 'group'), None)
|
||||||
|
|
||||||
|
# Get ntfy notification ID
|
||||||
|
notifications = api.get_notifications()
|
||||||
|
ntfy_notification_id = None
|
||||||
|
for notif in notifications:
|
||||||
|
if notif.get('type') == 'ntfy':
|
||||||
|
ntfy_notification_id = notif.get('id')
|
||||||
|
break
|
||||||
|
|
||||||
|
results = {}
|
||||||
|
for monitor_name in monitors_to_create:
|
||||||
|
existing = next((m for m in monitors if m.get('name') == monitor_name), None)
|
||||||
|
|
||||||
|
if existing:
|
||||||
|
print(f"Monitor '{monitor_name}' already exists (ID: {existing['id']})")
|
||||||
|
push_token = existing.get('pushToken') or existing.get('push_token')
|
||||||
|
if push_token:
|
||||||
|
results[monitor_name] = f"{url}/api/push/{push_token}"
|
||||||
|
print(f"Push URL ({monitor_name}): {results[monitor_name]}")
|
||||||
|
else:
|
||||||
|
print(f"Creating push monitor '{monitor_name}'...")
|
||||||
|
api.add_monitor(
|
||||||
|
type=MonitorType.PUSH,
|
||||||
|
name=monitor_name,
|
||||||
|
parent=group['id'],
|
||||||
|
interval=60,
|
||||||
|
maxretries=3,
|
||||||
|
retryInterval=60,
|
||||||
|
notificationIDList={ntfy_notification_id: True} if ntfy_notification_id else {}
|
||||||
|
)
|
||||||
|
monitors = api.get_monitors()
|
||||||
|
new_monitor = next((m for m in monitors if m.get('name') == monitor_name), None)
|
||||||
|
if new_monitor:
|
||||||
|
push_token = new_monitor.get('pushToken') or new_monitor.get('push_token')
|
||||||
|
if push_token:
|
||||||
|
results[monitor_name] = f"{url}/api/push/{push_token}"
|
||||||
|
print(f"Push URL ({monitor_name}): {results[monitor_name]}")
|
||||||
|
|
||||||
|
api.disconnect()
|
||||||
|
print("SUCCESS")
|
||||||
|
|
||||||
|
# Write results to file for Ansible to read
|
||||||
|
with open('/tmp/mempool_push_urls.yml', 'w') as f:
|
||||||
|
yaml.dump(results, f)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ERROR: {str(e)}", file=sys.stderr)
|
||||||
|
traceback.print_exc(file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Create temporary config for monitor setup
|
||||||
|
delegate_to: localhost
|
||||||
|
become: no
|
||||||
|
copy:
|
||||||
|
dest: /tmp/ansible_mempool_config.yml
|
||||||
|
content: |
|
||||||
|
uptime_kuma_url: "{{ uptime_kuma_api_url }}"
|
||||||
|
username: "{{ uptime_kuma_username }}"
|
||||||
|
password: "{{ uptime_kuma_password }}"
|
||||||
|
monitors:
|
||||||
|
- "Mempool MariaDB"
|
||||||
|
- "Mempool Backend"
|
||||||
|
- "Mempool Frontend"
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Run Uptime Kuma push monitor setup
|
||||||
|
command: python3 /tmp/setup_mempool_monitors.py
|
||||||
|
delegate_to: localhost
|
||||||
|
become: no
|
||||||
|
register: monitor_setup
|
||||||
|
changed_when: "'SUCCESS' in monitor_setup.stdout"
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Display monitor setup output
|
||||||
|
debug:
|
||||||
|
msg: "{{ monitor_setup.stdout_lines }}"
|
||||||
|
when: monitor_setup.stdout is defined
|
||||||
|
|
||||||
|
- name: Read push URLs from file
|
||||||
|
slurp:
|
||||||
|
src: /tmp/mempool_push_urls.yml
|
||||||
|
delegate_to: localhost
|
||||||
|
become: no
|
||||||
|
register: push_urls_file
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Parse push URLs
|
||||||
|
set_fact:
|
||||||
|
push_urls: "{{ push_urls_file.content | b64decode | from_yaml }}"
|
||||||
|
when: push_urls_file.content is defined
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Update MariaDB health check service with push URL
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/systemd/system/mempool-mariadb-healthcheck.service
|
||||||
|
regexp: '^Environment=UPTIME_KUMA_PUSH_URL='
|
||||||
|
line: "Environment=UPTIME_KUMA_PUSH_URL={{ push_urls['Mempool MariaDB'] }}"
|
||||||
|
insertafter: '^\[Service\]'
|
||||||
|
when: push_urls is defined and push_urls['Mempool MariaDB'] is defined
|
||||||
|
|
||||||
|
- name: Update Backend health check service with push URL
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/systemd/system/mempool-backend-healthcheck.service
|
||||||
|
regexp: '^Environment=UPTIME_KUMA_PUSH_URL='
|
||||||
|
line: "Environment=UPTIME_KUMA_PUSH_URL={{ push_urls['Mempool Backend'] }}"
|
||||||
|
insertafter: '^\[Service\]'
|
||||||
|
when: push_urls is defined and push_urls['Mempool Backend'] is defined
|
||||||
|
|
||||||
|
- name: Update Frontend health check service with push URL
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/systemd/system/mempool-frontend-healthcheck.service
|
||||||
|
regexp: '^Environment=UPTIME_KUMA_PUSH_URL='
|
||||||
|
line: "Environment=UPTIME_KUMA_PUSH_URL={{ push_urls['Mempool Frontend'] }}"
|
||||||
|
insertafter: '^\[Service\]'
|
||||||
|
when: push_urls is defined and push_urls['Mempool Frontend'] is defined
|
||||||
|
|
||||||
|
- name: Reload systemd after push URL updates
|
||||||
|
systemd:
|
||||||
|
daemon_reload: yes
|
||||||
|
when: push_urls is defined
|
||||||
|
|
||||||
|
- name: Restart health check timers
|
||||||
|
systemd:
|
||||||
|
name: "mempool-{{ item }}-healthcheck.timer"
|
||||||
|
state: restarted
|
||||||
|
loop:
|
||||||
|
- mariadb
|
||||||
|
- backend
|
||||||
|
- frontend
|
||||||
|
when: push_urls is defined
|
||||||
|
|
||||||
|
- name: Clean up temporary files
|
||||||
|
delegate_to: localhost
|
||||||
|
become: no
|
||||||
|
file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: absent
|
||||||
|
loop:
|
||||||
|
- /tmp/setup_mempool_monitors.py
|
||||||
|
- /tmp/ansible_mempool_config.yml
|
||||||
|
- /tmp/mempool_push_urls.yml
|
||||||
|
|
||||||
|
- name: Configure Caddy reverse proxy for Mempool on vipy
|
||||||
|
hosts: vipy
|
||||||
|
become: yes
|
||||||
|
vars_files:
|
||||||
|
- ../../infra_vars.yml
|
||||||
|
- ../../services_config.yml
|
||||||
|
- ../../infra_secrets.yml
|
||||||
|
- ./mempool_vars.yml
|
||||||
|
vars:
|
||||||
|
mempool_subdomain: "{{ subdomains.mempool }}"
|
||||||
|
mempool_domain: "{{ mempool_subdomain }}.{{ root_domain }}"
|
||||||
|
caddy_sites_dir: "{{ caddy_sites_dir }}"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Ensure Caddy sites-enabled directory exists
|
||||||
|
file:
|
||||||
|
path: "{{ caddy_sites_dir }}"
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Ensure Caddyfile includes import directive for sites-enabled
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/caddy/Caddyfile
|
||||||
|
line: 'import sites-enabled/*'
|
||||||
|
insertafter: EOF
|
||||||
|
state: present
|
||||||
|
backup: yes
|
||||||
|
create: yes
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Create Caddy reverse proxy configuration for Mempool
|
||||||
|
copy:
|
||||||
|
dest: "{{ caddy_sites_dir }}/mempool.conf"
|
||||||
|
content: |
|
||||||
|
{{ mempool_domain }} {
|
||||||
|
reverse_proxy mempool-box:{{ mempool_frontend_port }} {
|
||||||
|
# Use Tailscale MagicDNS to resolve the upstream hostname
|
||||||
|
transport http {
|
||||||
|
resolvers 100.100.100.100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Reload Caddy to apply new config
|
||||||
|
systemd:
|
||||||
|
name: caddy
|
||||||
|
state: reloaded
|
||||||
|
|
||||||
|
- name: Display Mempool URL
|
||||||
|
debug:
|
||||||
|
msg: "Mempool is now available at https://{{ mempool_domain }}"
|
||||||
|
|
||||||
|
# ===========================================
|
||||||
|
# Uptime Kuma HTTP Monitor for Public Endpoint
|
||||||
|
# ===========================================
|
||||||
|
- name: Create Uptime Kuma HTTP monitor setup script for Mempool
|
||||||
|
delegate_to: localhost
|
||||||
|
become: no
|
||||||
|
copy:
|
||||||
|
dest: /tmp/setup_mempool_http_monitor.py
|
||||||
|
content: |
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
import yaml
|
||||||
|
from uptime_kuma_api import UptimeKumaApi, MonitorType
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open('/tmp/ansible_mempool_http_config.yml', 'r') as f:
|
||||||
|
config = yaml.safe_load(f)
|
||||||
|
|
||||||
|
url = config['uptime_kuma_url']
|
||||||
|
username = config['username']
|
||||||
|
password = config['password']
|
||||||
|
monitor_url = config['monitor_url']
|
||||||
|
monitor_name = config['monitor_name']
|
||||||
|
|
||||||
|
api = UptimeKumaApi(url, timeout=30)
|
||||||
|
api.login(username, password)
|
||||||
|
|
||||||
|
monitors = api.get_monitors()
|
||||||
|
|
||||||
|
# Find or create "services" group
|
||||||
|
group = next((m for m in monitors if m.get('name') == 'services' and m.get('type') == 'group'), None)
|
||||||
|
if not group:
|
||||||
|
api.add_monitor(type='group', name='services')
|
||||||
|
monitors = api.get_monitors()
|
||||||
|
group = next((m for m in monitors if m.get('name') == 'services' and m.get('type') == 'group'), None)
|
||||||
|
|
||||||
|
# Check if monitor already exists
|
||||||
|
existing = next((m for m in monitors if m.get('name') == monitor_name), None)
|
||||||
|
|
||||||
|
# Get ntfy notification ID
|
||||||
|
notifications = api.get_notifications()
|
||||||
|
ntfy_notification_id = None
|
||||||
|
for notif in notifications:
|
||||||
|
if notif.get('type') == 'ntfy':
|
||||||
|
ntfy_notification_id = notif.get('id')
|
||||||
|
break
|
||||||
|
|
||||||
|
if existing:
|
||||||
|
print(f"Monitor '{monitor_name}' already exists (ID: {existing['id']})")
|
||||||
|
print("Skipping - monitor already configured")
|
||||||
|
else:
|
||||||
|
print(f"Creating HTTP monitor '{monitor_name}'...")
|
||||||
|
api.add_monitor(
|
||||||
|
type=MonitorType.HTTP,
|
||||||
|
name=monitor_name,
|
||||||
|
url=monitor_url,
|
||||||
|
parent=group['id'],
|
||||||
|
interval=60,
|
||||||
|
maxretries=3,
|
||||||
|
retryInterval=60,
|
||||||
|
notificationIDList={ntfy_notification_id: True} if ntfy_notification_id else {}
|
||||||
|
)
|
||||||
|
|
||||||
|
api.disconnect()
|
||||||
|
print("SUCCESS")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ERROR: {str(e)}", file=sys.stderr)
|
||||||
|
traceback.print_exc(file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Create temporary config for HTTP monitor setup
|
||||||
|
delegate_to: localhost
|
||||||
|
become: no
|
||||||
|
copy:
|
||||||
|
dest: /tmp/ansible_mempool_http_config.yml
|
||||||
|
content: |
|
||||||
|
uptime_kuma_url: "https://{{ subdomains.uptime_kuma }}.{{ root_domain }}"
|
||||||
|
username: "{{ uptime_kuma_username }}"
|
||||||
|
password: "{{ uptime_kuma_password }}"
|
||||||
|
monitor_url: "https://{{ mempool_domain }}"
|
||||||
|
monitor_name: "Mempool"
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Run Uptime Kuma HTTP monitor setup
|
||||||
|
command: python3 /tmp/setup_mempool_http_monitor.py
|
||||||
|
delegate_to: localhost
|
||||||
|
become: no
|
||||||
|
register: http_monitor_setup
|
||||||
|
changed_when: "'SUCCESS' in http_monitor_setup.stdout"
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Display HTTP monitor setup output
|
||||||
|
debug:
|
||||||
|
msg: "{{ http_monitor_setup.stdout_lines }}"
|
||||||
|
when: http_monitor_setup.stdout is defined
|
||||||
|
|
||||||
|
- name: Clean up HTTP monitor temporary files
|
||||||
|
delegate_to: localhost
|
||||||
|
become: no
|
||||||
|
file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: absent
|
||||||
|
loop:
|
||||||
|
- /tmp/setup_mempool_http_monitor.py
|
||||||
|
- /tmp/ansible_mempool_http_config.yml
|
||||||
|
|
||||||
33
ansible/services/mempool/mempool_vars.yml
Normal file
33
ansible/services/mempool/mempool_vars.yml
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
# Mempool Configuration Variables
|
||||||
|
|
||||||
|
# Version - Pinned to specific release
|
||||||
|
mempool_version: "v3.2.1"
|
||||||
|
|
||||||
|
# Directories
|
||||||
|
mempool_dir: /opt/mempool
|
||||||
|
mempool_data_dir: "{{ mempool_dir }}/data"
|
||||||
|
mempool_mysql_dir: "{{ mempool_dir }}/mysql"
|
||||||
|
|
||||||
|
# Network - Bitcoin Core/Knots connection (via Tailnet Magic DNS)
|
||||||
|
bitcoin_host: "knots-box"
|
||||||
|
bitcoin_rpc_port: 8332
|
||||||
|
# Note: bitcoin_rpc_user and bitcoin_rpc_password are loaded from infra_secrets.yml
|
||||||
|
|
||||||
|
# Network - Fulcrum Electrum server (via Tailnet Magic DNS)
|
||||||
|
fulcrum_host: "fulcrum-box"
|
||||||
|
fulcrum_port: 50001
|
||||||
|
fulcrum_tls: "false"
|
||||||
|
|
||||||
|
# Mempool network mode
|
||||||
|
mempool_network: "mainnet"
|
||||||
|
|
||||||
|
# Container ports (internal)
|
||||||
|
mempool_frontend_port: 8080
|
||||||
|
mempool_backend_port: 8999
|
||||||
|
|
||||||
|
# MariaDB settings
|
||||||
|
mariadb_database: "mempool"
|
||||||
|
mariadb_user: "mempool"
|
||||||
|
# Note: mariadb_mempool_password is loaded from infra_secrets.yml
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -21,6 +21,9 @@ subdomains:
|
||||||
|
|
||||||
# Memos (on memos-box)
|
# Memos (on memos-box)
|
||||||
memos: memos
|
memos: memos
|
||||||
|
|
||||||
|
# Mempool Block Explorer (on mempool_box, proxied via vipy)
|
||||||
|
mempool: mempool
|
||||||
|
|
||||||
# Caddy configuration
|
# Caddy configuration
|
||||||
caddy_sites_dir: /etc/caddy/sites-enabled
|
caddy_sites_dir: /etc/caddy/sites-enabled
|
||||||
|
|
|
||||||
|
|
@ -30,16 +30,7 @@ resource "proxmox_vm_qemu" "vm" {
|
||||||
|
|
||||||
lifecycle {
|
lifecycle {
|
||||||
prevent_destroy = true
|
prevent_destroy = true
|
||||||
ignore_changes = [
|
ignore_changes = all
|
||||||
name,
|
|
||||||
cpu,
|
|
||||||
memory,
|
|
||||||
network,
|
|
||||||
ipconfig0,
|
|
||||||
ciuser,
|
|
||||||
sshkeys,
|
|
||||||
cicustom,
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
serial {
|
serial {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue