summaryrefslogtreecommitdiff
path: root/openstackclient
diff options
context:
space:
mode:
Diffstat (limited to 'openstackclient')
-rw-r--r--openstackclient/compute/v2/server.py76
-rw-r--r--openstackclient/tests/unit/compute/v2/test_server.py50
2 files changed, 101 insertions, 25 deletions
diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py
index 5c603d04..76f5ffd8 100644
--- a/openstackclient/compute/v2/server.py
+++ b/openstackclient/compute/v2/server.py
@@ -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
+ args.extend(['-l', login])
+
if parsed_args.verbose:
- cmd += " -v"
-
- cmd += " %s@%s"
- 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))
+ args.append('-v')
+
+ ip_address = _get_ip_address(
+ server.addresses,
+ parsed_args.address_type,
+ ip_address_family,
+ )
+
+ cmd = ' '.join(['ssh', ip_address] + args)
+ LOG.debug("ssh command: {cmd}".format(cmd=cmd))
+ os.system(cmd)
class StartServer(command.Command):
diff --git a/openstackclient/tests/unit/compute/v2/test_server.py b/openstackclient/tests/unit/compute/v2/test_server.py
index acff61e6..3f7ad04a 100644
--- a/openstackclient/tests/unit/compute/v2/test_server.py
+++ b/openstackclient/tests/unit/compute/v2/test_server.py
@@ -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)
- result = self.cmd.take_action(parsed_args)
+ 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 cloud')
+ mock_warning.assert_not_called()
+
+ 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 cloud@192.168.1.30')
+ mock_exec.assert_called_once_with(
+ 'ssh 192.168.1.30 -l username -p 2222'
+ )
+ mock_warning.assert_not_called()
- def test_server_ssh_opts(self, mock_exec):
+ 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)
- result = self.cmd.take_action(parsed_args)
+ 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],
)