Compare commits
2 commits
d164f502a1
...
744bbdb245
Author | SHA1 | Date | |
---|---|---|---|
June | 744bbdb245 | ||
June | a7772aa154 |
|
@ -20,7 +20,7 @@ However to override aspects of the target host for specific or all hosts, infra-
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
infra-rebuild accepts optional configuration in a `deployment_configuration.json`. \
|
infra-rebuild accepts optional configuration in a `deployment_configuration.json` present in the flake repos root. \
|
||||||
The following keys are available to be set for configuring various aspects of deployment for specific or all hosts:
|
The following keys are available to be set for configuring various aspects of deployment for specific or all hosts:
|
||||||
|
|
||||||
- `default.targetPort`: A default port to use for connecting to all host.
|
- `default.targetPort`: A default port to use for connecting to all host.
|
||||||
|
|
|
@ -3,54 +3,118 @@ import click
|
||||||
from infra_rebuild import operations
|
from infra_rebuild import operations
|
||||||
|
|
||||||
reboot_option_help_text = "Reboot the target hosts after running the operation."
|
reboot_option_help_text = "Reboot the target hosts after running the operation."
|
||||||
|
flake_option_help_text = "URI of the flake to use. Defaults to the current direcory."
|
||||||
|
|
||||||
|
|
||||||
@click.group(context_settings={"help_option_names": ["-h", "--help"]}, invoke_without_command=True)
|
def initialize_recursive_option(ctx, option_name, default_value):
|
||||||
|
"""Helper function for initializing a recursive option.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
`ctx` -- The click context passed to the calling command.
|
||||||
|
`option_name` -- The name of the option in question.
|
||||||
|
`default_value` -- A default value for the option.
|
||||||
|
|
||||||
|
Simply sets the value of the recursive option (`ctx.obj[option_name]`) to `default_value`.
|
||||||
|
"""
|
||||||
|
ctx.obj[option_name] = default_value
|
||||||
|
|
||||||
|
|
||||||
|
def update_recursive_option(ctx, option_name, given_value):
|
||||||
|
"""Helper function for updating a recursive option.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
ctx -- The click context passed to the calling command.
|
||||||
|
option_name -- The name of the option in question.
|
||||||
|
given_value -- The value the calling command received for the option.
|
||||||
|
|
||||||
|
It overrides the current value for the recursive option (`ctx.obj[option_name]`) with `given_value`, if `given_value` isn't `None`.
|
||||||
|
This ensure precedence of the innermost command (since the innermost command would call this function last).
|
||||||
|
""" # noqa: E501
|
||||||
|
if given_value is not None:
|
||||||
|
ctx.obj[option_name] = given_value
|
||||||
|
|
||||||
|
|
||||||
|
@click.group(
|
||||||
|
context_settings={"help_option_names": ["-h", "--help"]},
|
||||||
|
invoke_without_command=True,
|
||||||
|
help="""Runs COMMAND for each given host.
|
||||||
|
|
||||||
|
The commands mirror the operations of nixos-rebuild (with the exception of reboot, which is simply a convenience alias for "boot --reboot").
|
||||||
|
|
||||||
|
For commands acting remotely (boot, reboot, switch, test) infra-rebuild tries to be useful without any configuration by taking the FQDN from the hosts NixOS configuration as the target host.
|
||||||
|
However infra-rebuild also accepts configuration to override various aspects of the target host for specific or all hosts.
|
||||||
|
See the documentation on configuration for more information.""", # noqa: E501
|
||||||
|
)
|
||||||
@click.version_option(prog_name="infra-rebuild")
|
@click.version_option(prog_name="infra-rebuild")
|
||||||
def infra_rebuild():
|
@click.pass_context
|
||||||
pass
|
@click.option("--flake", help=flake_option_help_text)
|
||||||
|
def infra_rebuild(ctx, flake):
|
||||||
|
ctx.ensure_object(dict)
|
||||||
|
initialize_recursive_option(ctx, "flake", ".")
|
||||||
|
update_recursive_option(ctx, "flake", flake)
|
||||||
|
|
||||||
|
|
||||||
@infra_rebuild.command()
|
@infra_rebuild.command()
|
||||||
|
@click.pass_context
|
||||||
|
@click.option("--flake", help=flake_option_help_text)
|
||||||
@click.argument("hosts", nargs=-1)
|
@click.argument("hosts", nargs=-1)
|
||||||
def build(hosts):
|
def build(ctx, flake, hosts):
|
||||||
operations.run("build", hosts)
|
update_recursive_option(ctx, "flake", flake)
|
||||||
|
operations.run("build", hosts, ctx.obj["flake"])
|
||||||
|
|
||||||
|
|
||||||
@infra_rebuild.command()
|
@infra_rebuild.command()
|
||||||
|
@click.pass_context
|
||||||
|
@click.option("--flake", help=flake_option_help_text)
|
||||||
@click.argument("hosts", nargs=-1)
|
@click.argument("hosts", nargs=-1)
|
||||||
def build_vm(hosts):
|
def build_vm(ctx, flake, hosts):
|
||||||
operations.run("build-vm", hosts)
|
update_recursive_option(ctx, "flake", flake)
|
||||||
|
operations.run("build-vm", hosts, ctx.obj["flake"])
|
||||||
|
|
||||||
|
|
||||||
@infra_rebuild.command()
|
@infra_rebuild.command()
|
||||||
|
@click.pass_context
|
||||||
|
@click.option("--flake", help=flake_option_help_text)
|
||||||
@click.argument("hosts", nargs=-1)
|
@click.argument("hosts", nargs=-1)
|
||||||
def build_vm_with_bootloader(hosts):
|
def build_vm_with_bootloader(ctx, flake, hosts):
|
||||||
operations.run("build-vm-with-bootloader", hosts)
|
update_recursive_option(ctx, "flake", flake)
|
||||||
|
operations.run("build-vm-with-bootloader", hosts, ctx.obj["flake"])
|
||||||
|
|
||||||
|
|
||||||
@infra_rebuild.command()
|
@infra_rebuild.command()
|
||||||
|
@click.pass_context
|
||||||
|
@click.option("--flake", help=flake_option_help_text)
|
||||||
@click.option("--reboot", is_flag=True, help=reboot_option_help_text)
|
@click.option("--reboot", is_flag=True, help=reboot_option_help_text)
|
||||||
@click.argument("hosts", nargs=-1)
|
@click.argument("hosts", nargs=-1)
|
||||||
def switch(hosts, reboot):
|
def switch(ctx, flake, reboot, hosts):
|
||||||
operations.run("switch", hosts, reboot)
|
update_recursive_option(ctx, "flake", flake)
|
||||||
|
operations.run("switch", hosts, ctx.obj["flake"], reboot)
|
||||||
|
|
||||||
|
|
||||||
@infra_rebuild.command()
|
@infra_rebuild.command()
|
||||||
|
@click.pass_context
|
||||||
|
@click.option("--flake", help=flake_option_help_text)
|
||||||
@click.option("--reboot", is_flag=True, help=reboot_option_help_text)
|
@click.option("--reboot", is_flag=True, help=reboot_option_help_text)
|
||||||
@click.argument("hosts", nargs=-1)
|
@click.argument("hosts", nargs=-1)
|
||||||
def boot(hosts, reboot):
|
def boot(ctx, flake, reboot, hosts):
|
||||||
operations.run("boot", hosts, reboot)
|
update_recursive_option(ctx, "flake", flake)
|
||||||
|
operations.run("boot", hosts, ctx.obj["flake"], reboot)
|
||||||
|
|
||||||
|
|
||||||
@infra_rebuild.command()
|
@infra_rebuild.command()
|
||||||
|
@click.pass_context
|
||||||
|
@click.option("--flake", help=flake_option_help_text)
|
||||||
@click.option("--reboot", is_flag=True, help=reboot_option_help_text)
|
@click.option("--reboot", is_flag=True, help=reboot_option_help_text)
|
||||||
@click.argument("hosts", nargs=-1)
|
@click.argument("hosts", nargs=-1)
|
||||||
def test(hosts, reboot):
|
def test(ctx, flake, reboot, hosts):
|
||||||
operations.run("test", hosts, reboot)
|
update_recursive_option(ctx, "flake", flake)
|
||||||
|
operations.run("test", hosts, ctx.obj["flake"], reboot)
|
||||||
|
|
||||||
|
|
||||||
@infra_rebuild.command(short_help=" ", help="This operation is a convenience alias for boot --reboot.")
|
@infra_rebuild.command(short_help=" ", help="This operation is a convenience alias for boot --reboot.")
|
||||||
|
@click.pass_context
|
||||||
|
@click.option("--flake", help=flake_option_help_text)
|
||||||
@click.argument("hosts", nargs=-1)
|
@click.argument("hosts", nargs=-1)
|
||||||
def reboot(hosts):
|
def reboot(ctx, flake, hosts):
|
||||||
operations.run("boot", hosts, True)
|
update_recursive_option(ctx, "flake", flake)
|
||||||
|
operations.run("boot", hosts, ctx.obj["flake"], True)
|
||||||
|
|
|
@ -6,7 +6,27 @@ import sys
|
||||||
from infra_rebuild import msg
|
from infra_rebuild import msg
|
||||||
|
|
||||||
|
|
||||||
def run(operation, hosts, reboot=False): # noqa: FBT002 - having reboot as a Boolean positional argument is fine I think # fmt: skip
|
def run(operation, hosts, flake_uri, reboot=False): # noqa: FBT002 - having reboot as a Boolean positional argument is fine I think # fmt: skip
|
||||||
|
try:
|
||||||
|
flake_archive_json = subprocess.run(
|
||||||
|
["nix", "flake", "archive", "--json", f"{flake_uri}"], # noqa: S607, S603 - can't know what the users system looks like, maybe do some kind of validation for the flake_uri in the future?
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
check=True
|
||||||
|
) # fmt: skip
|
||||||
|
try:
|
||||||
|
flake_archive = json.loads(flake_archive_json.stdout)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
msg.error("Internal Error: Couldn't parse the output of \"nix flake archive\".")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if not flake_archive["path"]:
|
||||||
|
msg.error("Internal Error: The \"nix flake archive\" output doesn't include a path.")
|
||||||
|
sys.exit(1)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
msg.error("Error: Couldn't archive the provided flake.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
match operation:
|
match operation:
|
||||||
case "build" | "build-vm" | "build-vm-with-bootloader":
|
case "build" | "build-vm" | "build-vm-with-bootloader":
|
||||||
act_remotely = False
|
act_remotely = False
|
||||||
|
@ -22,23 +42,23 @@ def run(operation, hosts, reboot=False): # noqa: FBT002 - having reboot as a Bo
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if act_remotely:
|
if act_remotely:
|
||||||
remote(operation, host, reboot)
|
remote(operation, host, flake_archive, reboot)
|
||||||
else:
|
else:
|
||||||
local(operation, host)
|
local(operation, host, flake_archive)
|
||||||
|
|
||||||
|
|
||||||
def local(operation, host):
|
def local(operation, host, flake_archive):
|
||||||
msg.info(f"Running nixos-rebuild {operation} for {host}...")
|
msg.info(f"Running nixos-rebuild {operation} for {host}...")
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
["nixos-rebuild", operation, "--flake", f".#{host}"], # noqa: S607, S603 - can't know what the users system looks like, maybe do some kind of validation for the given host in the future?
|
["nixos-rebuild", operation, "--flake", f"{flake_archive['path']}#{host}"], # noqa: S607, S603 - can't know what the users system looks like, maybe do some kind of validation for the given host in the future?
|
||||||
check=False
|
check=False
|
||||||
) # fmt: skip
|
) # fmt: skip
|
||||||
|
|
||||||
|
|
||||||
def remote(operation, host, reboot=False): # noqa: FBT002 - having reboot as a Boolean positional argument is fine I think # fmt: skip
|
def remote(operation, host, flake_archive, reboot=False): # noqa: FBT002 - having reboot as a Boolean positional argument is fine I think # fmt: skip
|
||||||
config = None
|
config = None
|
||||||
try:
|
try:
|
||||||
with open("deployment_configuration.json") as config_file:
|
with open(f"{flake_archive['path']}/deployment_configuration.json") as config_file:
|
||||||
try:
|
try:
|
||||||
config = json.load(config_file)
|
config = json.load(config_file)
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
|
@ -62,7 +82,7 @@ def remote(operation, host, reboot=False): # noqa: FBT002 - having reboot as a
|
||||||
pass
|
pass
|
||||||
if not target_hostname:
|
if not target_hostname:
|
||||||
nix_config_fqdn = subprocess.run(
|
nix_config_fqdn = subprocess.run(
|
||||||
["nix", "eval", "--raw", f".#nixosConfigurations.{host}.config.networking.fqdn"], # noqa: S607, S603 - can't know what the users system looks like, maybe do some kind of validation for host in the future?
|
["nix", "eval", "--raw", f"{flake_archive['path']}#nixosConfigurations.{host}.config.networking.fqdn"], # noqa: S607, S603 - can't know what the users system looks like, maybe do some kind of validation for host in the future?
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
check=False,
|
check=False,
|
||||||
|
@ -119,7 +139,7 @@ def remote(operation, host, reboot=False): # noqa: FBT002 - having reboot as a
|
||||||
msg.info(f"Running nixos-rebuild {operation} for {host} on {target_host}...")
|
msg.info(f"Running nixos-rebuild {operation} for {host} on {target_host}...")
|
||||||
|
|
||||||
nixos_rebuild = subprocess.run(
|
nixos_rebuild = subprocess.run(
|
||||||
["nixos-rebuild", operation, "--flake", f".#{host}", "--target-host", target_host, "--use-substitutes", "--use-remote-sudo"], # noqa: S607, S603, E501 - can't know what the users system looks like, maybe do some kind of validation for the given host in the future?, not breaking up the command makes it more readable
|
["nixos-rebuild", operation, "--flake", f"{flake_archive['path']}#{host}", "--target-host", target_host, "--use-substitutes", "--use-remote-sudo"], # noqa: S607, S603, E501 - can't know what the users system looks like, maybe do some kind of validation for the given host in the future?, not breaking up the command makes it more readable
|
||||||
env=nixos_rebuild_env,
|
env=nixos_rebuild_env,
|
||||||
check=False,
|
check=False,
|
||||||
) # fmt: skip
|
) # fmt: skip
|
||||||
|
|
Loading…
Reference in a new issue