Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add flag to enable login shells #828

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ backup_grace_period_in_days = 10
;cert_file = <Path of public key signed certificate file to use for authentication. The corresponding private key must also be provided via key_file parameter>
;keepalive_seconds = <seconds between ssh keepalive messages to the ssh server. Default to 60 seconds. Due to a limitation in parallel-ssh, if 'cert_file' is defined, then 'keepalive_seconds' will be ignored and no keep alive messages will be sent>
;use_pty = <Boolean: Allocates pseudo-terminal. Default to False. Useful if sudo settings require a tty>
; Enables the usage of a 'login' shell which, among other things, loads user's profile files.
;login_shell = False
[checks]
;health_check = <Which ports to check when verifying a node restored properly. Options are 'cql' (default), 'thrift', 'all'.>
Expand Down
2 changes: 2 additions & 0 deletions medusa-example.ini
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ use_sudo_for_restore = True
;key_file = <Path of SSH key for use for restoring clusters. Expected in PEM unencrypted format.>
;port = <SSH port for use for restoring clusters. Default to port 22.
;cert_file = <Path of public key signed certificate file to use for authentication. The corresponding private key must also be provided via key_file parameter>
; Enables the usage of a 'login' shell which, among other things, loads user's profile files.
;login_shell = False

[checks]
;health_check = <Which ports to check when verifying a node restored properly. Options are 'cql' (default), 'thrift', 'all'.>
Expand Down
5 changes: 3 additions & 2 deletions medusa/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@

SSHConfig = collections.namedtuple(
'SSHConfig',
['username', 'key_file', 'port', 'cert_file', 'use_pty', 'keepalive_seconds']
['username', 'key_file', 'port', 'cert_file', 'use_pty', 'keepalive_seconds', 'login_shell']
)

ChecksConfig = collections.namedtuple(
Expand Down Expand Up @@ -148,7 +148,8 @@ def _build_default_config():
'port': '22',
'cert_file': '',
'use_pty': 'False',
'keepalive_seconds': '60'
'keepalive_seconds': '60',
'login_shell': 'False'
}

config['checks'] = {
Expand Down
10 changes: 7 additions & 3 deletions medusa/orchestration.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def pssh_run(self, hosts, command, hosts_variables=None, ssh_client=None):
cert_file = self.config.ssh.cert_file if self.config.ssh.cert_file != '' else None
keepalive_seconds = int(self.config.ssh.keepalive_seconds)
use_pty = medusa.utils.evaluate_boolean(self.config.ssh.use_pty)
use_login_shell = medusa.utils.evaluate_boolean(self.config.ssh.login_shell)

if ssh_client is None:
if cert_file is None:
Expand Down Expand Up @@ -81,9 +82,12 @@ def pssh_run(self, hosts, command, hosts_variables=None, ssh_client=None):
pkey=pkey,
cert_file=cert_file)

logging.debug('Batch #{i}: Running "{command}" on nodes {hosts} parallelism of {pool_size}'
.format(i=i, command=command, hosts=parallel_hosts, pool_size=len(parallel_hosts)))
output = client.run_command(command, host_args=hosts_variables, use_pty=use_pty,
logging.debug(f'Batch #{i}: Running "{command}" nodes={parallel_hosts} parallelism={len(parallel_hosts)} '
f'login_shell={use_login_shell}')

shell = '$SHELL -cl' if use_login_shell else None

output = client.run_command(command, host_args=hosts_variables, use_pty=use_pty, shell=shell,
sudo=medusa.utils.evaluate_boolean(self.config.cassandra.use_sudo))
client.join(output)

Expand Down
19 changes: 15 additions & 4 deletions tests/orchestration_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ def _build_config_parser():
'port': '22',
'cert_file': '',
'keepalive_seconds': '60',
'use_pty': 'False'
'use_pty': 'False',
'login_shell': 'False',
}
return config

Expand All @@ -93,12 +94,16 @@ def test_pssh_with_sudo(self):
self.mock_pssh.run_command.return_value = output
assert self.orchestration.pssh_run(list(self.hosts.keys()), 'fake command',
ssh_client=self.fake_ssh_client_factory)
self.mock_pssh.run_command.assert_called_with('fake command', host_args=None, use_pty=False, sudo=True)
self.mock_pssh.run_command.assert_called_with(
'fake command',
host_args=None, use_pty=False, shell=None, sudo=True
)

def test_pssh_without_sudo(self):
"""Ensure that Parallel SSH honors configuration when we don't want to use sudo in commands"""
conf = self.config
conf['cassandra']['use_sudo'] = 'False'
conf['ssh']['login_shell'] = 'True'
medusa_conf = self._build_medusa_config(conf)
orchestration_no_sudo = Orchestration(medusa_conf)

Expand All @@ -107,7 +112,10 @@ def test_pssh_without_sudo(self):
assert orchestration_no_sudo.pssh_run(list(self.hosts.keys()), 'fake command',
ssh_client=self.fake_ssh_client_factory)

self.mock_pssh.run_command.assert_called_with('fake command', host_args=None, use_pty=False, sudo=False)
self.mock_pssh.run_command.assert_called_with(
'fake command',
host_args=None, use_pty=False, shell='$SHELL -cl', sudo=False
)

def test_pssh_run_failure(self):
"""Ensure that Parallel SSH detects a failed command on a host"""
Expand All @@ -120,7 +128,10 @@ def test_pssh_run_failure(self):
self.mock_pssh.run_command.return_value = output
assert not self.orchestration.pssh_run(list(self.hosts.keys()), 'fake command',
ssh_client=self.fake_ssh_client_factory)
self.mock_pssh.run_command.assert_called_with('fake command', host_args=None, use_pty=False, sudo=True)
self.mock_pssh.run_command.assert_called_with(
'fake command',
host_args=None, use_pty=False, shell=None, sudo=True
)


if __name__ == '__main__':
Expand Down
Loading