132 lines
5.4 KiB
Bash
Executable File
132 lines
5.4 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_CONTROL_BOARD_MIGRATION_PROJECT:-minerops-control-board-migration-$$}"
|
|
compose=(docker compose --project-name "${project_name}" --env-file .env.dev -f compose.dev.yaml)
|
|
|
|
cleanup() {
|
|
status=$?
|
|
"${compose[@]}" down --volumes --remove-orphans >/dev/null 2>&1 || true
|
|
exit "${status}"
|
|
}
|
|
trap cleanup EXIT
|
|
run_alembic() { "${compose[@]}" run --rm --no-deps backend alembic "$@"; }
|
|
|
|
[[ -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 )) || exit 1
|
|
sleep 1
|
|
done
|
|
"${compose[@]}" build backend
|
|
|
|
run_alembic upgrade 0012_return_to_service
|
|
"${compose[@]}" exec -T postgres sh -ec \
|
|
'psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$POSTGRES_DB"' <<'SQL'
|
|
INSERT INTO users (id, username, display_name, password_hash, role_id)
|
|
SELECT '00000000-0000-0000-0000-000000001401', 'board-migration',
|
|
'Board Migration', 'unused', id FROM roles WHERE name = 'Admin';
|
|
INSERT INTO miners (
|
|
id, asset_tag, current_mac, control_board_sn, lifecycle_status,
|
|
status, first_seen_at, last_seen_at
|
|
) VALUES (
|
|
'00000000-0000-0000-0000-000000001402', 'BOARD-LEGACY',
|
|
'02-AA-BB-CC-DD-01', 'LEGACY-BOARD', 'active', 'unknown', NULL, NULL
|
|
);
|
|
SQL
|
|
|
|
"${compose[@]}" exec -T postgres sh -ec \
|
|
'psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$POSTGRES_DB"' <<'SQL'
|
|
INSERT INTO miners (
|
|
id, asset_tag, current_mac, lifecycle_status, status,
|
|
first_seen_at, last_seen_at
|
|
) VALUES (
|
|
'00000000-0000-0000-0000-000000001404', 'BOARD-CONFLICT',
|
|
'02:AA:BB:CC:DD:01', 'active', 'unknown', NULL, NULL
|
|
);
|
|
SQL
|
|
if preflight_error="$(run_alembic upgrade head 2>&1)"; then
|
|
echo "Duplicate normalized MAC preflight did not stop the upgrade." >&2
|
|
exit 1
|
|
fi
|
|
[[ "${preflight_error}" == *"normalized MAC values have multiple miner owners"* ]]
|
|
"${compose[@]}" exec -T postgres sh -ec \
|
|
'psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$POSTGRES_DB"' <<'SQL'
|
|
DELETE FROM miners WHERE id = '00000000-0000-0000-0000-000000001404';
|
|
SQL
|
|
|
|
run_alembic upgrade head
|
|
[[ "$(run_alembic current 2>/dev/null)" == *"0013_control_board_replacement"* ]]
|
|
"${compose[@]}" exec -T postgres sh -ec \
|
|
'psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$POSTGRES_DB"' <<'SQL'
|
|
DO $$
|
|
DECLARE roles_for_permission text[];
|
|
BEGIN
|
|
IF to_regclass('public.miner_control_board_installations') IS NULL
|
|
OR to_regclass('public.miner_mac_ownerships') IS NULL THEN
|
|
RAISE EXCEPTION 'Task 004 tables are missing';
|
|
END IF;
|
|
IF EXISTS (SELECT 1 FROM miner_control_board_installations) THEN
|
|
RAISE EXCEPTION 'Migration fabricated installation history';
|
|
END IF;
|
|
SELECT array_agg(role.name ORDER BY role.name) INTO roles_for_permission
|
|
FROM role_permissions rp JOIN roles role ON role.id = rp.role_id
|
|
JOIN permissions permission ON permission.id = rp.permission_id
|
|
WHERE permission.key = 'miners.replace_control_board';
|
|
IF roles_for_permission <> ARRAY['Admin', 'Manager', 'Technician'] THEN
|
|
RAISE EXCEPTION 'Unexpected permission roles: %', roles_for_permission;
|
|
END IF;
|
|
IF (SELECT miner_id FROM miner_mac_ownerships WHERE normalized_mac = '02aabbccdd01')
|
|
<> '00000000-0000-0000-0000-000000001402'::uuid THEN
|
|
RAISE EXCEPTION 'Legacy MAC ownership was not preserved';
|
|
END IF;
|
|
END $$;
|
|
SQL
|
|
|
|
run_alembic downgrade 0012_return_to_service
|
|
run_alembic upgrade head
|
|
|
|
"${compose[@]}" exec -T postgres sh -ec \
|
|
'psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$POSTGRES_DB"' <<'SQL'
|
|
UPDATE miners
|
|
SET lifecycle_status = 'in_repair', current_mac = '02:AA:BB:CC:DD:02',
|
|
control_board_sn = 'NEW-BOARD'
|
|
WHERE id = '00000000-0000-0000-0000-000000001402';
|
|
INSERT INTO miner_network_identities (
|
|
miner_id, mac_address, source, is_current, first_seen_at, last_seen_at, associated_at
|
|
) VALUES (
|
|
'00000000-0000-0000-0000-000000001402', '02:AA:BB:CC:DD:02',
|
|
'control_board_replacement', true, NULL, NULL, now()
|
|
);
|
|
INSERT INTO repairs (id, miner_id, reason, opened_by) VALUES (
|
|
'00000000-0000-0000-0000-000000001403',
|
|
'00000000-0000-0000-0000-000000001402', 'CONTROL_BOARD',
|
|
'00000000-0000-0000-0000-000000001401'
|
|
);
|
|
INSERT INTO miner_control_board_installations (
|
|
miner_id, record_origin, installed_repair_id, mac_address, normalized_mac, board_serial,
|
|
replacement_reason, installed_at, installed_by
|
|
) VALUES (
|
|
'00000000-0000-0000-0000-000000001402', 'replacement',
|
|
'00000000-0000-0000-0000-000000001403', '02:AA:BB:CC:DD:02',
|
|
'02aabbccdd02', 'NEW-BOARD', 'failed', now(),
|
|
'00000000-0000-0000-0000-000000001401'
|
|
);
|
|
SQL
|
|
if downgrade_error="$(run_alembic downgrade 0012_return_to_service 2>&1)"; then
|
|
echo "Downgrade discarded authoritative control-board history." >&2
|
|
exit 1
|
|
fi
|
|
[[ "${downgrade_error}" == *"authoritative installation records or events"* ]]
|
|
[[ "$(run_alembic current 2>/dev/null)" == *"0013_control_board_replacement"* ]]
|
|
|
|
database="minerops_control_board_empty"
|
|
"${compose[@]}" exec -T postgres sh -ec \
|
|
'createdb -U "$POSTGRES_USER" '"${database}"
|
|
"${compose[@]}" run --rm --no-deps -e POSTGRES_DB="${database}" backend alembic upgrade head
|
|
[[ "$("${compose[@]}" run --rm --no-deps -e POSTGRES_DB="${database}" backend alembic current 2>/dev/null)" == *"0013_control_board_replacement"* ]]
|