Skip to content

Commit

Permalink
Add support for the SSH ControlPath connection sharing option (#713)
Browse files Browse the repository at this point in the history
OpenSSH multiplexing needs 3 configuration items:
* ControlMaster
* ControlPersist
* ControlPath

Testinfra uses only the first two and this causes that connection multiplexing is not used:

```
DEBUG    testinfra:base.py:288 RUN CommandResult(command=b'ssh -o ControlMaster=auto -o ControlPersist=1200 -o ServerAliveInterval=180 -o StrictHostKeyChecking=no -o User=<reducted> -i \'~/.ssh/<reducted>\' -o ConnectTimeout=10 <reducted> \'sudo /bin/sh -c \'"\'"\'<reducted>\'"\'"\'\'', exit_status=0, stdout=b'<reducted>', stderr=None)
```

In comparison, Ansible uses all 3 parameters:

```
SSH: EXEC ssh -o ControlMaster=auto -o ControlPersist=1200 -o ServerAliveInterval=180 -o StrictHostKeyChecking=no -o StrictHostKeyChecking=no -o 'IdentityFile="<reducted>"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o 'User="<reducted>"' -o ConnectTimeout=10 -o 'ControlPath="<reducted>/.ansible/cp/%C"' <reducted>
```

With this change the third option to control connection sharing is introduced.
  • Loading branch information
CarstenGrohmann authored Aug 24, 2023
1 parent a12badf commit 177947a
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 0 deletions.
8 changes: 8 additions & 0 deletions testinfra/backend/ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def __init__(
ssh_config: Optional[str] = None,
ssh_identity_file: Optional[str] = None,
timeout: int = 10,
controlpath: str = "",
controlpersist: int = 60,
ssh_extra_args: Optional[str] = None,
*args: Any,
Expand All @@ -36,6 +37,7 @@ def __init__(
self.ssh_config = ssh_config
self.ssh_identity_file = ssh_identity_file
self.timeout = int(timeout)
self.controlpath = controlpath
self.controlpersist = int(controlpersist)
self.ssh_extra_args = ssh_extra_args
super().__init__(self.host.name, *args, **kwargs)
Expand Down Expand Up @@ -75,6 +77,12 @@ def _build_ssh_command(self, command: str) -> tuple[list[str], list[str]]:
self.controlpersist
)
)
if (
"ControlMaster" in " ".join(cmd)
and self.controlpath
and ("controlpath" not in (self.ssh_extra_args or "").lower())
):
cmd.append("-o ControlPath={}".format(self.controlpath))
cmd.append("%s %s")
cmd_args.extend([self.host.name, command])
return cmd, cmd_args
Expand Down
10 changes: 10 additions & 0 deletions testinfra/utils/ansible_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,16 @@ def get_config(
]
).strip()

control_path = config.get("ssh_connection", "control_path", fallback="", raw=True)
if control_path:
directory = config.get(
"persistent_connection", "control_path_dir", fallback="~/.ansible/cp"
)
control_path = control_path % ({"directory": directory}) # noqa: S001
# restore original "%%"
control_path = control_path.replace("%", "%%")
kwargs["controlpath"] = control_path

spec = "{}://".format(connection)

# Fallback to user:password auth when identity file is not used
Expand Down

0 comments on commit 177947a

Please sign in to comment.