187 lines
8.1 KiB
Bash
Executable File
187 lines
8.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
cd "${repo_root}"
|
|
project_name="${MINEROPS_AGENT_ZONES_MIGRATION_PROJECT:-minerops-agent-zones-migration-$$}"
|
|
compose=(docker compose --project-name "${project_name}" --env-file .env.dev -f compose.dev.yaml)
|
|
|
|
cleanup() {
|
|
status=$?
|
|
if (( status != 0 )); then
|
|
"${compose[@]}" logs --no-color --tail 160 postgres || true
|
|
fi
|
|
"${compose[@]}" down --volumes --remove-orphans >/dev/null 2>&1 || true
|
|
exit "${status}"
|
|
}
|
|
trap cleanup EXIT
|
|
run_alembic() { "${compose[@]}" run --rm --no-deps backend alembic "$@"; }
|
|
psql_db() {
|
|
"${compose[@]}" exec -T postgres sh -ec \
|
|
'exec psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$POSTGRES_DB" "$@"' sh "$@"
|
|
}
|
|
|
|
[[ -f .env.dev ]] || { echo "Missing .env.dev" >&2; exit 1; }
|
|
"${compose[@]}" up --detach postgres
|
|
for attempt in $(seq 1 60); do
|
|
"${compose[@]}" exec -T postgres sh -ec \
|
|
'pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB"' >/dev/null 2>&1 && break
|
|
(( attempt < 60 )) || { echo "PostgreSQL did not become ready" >&2; exit 1; }
|
|
sleep 1
|
|
done
|
|
"${compose[@]}" build backend
|
|
|
|
site_a="00000000-0000-4000-8000-000000001690"
|
|
site_b="00000000-0000-4000-8000-000000001691"
|
|
miner_a="00000000-0000-4000-8000-000000001692"
|
|
|
|
echo "Testing production path 0014 -> 0015 -> 0016 and truthful unassigned data..."
|
|
run_alembic upgrade 0014_repair_parts_tracking
|
|
psql_db -c "INSERT INTO minerops_site_agents (agent_id, site_name) VALUES ('legacy-zone-unassigned', 'Legacy Display')"
|
|
run_alembic upgrade 0015_miner_control_foundation
|
|
psql_db <<SQL
|
|
INSERT INTO sites (id, name) VALUES
|
|
('${site_a}', 'Agent Zone Site A'),
|
|
('${site_b}', 'Agent Zone Site B');
|
|
INSERT INTO miners (id, site_id, asset_tag, first_seen_at, last_seen_at)
|
|
VALUES ('${miner_a}', '${site_a}', 'AGENT-ZONE-MIGRATION', NULL, NULL);
|
|
INSERT INTO minerops_site_agents (agent_id, site_id, site_name)
|
|
VALUES ('zone-agent-a', '${site_a}', 'Agent Zone Site A');
|
|
INSERT INTO minerops_agent_snapshots (agent_id, site_name, miner_count, payload)
|
|
VALUES ('zone-agent-a', 'Agent Zone Site A', 0, '{}');
|
|
INSERT INTO minerops_agent_discoveries (
|
|
id, agent_id, site_name, ip_address, raw_payload, discovery_status
|
|
) VALUES (
|
|
'agent-zone-discovery', 'zone-agent-a', 'Agent Zone Site A',
|
|
'192.0.2.90', '{}', 'new'
|
|
);
|
|
SQL
|
|
run_alembic upgrade 0016_agent_zones
|
|
[[ "$(run_alembic current 2>/dev/null)" == *"0016_agent_zones"* ]]
|
|
|
|
psql_db <<SQL
|
|
DO \$\$
|
|
DECLARE zone_a uuid;
|
|
BEGIN
|
|
SELECT id INTO zone_a FROM agent_zones
|
|
WHERE site_id = '${site_a}' AND name = 'Default Zone';
|
|
IF zone_a IS NULL THEN
|
|
RAISE EXCEPTION 'Default Zone was not created for Site A';
|
|
END IF;
|
|
IF (SELECT agent_zone_id FROM miners WHERE id = '${miner_a}') IS DISTINCT FROM zone_a THEN
|
|
RAISE EXCEPTION 'Miner was not backfilled to its Site default Zone';
|
|
END IF;
|
|
IF (SELECT agent_zone_id FROM minerops_site_agents WHERE agent_id = 'zone-agent-a')
|
|
IS DISTINCT FROM zone_a THEN
|
|
RAISE EXCEPTION 'Agent was not backfilled to its Site default Zone';
|
|
END IF;
|
|
IF (SELECT agent_zone_id FROM minerops_agent_snapshots WHERE agent_id = 'zone-agent-a' LIMIT 1)
|
|
IS DISTINCT FROM zone_a THEN
|
|
RAISE EXCEPTION 'Snapshot Zone backfill failed';
|
|
END IF;
|
|
IF (SELECT agent_zone_id FROM minerops_agent_discoveries WHERE id = 'agent-zone-discovery')
|
|
IS DISTINCT FROM zone_a THEN
|
|
RAISE EXCEPTION 'Discovery Zone backfill failed';
|
|
END IF;
|
|
IF (SELECT agent_zone_id FROM minerops_site_agents
|
|
WHERE agent_id = 'legacy-zone-unassigned') IS NOT NULL THEN
|
|
RAISE EXCEPTION 'Legacy Agent without a durable Site was guessed into a Zone';
|
|
END IF;
|
|
IF NOT EXISTS (SELECT 1 FROM pg_indexes
|
|
WHERE indexname = 'uq_minerops_site_agents_agent_zone_id') THEN
|
|
RAISE EXCEPTION 'One-Agent-per-Zone index missing';
|
|
END IF;
|
|
IF EXISTS (SELECT 1 FROM pg_indexes
|
|
WHERE indexname = 'uq_minerops_site_agents_site_id') THEN
|
|
RAISE EXCEPTION 'One-Agent-per-Site index was not removed';
|
|
END IF;
|
|
END \$\$;
|
|
SQL
|
|
|
|
echo "Testing CIDR, active-name, cross-Site, and one-Agent-per-Zone integrity..."
|
|
psql_db <<SQL
|
|
INSERT INTO agent_zone_network_ranges (agent_zone_id, network)
|
|
SELECT id, '10.30.0.0/24'::cidr FROM agent_zones
|
|
WHERE site_id = '${site_a}' AND name = 'Default Zone';
|
|
DO \$\$
|
|
DECLARE zone_a uuid;
|
|
BEGIN
|
|
SELECT id INTO zone_a FROM agent_zones
|
|
WHERE site_id = '${site_a}' AND name = 'Default Zone';
|
|
IF (SELECT network::text FROM agent_zone_network_ranges
|
|
WHERE agent_zone_id = zone_a) <> '10.30.0.0/24' THEN
|
|
RAISE EXCEPTION 'CIDR was not stored canonically';
|
|
END IF;
|
|
BEGIN
|
|
INSERT INTO agent_zones (site_id, name) VALUES ('${site_a}', 'default zone');
|
|
RAISE EXCEPTION 'Case-insensitive active Zone duplicate was accepted';
|
|
EXCEPTION WHEN unique_violation THEN NULL;
|
|
END;
|
|
BEGIN
|
|
INSERT INTO minerops_site_agents (agent_id, site_id, agent_zone_id, site_name)
|
|
VALUES ('duplicate-zone-agent', '${site_a}', zone_a, 'Duplicate');
|
|
RAISE EXCEPTION 'Second Agent in one Zone was accepted';
|
|
EXCEPTION WHEN unique_violation THEN NULL;
|
|
END;
|
|
BEGIN
|
|
UPDATE miners SET site_id = '${site_b}' WHERE id = '${miner_a}';
|
|
RAISE EXCEPTION 'Cross-Site miner Zone combination was accepted';
|
|
EXCEPTION WHEN foreign_key_violation THEN NULL;
|
|
END;
|
|
END \$\$;
|
|
SQL
|
|
|
|
echo "Confirming CIDR values with host bits are rejected..."
|
|
if psql_db -c "INSERT INTO agent_zone_network_ranges (agent_zone_id, network) SELECT id, '10.30.0.7/24'::cidr FROM agent_zones WHERE site_id = '${site_a}' AND name = 'Default Zone'"; then
|
|
echo "Host-address CIDR unexpectedly passed PostgreSQL validation" >&2
|
|
exit 1
|
|
fi
|
|
|
|
|
|
echo "Testing downgrade refusal for irreducible network configuration..."
|
|
if output="$(run_alembic downgrade 0015_miner_control_foundation 2>&1)"; then
|
|
echo "Downgrade unexpectedly accepted Agent Zone network ranges" >&2
|
|
exit 1
|
|
fi
|
|
[[ "${output}" == *"cannot be represented by the one-Agent-per-Site model"* ]]
|
|
[[ "$(run_alembic current 2>/dev/null)" == *"0016_agent_zones"* ]]
|
|
[[ "$(psql_db -Atc "SELECT count(*) FROM agent_zone_network_ranges")" == "1" ]]
|
|
psql_db -c "DELETE FROM agent_zone_network_ranges"
|
|
|
|
echo "Testing downgrade refusal with multiple Agents at one Site..."
|
|
psql_db <<SQL
|
|
WITH created AS (
|
|
INSERT INTO agent_zones (site_id, name)
|
|
VALUES ('${site_a}', 'Room 2') RETURNING id
|
|
)
|
|
INSERT INTO minerops_site_agents (agent_id, site_id, agent_zone_id, site_name)
|
|
SELECT 'zone-agent-b', '${site_a}', id, 'Agent Zone Site A' FROM created;
|
|
SQL
|
|
if output="$(run_alembic downgrade 0015_miner_control_foundation 2>&1)"; then
|
|
echo "Downgrade unexpectedly accepted multiple Agents at one Site" >&2
|
|
exit 1
|
|
fi
|
|
[[ "${output}" == *"multiple Agent installations are assigned"* ]]
|
|
[[ "${output}" == *"${site_a}"* ]]
|
|
[[ "$(run_alembic current 2>/dev/null)" == *"0016_agent_zones"* ]]
|
|
[[ "$(psql_db -Atc "SELECT count(*) FROM minerops_site_agents WHERE site_id='${site_a}'")" == "2" ]]
|
|
psql_db -c "DELETE FROM minerops_site_agents WHERE agent_id = 'zone-agent-b'; DELETE FROM agent_zones WHERE site_id = '${site_a}' AND name = 'Room 2'"
|
|
|
|
echo "Testing legal downgrade, data preservation, and re-upgrade..."
|
|
run_alembic downgrade 0015_miner_control_foundation
|
|
[[ "$(run_alembic current 2>/dev/null)" == *"0015_miner_control_foundation"* ]]
|
|
[[ "$(psql_db -Atc "SELECT count(*) FROM miners WHERE id='${miner_a}'")" == "1" ]]
|
|
[[ "$(psql_db -Atc "SELECT count(*) FROM minerops_site_agents WHERE agent_id='zone-agent-a'")" == "1" ]]
|
|
[[ "$(psql_db -Atc "SELECT count(*) FROM information_schema.tables WHERE table_name='agent_zones'")" == "0" ]]
|
|
run_alembic upgrade 0016_agent_zones
|
|
[[ "$(run_alembic current 2>/dev/null)" == *"0016_agent_zones"* ]]
|
|
|
|
echo "Testing empty database through head..."
|
|
"${compose[@]}" exec -T postgres sh -ec 'createdb -U "$POSTGRES_USER" minerops_agent_zones_empty'
|
|
"${compose[@]}" run --rm --no-deps -e POSTGRES_DB=minerops_agent_zones_empty backend alembic upgrade head
|
|
empty_revision="$("${compose[@]}" exec -T postgres sh -ec \
|
|
'psql -U "$POSTGRES_USER" -d minerops_agent_zones_empty -Atc "SELECT version_num FROM alembic_version"')"
|
|
[[ "${empty_revision}" == "0016_agent_zones" ]]
|
|
|
|
echo "Agent Zones migration lifecycle checks passed."
|