clan-cli: Fix ignored debug flag in clan vms run, refactor Host.run to use RunOpts
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -62,7 +62,8 @@ def upload(
|
||||
str(remote_dest),
|
||||
";",
|
||||
"mkdir",
|
||||
f"--mode={dir_mode:o}",
|
||||
"-m",
|
||||
f"{dir_mode:o}",
|
||||
"-p",
|
||||
str(remote_dest),
|
||||
"&&",
|
||||
|
||||
Reference in New Issue
Block a user