clan-cli: Fix ignored debug flag in clan vms run, refactor Host.run to use RunOpts

This commit is contained in:
Qubasa
2024-12-03 16:01:51 +01:00
parent e0cedb956a
commit 570bceff4e
14 changed files with 92 additions and 151 deletions

View File

@@ -1,16 +1,15 @@
# Adapted from https://github.com/numtide/deploykit
import logging
import math
import os
import shlex
from dataclasses import dataclass, field
from pathlib import Path
from shlex import quote
from typing import IO, Any
from typing import Any
from clan_cli.cmd import CmdOut, Log, MsgColor, RunOpts, run
from clan_cli.cmd import CmdOut, RunOpts, run
from clan_cli.colors import AnsiColor
from clan_cli.errors import ClanError
from clan_cli.ssh.host_key import HostKeyCheck
cmdlog = logging.getLogger(__name__)
@@ -78,18 +77,11 @@ class Host:
def run(
self,
cmd: list[str],
stdout: IO[bytes] | None = None,
stderr: IO[bytes] | None = None,
opts: RunOpts | None = None,
become_root: bool = False,
extra_env: dict[str, str] | None = None,
cwd: None | Path = None,
check: bool = True,
timeout: float = math.inf,
verbose_ssh: bool = False,
tty: bool = False,
msg_color: MsgColor | None = None,
shell: bool = False,
log: Log = Log.BOTH,
verbose_ssh: bool = False,
) -> CmdOut:
"""
Command to run on the host via ssh
@@ -107,6 +99,16 @@ class Host:
for k, v in extra_env.items():
env_vars.append(f"{shlex.quote(k)}={shlex.quote(v)}")
if opts is None:
opts = RunOpts()
else:
opts.needs_user_terminal = True
opts.prefix = self.command_prefix
if opts.cwd is not None:
msg = "cwd is not supported for remote commands"
raise ClanError(msg)
# Build a pretty command for logging
displayed_cmd = ""
export_cmd = ""
@@ -124,8 +126,9 @@ class Host:
# Build the ssh command
bash_cmd = export_cmd
if shell:
if opts.shell:
bash_cmd += " ".join(cmd)
opts.shell = False
else:
bash_cmd += 'exec "$@"'
# FIXME we assume bash to be present here? Should be documented...
@@ -135,19 +138,6 @@ class Host:
f"{sudo}bash -c {quote(bash_cmd)} -- {' '.join(map(quote, cmd))}",
]
opts = RunOpts(
shell=False,
stdout=stdout,
stderr=stderr,
log=log,
cwd=cwd,
check=check,
prefix=self.command_prefix,
timeout=timeout,
msg_color=msg_color,
needs_user_terminal=True, # ssh asks for a password
)
# Run the ssh command
return run(ssh_cmd, opts)

View File

@@ -1,12 +1,10 @@
import logging
import math
from collections.abc import Callable
from dataclasses import dataclass
from pathlib import Path
from threading import Thread
from typing import IO, Any
from typing import Any
from clan_cli.cmd import Log, RunOpts
from clan_cli.cmd import RunOpts
from clan_cli.errors import ClanError
from clan_cli.ssh import T
from clan_cli.ssh.host import Host
@@ -42,8 +40,6 @@ class HostGroup:
verbose_ssh: bool = False,
tty: bool = False,
) -> None:
if extra_env is None:
extra_env = {}
try:
proc = host.run_local(
cmd,
@@ -57,37 +53,20 @@ class HostGroup:
def _run_remote(
self,
cmd: list[str],
opts: RunOpts,
host: Host,
results: Results,
stdout: IO[bytes] | None = None,
stderr: IO[bytes] | None = None,
extra_env: dict[str, str] | None = None,
cwd: None | str | Path = None,
check: bool = True,
verbose_ssh: bool = False,
timeout: float = math.inf,
tty: bool = False,
shell: bool = False,
log: Log = Log.BOTH,
) -> None:
if cwd is not None:
msg = "cwd is not supported for remote commands"
raise ClanError(msg)
if extra_env is None:
extra_env = {}
try:
proc = host.run(
cmd,
stdout=stdout,
stderr=stderr,
extra_env=extra_env,
cwd=cwd,
check=check,
verbose_ssh=verbose_ssh,
timeout=timeout,
opts=opts,
tty=tty,
shell=shell,
log=log,
)
results.append(HostResult(host, proc))
except Exception as e:
@@ -116,12 +95,12 @@ class HostGroup:
verbose_ssh: bool = False,
tty: bool = False,
) -> Results:
if opts is None:
opts = RunOpts()
if extra_env is None:
extra_env = {}
results: Results = []
threads = []
if opts is None:
opts = RunOpts()
for host in self.hosts:
if local:
thread = Thread(
@@ -143,16 +122,10 @@ class HostGroup:
"results": results,
"cmd": cmd,
"host": host,
"stdout": opts.stdout,
"stderr": opts.stderr,
"opts": opts,
"extra_env": extra_env,
"cwd": opts.cwd,
"check": opts.check,
"timeout": opts.timeout,
"verbose_ssh": verbose_ssh,
"tty": tty,
"shell": opts.shell,
"log": opts.log,
},
)
@@ -170,33 +143,17 @@ class HostGroup:
def run(
self,
cmd: list[str],
stdout: IO[bytes] | None = None,
stderr: IO[bytes] | None = None,
opts: RunOpts | None = None,
*,
extra_env: dict[str, str] | None = None,
cwd: None | Path = None,
check: bool = True,
verbose_ssh: bool = False,
timeout: float = math.inf,
tty: bool = False,
log: Log = Log.BOTH,
shell: bool = False,
) -> Results:
"""
Command to run on the remote host via ssh
@return a lists of tuples containing Host and the result of the command for this Host
"""
if extra_env is None:
extra_env = {}
opts = RunOpts(
shell=shell,
stdout=stdout,
stderr=stderr,
log=log,
timeout=timeout,
cwd=cwd,
check=check,
)
return self._run(
cmd,
opts,
@@ -208,31 +165,16 @@ class HostGroup:
def run_local(
self,
cmd: list[str],
stdout: IO[bytes] | None = None,
stderr: IO[bytes] | None = None,
opts: RunOpts | None = None,
*,
extra_env: dict[str, str] | None = None,
cwd: None | Path = None,
check: bool = True,
timeout: float = math.inf,
shell: bool = False,
log: Log = Log.BOTH,
) -> Results:
"""
Command to run locally for each host in the group in parallel
@return a lists of tuples containing Host and the result of the command for this Host
"""
if extra_env is None:
extra_env = {}
opts = RunOpts(
stdout=stdout,
stderr=stderr,
cwd=cwd,
check=check,
timeout=timeout,
shell=shell,
log=log,
)
return self._run(
cmd,
opts,

View File

@@ -62,7 +62,8 @@ def upload(
str(remote_dest),
";",
"mkdir",
f"--mode={dir_mode:o}",
"-m",
f"{dir_mode:o}",
"-p",
str(remote_dest),
"&&",