formatting

This commit is contained in:
Jakub Kropáček 2025-01-09 17:34:18 +01:00
parent 8afcfba1d9
commit 60777a578f
3 changed files with 100 additions and 42 deletions

View file

@ -1,11 +1,16 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import argparse import argparse
import json import json
import pathlib
import shutil
import socket import socket
import time import time
from subprocess import check_output from subprocess import check_output
ROOT_DIR = pathlib.Path(__file__).parent.parent
KEYS_FILE = ROOT_DIR / "secrets" / "keys.json"
def _get_available_machines() -> list: def _get_available_machines() -> list:
output = check_output(["nix", "flake", "show", "--json"]) output = check_output(["nix", "flake", "show", "--json"])
@ -14,22 +19,38 @@ def _get_available_machines() -> list:
return list(machines) return list(machines)
def _validate_ip(ip: str) -> bool: def _is_valid_ip(ip: str) -> bool:
try: try:
socket.inet_aton(ip) socket.inet_aton(ip)
return False
except socket.error:
return True return True
except socket.error:
return False
def _check_ssh_connection(ip: str) -> bool: def _check_ssh_connection(ip: str) -> bool:
try: try:
check_output(["ssh", f"root@{ip}", "echo", "Connected"]) check_output(["ssh", f"krop@{ip}", "echo", "Connected"])
return True return True
except Exception: except Exception:
return False return False
def add_key_to_secrets(key: str):
def add_key_to_secrets(machine_name: str, key: str):
keys = json.loads(KEYS_FILE.read_text())
if keys.get("servers").get(machine_name):
raise ValueError(f"Key for {machine_name} already exists, remove it first")
keys["servers"][machine_name] = key
for secret in keys.get("secrets"):
keys["secrets"][secret].append(f"servers:{machine_name}")
KEYS_FILE.write_text(json.dumps(keys, indent=2))
def rekey_secrets():
agenix_bin = shutil.which("agenix")
check_output([agenix_bin, "-r"], cwd=ROOT_DIR / "secrets")
def bootstrap_machine(ip: str): def bootstrap_machine(ip: str):
@ -40,7 +61,7 @@ def bootstrap_machine(ip: str):
"github:nix-community/nixos-anywhere", "github:nix-community/nixos-anywhere",
"--", "--",
"--flake", "--flake",
'".#bootstrap"', ".#bootstrap",
"--target-host", "--target-host",
f"root@{ip}", f"root@{ip}",
"--build-on-remote", "--build-on-remote",
@ -48,11 +69,29 @@ def bootstrap_machine(ip: str):
) )
def install_machine(machine_name: str, ip: str):
check_output(
[
"nixos-rebuild",
"boot",
"--flake",
f".#{machine_name}",
"--fast",
"--target-host",
f"krop@{ip}",
"--build-host",
f"krop@{ip}",
"--use-remote-sudo",
]
)
def get_ssh_key(ip: str) -> str: def get_ssh_key(ip: str) -> str:
""" """
This function uses machines ssh-keyscan to get the ssh key and then get the ed25519 key This function uses machines ssh-keyscan to get the ssh key and then get the ed25519 key
""" """
ssh_keys = check_output( ssh_keys = (
check_output(
[ [
"ssh-keyscan", "ssh-keyscan",
"-q", "-q",
@ -60,7 +99,11 @@ def get_ssh_key(ip: str) -> str:
"ed25519", "ed25519",
ip, ip,
] ]
).decode("utf-8").strip().splitlines() )
.decode("utf-8")
.strip()
.splitlines()
)
if len(ssh_keys) != 1: if len(ssh_keys) != 1:
raise ValueError("Exactly one key should be returned") raise ValueError("Exactly one key should be returned")
@ -69,6 +112,7 @@ def get_ssh_key(ip: str) -> str:
return key return key
def get_machine_config(machine_name: str) -> dict: def get_machine_config(machine_name: str) -> dict:
output = check_output( output = check_output(
[ [
@ -81,6 +125,17 @@ def get_machine_config(machine_name: str) -> dict:
return json.loads(output) return json.loads(output)
def reboot_machine(ip: str):
check_output(
[
"ssh",
f"krop@{ip}",
"sudo",
"reboot",
]
)
def main() -> int: def main() -> int:
parser = argparse.ArgumentParser(description="Install a machine") parser = argparse.ArgumentParser(description="Install a machine")
parser.add_argument( parser.add_argument(
@ -95,32 +150,32 @@ def main() -> int:
f"Machine {machine_name} not found, available machines are: {_get_available_machines()}" f"Machine {machine_name} not found, available machines are: {_get_available_machines()}"
) )
if _validate_ip(args.machine_ip): machine_ip = args.machine_ip
raise ValueError(f"Invalid IP address {args.machine_ip}") if not _is_valid_ip(machine_ip):
raise ValueError(f"Invalid IP address {machine_ip}")
machine_config = get_machine_config(machine_name) print(f"Bootstrapping machine {machine_ip}")
# We are bootstraping the machine first because we need their ssh keys bootstrap_machine(machine_ip)
print(f"Bootstrapping machine {args.machine_ip}")
bootstrap_machine()
print("Machine bootstrapped") print("Machine bootstrapped")
print("Waiting for ssh connection") print("Waiting for ssh connection")
while not _check_ssh_connection(): while not _check_ssh_connection(machine_ip):
time.sleep(5) time.sleep(5)
print("Machine is up and running") print("Machine is up and running")
print("Getting ssh key") print("Getting ssh key")
ssh_key = get_ssh_key(args.machine_ip) ssh_key = get_ssh_key(machine_ip)
print(f"SSH key: {ssh_key}")
print("Adding ssh key to secrets") print("Adding ssh key to secrets")
add_key_to_secrets(ssh_key) add_key_to_secrets(machine_name, ssh_key)
rekey_secrets() rekey_secrets()
# Add the ssh key to keys in secrets/keys.json print("Installing machine")
# and rekey the secrets install_machine(machine_name, machine_ip)
print("Machine installed, rebooting")
# install_machine() reboot_machine(machine_ip)
print("")
return 0 return 0

View file

@ -1,13 +1,16 @@
{ {
"hosts": { "hosts": {
"wenar-nix": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJl0Rdo2kHliBeIiPuiO4kYO5M0VZFNXw4siepV1p6Pj", "wenar-nix": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJl0Rdo2kHliBeIiPuiO4kYO5M0VZFNXw4siepV1p6Pj",
"lenar": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOUnlAjPnMwJYgZb7YuholdTxifOEFnAyXVqI+xFlHw6" "lenar": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOUnlAjPnMwJYgZb7YuholdTxifOEFnAyXVqI+xFlHw6"
}, },
"servers" : { "servers": {
"test-server": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID4ioqiTzYe6Y6H0YfFkWyDBbCB25wYs3gKNZIufE/Sn" "test-server": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID4ioqiTzYe6Y6H0YfFkWyDBbCB25wYs3gKNZIufE/Sn"
}, },
"secrets": { "secrets": {
"mypassword.age": ["hosts:wenar-nix", "hosts:lenar", "servers:test-server"] "mypassword.age": [
"hosts:wenar-nix",
"hosts:lenar",
"servers:test-server"
]
} }
} }

Binary file not shown.