compute: Pass through args to ssh

Why limit a user to preset ssh arguments? Capture them all and send
them along to ssh to deal with. This allows users to use the full range of
ssh arguments, including specifying a command to run on the
instance. For example:

  openstack server ssh -4 upg -- -l cirros -i ~/id_rsa_upg "date; uptime"

SSH arguments that openstackclient currently mirrors are deprecated
except for -4 and -6, as they are useful for retrieving the correct
instance IP.

Change-Id: Ia50786d5eee52688e180550fe16aeb8af610154b
Co-authored-by: Stephen Finucane <stephen@that.guru>
This commit is contained in:
Hugh Saunders 2016-11-25 11:44:13 +00:00 committed by Stephen Finucane
parent ba69870d86
commit 3a929611c0
3 changed files with 115 additions and 25 deletions

View File

@ -4461,26 +4461,30 @@ class SshServer(command.Command):
metavar='<server>',
help=_('Server (name or ID)'),
)
# Deprecated during the Yoga cycle
parser.add_argument(
'--login', '-l',
metavar='<login-name>',
help=_('Login name (ssh -l option)'),
help=argparse.SUPPRESS,
)
# Deprecated during the Yoga cycle
parser.add_argument(
'--port', '-p',
metavar='<port>',
type=int,
help=_('Destination port (ssh -p option)'),
help=argparse.SUPPRESS,
)
# Deprecated during the Yoga cycle
parser.add_argument(
'--identity', '-i',
metavar='<keyfile>',
help=_('Private key file (ssh -i option)'),
help=argparse.SUPPRESS,
)
# Deprecated during the Yoga cycle
parser.add_argument(
'--option', '-o',
metavar='<config-options>',
help=_('Options in ssh_config(5) format (ssh -o option)'),
help=argparse.SUPPRESS,
)
ip_group = parser.add_mutually_exclusive_group()
ip_group.add_argument(
@ -4521,6 +4525,7 @@ class SshServer(command.Command):
default='public',
help=_('Use other IP address (public, private, etc)'),
)
# Deprecated during the Yoga cycle
parser.add_argument(
'-v',
dest='verbose',
@ -4528,46 +4533,77 @@ class SshServer(command.Command):
default=False,
help=argparse.SUPPRESS,
)
parser.add_argument(
'ssh_args',
nargs='*',
metavar='-- <standard ssh args>',
help=(
'Any argument or option that ssh allows. '
'Use -- once between openstackclient args and SSH args.'
),
)
return parser
def take_action(self, parsed_args):
compute_client = self.app.client_manager.compute
server = utils.find_resource(
compute_client.servers,
parsed_args.server,
)
# Build the command
cmd = "ssh"
# first, handle the deprecated options
if any((
parsed_args.port,
parsed_args.identity,
parsed_args.option,
parsed_args.login,
parsed_args.verbose,
)):
msg = _(
'The ssh options have been deprecated. The ssh equivalent '
'options can be used instead as arguments after "--" on '
'the command line.'
)
self.log.warning(msg)
ip_address_family = [4, 6]
if parsed_args.ipv4:
ip_address_family = [4]
cmd += " -4"
if parsed_args.ipv6:
ip_address_family = [6]
cmd += " -6"
args = parsed_args.ssh_args[:]
if parsed_args.port:
cmd += " -p %d" % parsed_args.port
args.extend(['-p', str(parsed_args.port)])
if parsed_args.identity:
cmd += " -i %s" % parsed_args.identity
args.extend(['-i', parsed_args.identity])
if parsed_args.option:
cmd += " -o %s" % parsed_args.option
args.extend(['-o', parsed_args.option])
if parsed_args.login:
login = parsed_args.login
else:
args.extend(['-l', login])
elif '-l' not in args:
login = self.app.client_manager.auth_ref.username
if parsed_args.verbose:
cmd += " -v"
args.extend(['-l', login])
cmd += " %s@%s"
ip_address = _get_ip_address(server.addresses,
if parsed_args.verbose:
args.append('-v')
ip_address = _get_ip_address(
server.addresses,
parsed_args.address_type,
ip_address_family)
LOG.debug("ssh command: %s", (cmd % (login, ip_address)))
os.system(cmd % (login, ip_address))
ip_address_family,
)
cmd = ' '.join(['ssh', ip_address] + args)
LOG.debug("ssh command: {cmd}".format(cmd=cmd))
os.system(cmd)
class StartServer(command.Command):

View File

@ -8307,15 +8307,48 @@ class TestServerSsh(TestServer):
('ipv6', False),
('address_type', 'public'),
('verbose', False),
('ssh_args', []),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
with mock.patch.object(self.cmd.log, 'warning') as mock_warning:
result = self.cmd.take_action(parsed_args)
self.assertIsNone(result)
mock_exec.assert_called_once_with('ssh cloud@192.168.1.30')
mock_exec.assert_called_once_with('ssh 192.168.1.30 -l cloud')
mock_warning.assert_not_called()
def test_server_ssh_opts(self, mock_exec):
def test_server_ssh_passthrough_opts(self, mock_exec):
arglist = [
self.server.name,
'--',
'-l', 'username',
'-p', '2222',
]
verifylist = [
('server', self.server.name),
('login', None),
('port', None),
('identity', None),
('option', None),
('ipv4', False),
('ipv6', False),
('address_type', 'public'),
('verbose', False),
('ssh_args', ['-l', 'username', '-p', '2222']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
with mock.patch.object(self.cmd.log, 'warning') as mock_warning:
result = self.cmd.take_action(parsed_args)
self.assertIsNone(result)
mock_exec.assert_called_once_with(
'ssh 192.168.1.30 -l username -p 2222'
)
mock_warning.assert_not_called()
def test_server_ssh_deprecated_opts(self, mock_exec):
arglist = [
self.server.name,
'-l', 'username',
@ -8331,14 +8364,21 @@ class TestServerSsh(TestServer):
('ipv6', False),
('address_type', 'public'),
('verbose', False),
('ssh_args', []),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
with mock.patch.object(self.cmd.log, 'warning') as mock_warning:
result = self.cmd.take_action(parsed_args)
self.assertIsNone(result)
mock_exec.assert_called_once_with(
'ssh -p 2222 username@192.168.1.30'
'ssh 192.168.1.30 -p 2222 -l username'
)
mock_warning.assert_called_once()
self.assertIn(
'The ssh options have been deprecated.',
mock_warning.call_args[0][0],
)

View File

@ -0,0 +1,14 @@
---
features:
- |
Added the ability to pass arguments through to the ``ssh`` command When
using ``openstack server ssh``. This allows the user to use any ``ssh``
option without needing to add that option to the openstack client.
Existing openstackclient options that mirror SSH options are now
deprecated.
deprecations:
- |
``openstack server ssh`` options that mirror ``ssh`` options are now
deprecated (``--login, -l, --port, --identity, --option, -o, -vz``).
The ``ssh`` equivalent of each deprecated option should be used instead.
For example ``openstack server ssh instance -- -l user -i key``