SSH-Infrastructure / tools / sync-hosts-from-upstream.sh
Newer Older
125 lines | 3.92kb
Bogdan Timofte authored 2 weeks ago
1
#!/usr/bin/env bash
2
set -euo pipefail
3

            
4
project_root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
5

            
6
inventory_path=${INVENTORY_PATH:-"$project_root/inventory/hosts.yaml"}
7
upstream_hosts_file=${UPSTREAM_HOSTS_FILE:-}
8
upstream_ssh_target=${UPSTREAM_SSH_TARGET:-nextgen@192.168.2.103}
9
upstream_hosts_path=${UPSTREAM_HOSTS_PATH:-/home/nextgen/projects/ssh-infrastructure/inventory/hosts.yaml}
10
local_is_jumper_identity_file=${LOCAL_IS_JUMPER_IDENTITY_FILE:-}
11
if [[ -z "$local_is_jumper_identity_file" ]]; then
12
    local_is_jumper_identity_file='~/.ssh/keys/is-jumper_ed25519'
13
fi
14
deploy_after_sync=${DEPLOY_AFTER_SYNC:-1}
15
force_deploy=${FORCE_DEPLOY:-0}
16

            
17
tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/ssh-infra-sync.XXXXXX")
18
trap 'rm -rf "$tmpdir"' EXIT
19

            
20
tmp_hosts="$tmpdir/hosts.yaml"
21
tmp_generated="$tmpdir/generated"
22

            
23
if [[ -n "$upstream_hosts_file" ]]; then
24
    cp "$upstream_hosts_file" "$tmp_hosts"
25
else
26
    /usr/bin/scp -q "${upstream_ssh_target}:${upstream_hosts_path}" "$tmp_hosts"
27
fi
28

            
29
python3 - "$tmp_hosts" "$local_is_jumper_identity_file" <<'PY'
30
from pathlib import Path
31
import sys
32

            
33
import yaml
34

            
35
path = Path(sys.argv[1])
36
identity_file = sys.argv[2]
37
text = path.read_text(encoding="utf-8")
38

            
39
with path.open("r", encoding="utf-8") as handle:
40
    data = yaml.safe_load(handle)
41

            
42
is_jumper = data.get("entrypoints", {}).get("is_jumper", {})
43
if (
44
    is_jumper.get("identity_file") == identity_file
45
    and is_jumper.get("identities_only") is True
46
):
47
    raise SystemExit(0)
48

            
49
lines = text.splitlines(keepends=True)
50

            
51
entrypoints_idx = None
52
for idx, line in enumerate(lines):
53
    if line.strip() == "entrypoints:" and not line.startswith((" ", "\t")):
54
        entrypoints_idx = idx
55
        break
56
if entrypoints_idx is None:
57
    raise SystemExit("missing entrypoints section")
58

            
59
is_jumper_idx = None
60
for idx in range(entrypoints_idx + 1, len(lines)):
61
    line = lines[idx]
62
    if line and not line.startswith((" ", "\t")) and line.strip():
63
        break
64
    if line.startswith("  is_jumper:"):
65
        is_jumper_idx = idx
66
        break
67
if is_jumper_idx is None:
68
    raise SystemExit("missing entrypoints.is_jumper section")
69

            
70
block_end = len(lines)
71
for idx in range(is_jumper_idx + 1, len(lines)):
72
    line = lines[idx]
73
    if line.strip() and not line.startswith("    "):
74
        block_end = idx
75
        break
76

            
77
identity_line = f"    identity_file: {identity_file}\n"
78
identities_only_line = "    identities_only: true\n"
79
identity_idx = None
80
identities_only_idx = None
81
for idx in range(is_jumper_idx + 1, block_end):
82
    stripped = lines[idx].strip()
83
    if stripped.startswith("identity_file:"):
84
        identity_idx = idx
85
    elif stripped.startswith("identities_only:"):
86
        identities_only_idx = idx
87

            
88
if identity_idx is None:
89
    insert_at = identities_only_idx if identities_only_idx is not None else block_end
90
    lines.insert(insert_at, identity_line)
91
    if identities_only_idx is not None:
92
        identities_only_idx += 1
93
        block_end += 1
94
else:
95
    lines[identity_idx] = identity_line
96

            
97
if identities_only_idx is None:
98
    insert_at = (identity_idx + 1) if identity_idx is not None else block_end
99
    lines.insert(insert_at, identities_only_line)
100
else:
101
    lines[identities_only_idx] = identities_only_line
102

            
103
path.write_text("".join(lines), encoding="utf-8")
104
PY
105

            
106
python3 "$project_root/tools/generate-configs.py" \
107
    --inventory "$tmp_hosts" \
108
    --output-dir "$tmp_generated"
109

            
110
if cmp -s "$tmp_hosts" "$inventory_path"; then
111
    printf 'inventory unchanged: %s\n' "$inventory_path"
112
    if [[ "$deploy_after_sync" == "1" && "$force_deploy" == "1" ]]; then
113
        "$project_root/tools/deploy-local.sh"
114
    fi
115
    exit 0
116
fi
117

            
118
install -m 644 "$tmp_hosts" "$inventory_path"
119
printf 'updated inventory from upstream: %s\n' "$inventory_path"
120

            
121
if [[ "$deploy_after_sync" == "1" ]]; then
122
    "$project_root/tools/deploy-local.sh"
123
else
124
    printf 'skipped deploy because DEPLOY_AFTER_SYNC=%s\n' "$deploy_after_sync"
125
fi