Support --remote-ssh-config [path-to-ssh-config] as an argument in case extra params are required beyond --remote-port or --remote-user.
Note: `--remote-host` must still be set, but it can be an 'alias' represented by the 'Host' value in the ssh config.
This commit is contained in:
parent
5754ef1aad
commit
f5eaac9f75
6 changed files with 110 additions and 14 deletions
|
|
@ -1,3 +1,7 @@
|
|||
# 0.4.2
|
||||
|
||||
* Support `--remote-ssh-config [path-to-ssh-config]` as an argument in case extra params are required beyond `--remote-port` or `--remote-user`. Note: `--remote-host` must still be set, but it can be an 'alias' represented by the 'Host' value in the ssh config.
|
||||
|
||||
# 0.4.1
|
||||
|
||||
* Add interactive output when 'enroll diff --enforce' is invoking Ansible.
|
||||
|
|
|
|||
6
debian/changelog
vendored
6
debian/changelog
vendored
|
|
@ -1,3 +1,9 @@
|
|||
enroll (0.4.2) unstable; urgency=medium
|
||||
|
||||
* Support `--remote-ssh-config [path-to-ssh-config]` as an argument in case extra params are required beyond `--remote-port` or `--remote-user`. Note: `--remote-host` must still be set, but it can be an 'alias' represented by the 'Host' value in the ssh config.
|
||||
|
||||
-- Miguel Jacq <mig@mig5.net> Tue, 13 Jan 2026 21:55:00 +1100
|
||||
|
||||
enroll (0.4.1) unstable; urgency=medium
|
||||
* Add interactive output when 'enroll diff --enforce' is invoking Ansible.
|
||||
|
||||
|
|
|
|||
|
|
@ -350,16 +350,33 @@ def _add_remote_args(p: argparse.ArgumentParser) -> None:
|
|||
"--remote-host",
|
||||
help="SSH host to run harvesting on (if set, harvest runs remotely and is pulled locally).",
|
||||
)
|
||||
p.add_argument(
|
||||
"--remote-ssh-config",
|
||||
nargs="?",
|
||||
const=str(Path.home() / ".ssh" / "config"),
|
||||
default=None,
|
||||
help=(
|
||||
"Use OpenSSH-style ssh_config settings for --remote-host. "
|
||||
"If provided without a value, defaults to ~/.ssh/config. "
|
||||
"(Applies HostName/User/Port/IdentityFile/ProxyCommand/HostKeyAlias when supported.)"
|
||||
),
|
||||
)
|
||||
p.add_argument(
|
||||
"--remote-port",
|
||||
type=int,
|
||||
default=22,
|
||||
help="SSH port for --remote-host (default: 22).",
|
||||
default=None,
|
||||
help=(
|
||||
"SSH port for --remote-host. If omitted, defaults to 22, or a value from ssh_config when "
|
||||
"--remote-ssh-config is set."
|
||||
),
|
||||
)
|
||||
p.add_argument(
|
||||
"--remote-user",
|
||||
default=os.environ.get("USER") or None,
|
||||
help="SSH username for --remote-host (default: local $USER).",
|
||||
default=None,
|
||||
help=(
|
||||
"SSH username for --remote-host. If omitted, defaults to local $USER, or a value from ssh_config when "
|
||||
"--remote-ssh-config is set."
|
||||
),
|
||||
)
|
||||
|
||||
# Align terminology with Ansible: "become" == sudo.
|
||||
|
|
@ -728,6 +745,17 @@ def main() -> None:
|
|||
)
|
||||
args = ap.parse_args(argv)
|
||||
|
||||
# Preserve historical defaults for remote harvesting unless ssh_config lookup is enabled.
|
||||
# This lets ssh_config values take effect when the user did not explicitly set
|
||||
# --remote-user / --remote-port.
|
||||
if hasattr(args, "remote_host"):
|
||||
rsc = getattr(args, "remote_ssh_config", None)
|
||||
if not rsc:
|
||||
if getattr(args, "remote_port", None) is None:
|
||||
setattr(args, "remote_port", 22)
|
||||
if getattr(args, "remote_user", None) is None:
|
||||
setattr(args, "remote_user", os.environ.get("USER") or None)
|
||||
|
||||
try:
|
||||
if args.cmd == "harvest":
|
||||
sops_fps = getattr(args, "sops", None)
|
||||
|
|
@ -745,8 +773,9 @@ def main() -> None:
|
|||
ask_become_pass=args.ask_become_pass,
|
||||
local_out_dir=tmp_bundle,
|
||||
remote_host=args.remote_host,
|
||||
remote_port=int(args.remote_port),
|
||||
remote_port=args.remote_port,
|
||||
remote_user=args.remote_user,
|
||||
remote_ssh_config=args.remote_ssh_config,
|
||||
dangerous=bool(args.dangerous),
|
||||
no_sudo=bool(args.no_sudo),
|
||||
include_paths=list(getattr(args, "include_path", []) or []),
|
||||
|
|
@ -766,8 +795,9 @@ def main() -> None:
|
|||
ask_become_pass=args.ask_become_pass,
|
||||
local_out_dir=out_dir,
|
||||
remote_host=args.remote_host,
|
||||
remote_port=int(args.remote_port),
|
||||
remote_port=args.remote_port,
|
||||
remote_user=args.remote_user,
|
||||
remote_ssh_config=args.remote_ssh_config,
|
||||
dangerous=bool(args.dangerous),
|
||||
no_sudo=bool(args.no_sudo),
|
||||
include_paths=list(getattr(args, "include_path", []) or []),
|
||||
|
|
@ -968,8 +998,9 @@ def main() -> None:
|
|||
ask_become_pass=args.ask_become_pass,
|
||||
local_out_dir=tmp_bundle,
|
||||
remote_host=args.remote_host,
|
||||
remote_port=int(args.remote_port),
|
||||
remote_port=args.remote_port,
|
||||
remote_user=args.remote_user,
|
||||
remote_ssh_config=args.remote_ssh_config,
|
||||
dangerous=bool(args.dangerous),
|
||||
no_sudo=bool(args.no_sudo),
|
||||
include_paths=list(getattr(args, "include_path", []) or []),
|
||||
|
|
@ -998,8 +1029,9 @@ def main() -> None:
|
|||
ask_become_pass=args.ask_become_pass,
|
||||
local_out_dir=harvest_dir,
|
||||
remote_host=args.remote_host,
|
||||
remote_port=int(args.remote_port),
|
||||
remote_port=args.remote_port,
|
||||
remote_user=args.remote_user,
|
||||
remote_ssh_config=args.remote_ssh_config,
|
||||
dangerous=bool(args.dangerous),
|
||||
no_sudo=bool(args.no_sudo),
|
||||
include_paths=list(getattr(args, "include_path", []) or []),
|
||||
|
|
|
|||
|
|
@ -330,8 +330,9 @@ def _remote_harvest(
|
|||
*,
|
||||
local_out_dir: Path,
|
||||
remote_host: str,
|
||||
remote_port: int = 22,
|
||||
remote_port: Optional[int] = None,
|
||||
remote_user: Optional[str] = None,
|
||||
remote_ssh_config: Optional[str] = None,
|
||||
remote_python: str = "python3",
|
||||
dangerous: bool = False,
|
||||
no_sudo: bool = False,
|
||||
|
|
@ -370,10 +371,60 @@ def _remote_harvest(
|
|||
# Users should add the key to known_hosts.
|
||||
ssh.set_missing_host_key_policy(paramiko.RejectPolicy())
|
||||
|
||||
# Resolve SSH connection parameters.
|
||||
connect_host = remote_host
|
||||
connect_port = int(remote_port) if remote_port is not None else 22
|
||||
connect_user = remote_user
|
||||
key_filename = None
|
||||
sock = None
|
||||
hostkey_name = connect_host
|
||||
|
||||
if remote_ssh_config:
|
||||
from paramiko.config import SSHConfig # type: ignore
|
||||
from paramiko.proxy import ProxyCommand # type: ignore
|
||||
import socket as _socket
|
||||
|
||||
cfg_path = Path(str(remote_ssh_config)).expanduser()
|
||||
if not cfg_path.exists():
|
||||
raise RuntimeError(f"SSH config file not found: {cfg_path}")
|
||||
|
||||
cfg = SSHConfig()
|
||||
with cfg_path.open("r", encoding="utf-8") as _fp:
|
||||
cfg.parse(_fp)
|
||||
hcfg = cfg.lookup(remote_host)
|
||||
|
||||
connect_host = str(hcfg.get("hostname") or remote_host)
|
||||
hostkey_name = str(hcfg.get("hostkeyalias") or connect_host)
|
||||
|
||||
if remote_port is None and hcfg.get("port"):
|
||||
try:
|
||||
connect_port = int(str(hcfg.get("port")))
|
||||
except ValueError:
|
||||
pass
|
||||
if connect_user is None and hcfg.get("user"):
|
||||
connect_user = str(hcfg.get("user"))
|
||||
|
||||
ident = hcfg.get("identityfile")
|
||||
if ident:
|
||||
if isinstance(ident, (list, tuple)):
|
||||
key_filename = [str(Path(p).expanduser()) for p in ident]
|
||||
else:
|
||||
key_filename = str(Path(str(ident)).expanduser())
|
||||
|
||||
proxycmd = hcfg.get("proxycommand")
|
||||
if proxycmd:
|
||||
sock = ProxyCommand(str(proxycmd))
|
||||
elif hostkey_name != connect_host:
|
||||
# If HostKeyAlias is used, connect to HostName via a socket but
|
||||
# use HostKeyAlias for known_hosts lookups.
|
||||
sock = _socket.create_connection((connect_host, connect_port))
|
||||
|
||||
ssh.connect(
|
||||
hostname=remote_host,
|
||||
port=int(remote_port),
|
||||
username=remote_user,
|
||||
hostname=hostkey_name if sock is not None else connect_host,
|
||||
port=connect_port,
|
||||
username=connect_user,
|
||||
key_filename=key_filename,
|
||||
sock=sock,
|
||||
allow_agent=True,
|
||||
look_for_keys=True,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[tool.poetry]
|
||||
name = "enroll"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
description = "Enroll a server's running state retrospectively into Ansible"
|
||||
authors = ["Miguel Jacq <mig@mig5.net>"]
|
||||
license = "GPL-3.0-or-later"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
%global upstream_version 0.4.1
|
||||
%global upstream_version 0.4.2
|
||||
|
||||
Name: enroll
|
||||
Version: %{upstream_version}
|
||||
|
|
@ -43,6 +43,9 @@ Enroll a server's running state retrospectively into Ansible.
|
|||
%{_bindir}/enroll
|
||||
|
||||
%changelog
|
||||
* Tue Jan 13 2026 Miguel Jacq <mig@mig5.net> - %{version}-%{release}
|
||||
- Support `--remote-ssh-config [path-to-ssh-config]` as an argument in case extra params are required beyond `--remote-port` or `--remote-user`. Note: `--remote-host` must still be s
|
||||
et, but it can be an 'alias' represented by the 'Host' value in the ssh config.
|
||||
* Sun Jan 11 2026 Miguel Jacq <mig@mig5.net> - %{version}-%{release}
|
||||
- Add interactive output when 'enroll diff --enforce' is invoking Ansible.
|
||||
* Sat Jan 10 2026 Miguel Jacq <mig@mig5.net> - %{version}-%{release}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue