#!/usr/bin/env bash set -euo pipefail project_root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd) inventory_path=${INVENTORY_PATH:-"$project_root/inventory/hosts.yaml"} upstream_hosts_file=${UPSTREAM_HOSTS_FILE:-} upstream_ssh_target=${UPSTREAM_SSH_TARGET:-nextgen@192.168.2.103} upstream_hosts_path=${UPSTREAM_HOSTS_PATH:-/home/nextgen/projects/ssh-infrastructure/inventory/hosts.yaml} local_is_jumper_identity_file=${LOCAL_IS_JUMPER_IDENTITY_FILE:-} if [[ -z "$local_is_jumper_identity_file" ]]; then local_is_jumper_identity_file='~/.ssh/keys/is-jumper_ed25519' fi deploy_after_sync=${DEPLOY_AFTER_SYNC:-1} force_deploy=${FORCE_DEPLOY:-0} tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/ssh-infra-sync.XXXXXX") trap 'rm -rf "$tmpdir"' EXIT tmp_hosts="$tmpdir/hosts.yaml" tmp_generated="$tmpdir/generated" if [[ -n "$upstream_hosts_file" ]]; then cp "$upstream_hosts_file" "$tmp_hosts" else /usr/bin/scp -q "${upstream_ssh_target}:${upstream_hosts_path}" "$tmp_hosts" fi python3 - "$tmp_hosts" "$local_is_jumper_identity_file" <<'PY' from pathlib import Path import sys import yaml path = Path(sys.argv[1]) identity_file = sys.argv[2] text = path.read_text(encoding="utf-8") with path.open("r", encoding="utf-8") as handle: data = yaml.safe_load(handle) is_jumper = data.get("entrypoints", {}).get("is_jumper", {}) if ( is_jumper.get("identity_file") == identity_file and is_jumper.get("identities_only") is True ): raise SystemExit(0) lines = text.splitlines(keepends=True) entrypoints_idx = None for idx, line in enumerate(lines): if line.strip() == "entrypoints:" and not line.startswith((" ", "\t")): entrypoints_idx = idx break if entrypoints_idx is None: raise SystemExit("missing entrypoints section") is_jumper_idx = None for idx in range(entrypoints_idx + 1, len(lines)): line = lines[idx] if line and not line.startswith((" ", "\t")) and line.strip(): break if line.startswith(" is_jumper:"): is_jumper_idx = idx break if is_jumper_idx is None: raise SystemExit("missing entrypoints.is_jumper section") block_end = len(lines) for idx in range(is_jumper_idx + 1, len(lines)): line = lines[idx] if line.strip() and not line.startswith(" "): block_end = idx break identity_line = f" identity_file: {identity_file}\n" identities_only_line = " identities_only: true\n" identity_idx = None identities_only_idx = None for idx in range(is_jumper_idx + 1, block_end): stripped = lines[idx].strip() if stripped.startswith("identity_file:"): identity_idx = idx elif stripped.startswith("identities_only:"): identities_only_idx = idx if identity_idx is None: insert_at = identities_only_idx if identities_only_idx is not None else block_end lines.insert(insert_at, identity_line) if identities_only_idx is not None: identities_only_idx += 1 block_end += 1 else: lines[identity_idx] = identity_line if identities_only_idx is None: insert_at = (identity_idx + 1) if identity_idx is not None else block_end lines.insert(insert_at, identities_only_line) else: lines[identities_only_idx] = identities_only_line path.write_text("".join(lines), encoding="utf-8") PY python3 "$project_root/tools/generate-configs.py" \ --inventory "$tmp_hosts" \ --output-dir "$tmp_generated" if cmp -s "$tmp_hosts" "$inventory_path"; then printf 'inventory unchanged: %s\n' "$inventory_path" if [[ "$deploy_after_sync" == "1" && "$force_deploy" == "1" ]]; then "$project_root/tools/deploy-local.sh" fi exit 0 fi install -m 644 "$tmp_hosts" "$inventory_path" printf 'updated inventory from upstream: %s\n' "$inventory_path" if [[ "$deploy_after_sync" == "1" ]]; then "$project_root/tools/deploy-local.sh" else printf 'skipped deploy because DEPLOY_AFTER_SYNC=%s\n' "$deploy_after_sync" fi