Merge pull request 'clan-cli: use automatic networking for vars upload and machines update' (#4792) from networking_4 into main

Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4792
This commit is contained in:
Mic92
2025-08-20 12:42:56 +00:00
8 changed files with 267 additions and 104 deletions

View File

@@ -442,17 +442,31 @@ Examples:
parser_network = subparsers.add_parser(
"network",
aliases=["net"],
# TODO: Add help="Manage networks" when network code is ready
# help="Manage networks",
help="Manage networks",
description="Manage networks",
epilog=(
"""
show information about configured networks
Manage and monitor network connections for machines.
Clan supports multiple network technologies (direct SSH, Tor, etc.) that can be
configured with different priorities. When connecting to a machine, Clan will:
1. Check for targetHost in inventory
2. Try configured networks by priority
3. Fall back to targetHost from machine config
Commands like 'ssh' and 'machines update' automatically use the best
available network connection unless overridden with --target-host.
Examples:
$ clan network list
Will list networks
List all configured networks and their peers
$ clan network ping machine1
Check connectivity to machine1 across all networks
$ clan network overview
Show complete network status and connectivity
"""
),
formatter_class=argparse.RawTextHelpFormatter,
@@ -495,7 +509,7 @@ For more detailed information, visit: {help_hyperlink("getting-started", "https:
register_common_flags(parser)
if argcomplete:
argcomplete.autocomplete(parser, exclude=["morph", "network", "net"])
argcomplete.autocomplete(parser, exclude=["morph"])
return parser

View File

@@ -12,6 +12,7 @@ from clan_lib.machines.list import instantiate_inventory_to_machines
from clan_lib.machines.machines import Machine
from clan_lib.machines.suggestions import validate_machine_names
from clan_lib.machines.update import run_machine_update
from clan_lib.network.network import get_best_remote
from clan_lib.nix import nix_config
from clan_lib.ssh.host import Host
from clan_lib.ssh.host_key import HostKeyCheck
@@ -27,6 +28,42 @@ from clan_cli.completions import (
log = logging.getLogger(__name__)
def run_update_with_network(
machine: Machine,
build_host: Remote | LocalHost | None,
upload_inputs: bool,
host_key_check: HostKeyCheck,
target_host_override: str | None = None,
) -> None:
"""Run machine update with proper network context handling.
If target_host_override is provided, use it directly.
Otherwise, use get_best_remote to establish network connection.
"""
if target_host_override:
# Direct connection without network context
target_host = Remote.from_ssh_uri(
machine_name=machine.name,
address=target_host_override,
).override(host_key_check=host_key_check)
run_machine_update(
machine=machine,
target_host=target_host,
build_host=build_host,
upload_inputs=upload_inputs,
)
else:
# Use network context
with get_best_remote(machine) as remote:
target_host = remote.override(host_key_check=host_key_check)
run_machine_update(
machine=machine,
target_host=target_host,
build_host=build_host,
upload_inputs=upload_inputs,
)
def requires_explicit_update(m: Machine) -> bool:
try:
if m.select("config.clan.deployment.requireExplicitUpdate"):
@@ -144,27 +181,19 @@ def update_command(args: argparse.Namespace) -> None:
).override(host_key_check=host_key_check)
else:
build_host = machine.build_host()
# Figure out the target host
if args.target_host:
target_host = Remote.from_ssh_uri(
machine_name=machine.name,
address=args.target_host,
).override(host_key_check=host_key_check)
else:
target_host = machine.target_host().override(
host_key_check=host_key_check
)
# run the update
# Schedule the update with network handling
runtime.async_run(
AsyncOpts(
tid=machine.name,
async_ctx=AsyncContext(prefix=machine.name),
),
run_machine_update,
run_update_with_network,
machine=machine,
target_host=target_host,
build_host=build_host,
upload_inputs=args.upload_inputs,
host_key_check=host_key_check,
target_host_override=args.target_host,
)
runtime.join_all()
runtime.check_all()

View File

@@ -5,6 +5,7 @@ from pathlib import Path
from clan_cli.completions import add_dynamic_completer, complete_machines
from clan_lib.flake import require_flake
from clan_lib.machines.machines import Machine
from clan_lib.network.network import get_best_remote
from clan_lib.ssh.host import Host
log = logging.getLogger(__name__)
@@ -32,7 +33,12 @@ def upload_command(args: argparse.Namespace) -> None:
populate_secret_vars(machine, directory)
return
with machine.target_host().host_connection() as host, host.become_root() as host:
# Use get_best_remote to handle networking
with (
get_best_remote(machine) as remote,
remote.host_connection() as host,
host.become_root() as host,
):
upload_secret_vars(machine, host)