formatting
This commit is contained in:
parent
8afcfba1d9
commit
60777a578f
3 changed files with 100 additions and 42 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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.
Loading…
Reference in a new issue