Files
clan-core/pkgs/clan-cli/clan_cli/machines/update.py
2023-08-24 16:25:06 +02:00

106 lines
3.4 KiB
Python

import argparse
import json
import subprocess
from ..ssh import Host, HostGroup, HostKeyCheck
def deploy_nixos(hosts: HostGroup) -> None:
"""
Deploy to all hosts in parallel
"""
flake_store_paths = {}
for h in hosts.hosts:
flake_uri = str(h.meta.get("flake_uri", ".#"))
if flake_uri not in flake_store_paths:
res = subprocess.run(
[
"nix",
"--extra-experimental-features",
"nix-command flakes",
"flake",
"metadata",
"--json",
flake_uri,
],
check=True,
text=True,
stdout=subprocess.PIPE,
)
data = json.loads(res.stdout)
flake_store_paths[flake_uri] = data["path"]
def deploy(h: Host) -> None:
target = f"{h.user or 'root'}@{h.host}"
flake_store_path = flake_store_paths[str(h.meta.get("flake_uri", ".#"))]
flake_path = str(h.meta.get("flake_path", "/etc/nixos"))
ssh_arg = f"-p {h.port}" if h.port else ""
if h.host_key_check != HostKeyCheck.STRICT:
ssh_arg += " -o StrictHostKeyChecking=no"
if h.host_key_check == HostKeyCheck.NONE:
ssh_arg += " -o UserKnownHostsFile=/dev/null"
ssh_arg += " -i " + h.key if h.key else ""
h.run_local(
f"rsync --checksum -vaF --delete -e 'ssh {ssh_arg}' {flake_store_path}/ {target}:{flake_path}"
)
flake_attr = h.meta.get("flake_attr", "")
if flake_attr:
flake_attr = "#" + flake_attr
target_host = h.meta.get("target_host")
if target_host:
target_user = h.meta.get("target_user")
if target_user:
target_host = f"{target_user}@{target_host}"
extra_args = h.meta.get("extra_args", [])
cmd = (
["nixos-rebuild", "switch"]
+ extra_args
+ [
"--fast",
"--option",
"keep-going",
"true",
"--option",
"accept-flake-config",
"true",
"--build-host",
"",
"--flake",
f"{flake_path}{flake_attr}",
]
)
if target_host:
cmd.extend(["--target-host", target_host])
ret = h.run(cmd, check=False)
# re-retry switch if the first time fails
if ret.returncode != 0:
ret = h.run(cmd)
hosts.run_function(deploy)
# FIXME: we want some kind of inventory here.
def update(args: argparse.Namespace) -> None:
meta = {}
if args.flake_uri:
meta["flake_uri"] = args.flake_uri
if args.flake_attr:
meta["flake_attr"] = args.flake_attr
deploy_nixos(HostGroup([Host(args.host, user=args.user, meta=meta)]))
def register_update_parser(parser: argparse.ArgumentParser) -> None:
# TODO pass all args we don't parse into ssh_args, currently it fails if arg starts with -
parser.add_argument("--flake-uri", type=str, default=".#", help="nix flake uri")
parser.add_argument(
"--flake-attr", type=str, help="nixos configuration in the flake"
)
parser.add_argument("--user", type=str, default="root")
parser.add_argument("host", type=str)
parser.set_defaults(func=update)