Skip to content

Commit 6a0187d

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "compute: Pass through args to ssh"
2 parents ba93559 + 3a92961 commit 6a0187d

3 files changed

Lines changed: 115 additions & 25 deletions

File tree

openstackclient/compute/v2/server.py

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4461,26 +4461,30 @@ def get_parser(self, prog_name):
44614461
metavar='<server>',
44624462
help=_('Server (name or ID)'),
44634463
)
4464+
# Deprecated during the Yoga cycle
44644465
parser.add_argument(
44654466
'--login', '-l',
44664467
metavar='<login-name>',
4467-
help=_('Login name (ssh -l option)'),
4468+
help=argparse.SUPPRESS,
44684469
)
4470+
# Deprecated during the Yoga cycle
44694471
parser.add_argument(
44704472
'--port', '-p',
44714473
metavar='<port>',
44724474
type=int,
4473-
help=_('Destination port (ssh -p option)'),
4475+
help=argparse.SUPPRESS,
44744476
)
4477+
# Deprecated during the Yoga cycle
44754478
parser.add_argument(
44764479
'--identity', '-i',
44774480
metavar='<keyfile>',
4478-
help=_('Private key file (ssh -i option)'),
4481+
help=argparse.SUPPRESS,
44794482
)
4483+
# Deprecated during the Yoga cycle
44804484
parser.add_argument(
44814485
'--option', '-o',
44824486
metavar='<config-options>',
4483-
help=_('Options in ssh_config(5) format (ssh -o option)'),
4487+
help=argparse.SUPPRESS,
44844488
)
44854489
ip_group = parser.add_mutually_exclusive_group()
44864490
ip_group.add_argument(
@@ -4521,53 +4525,85 @@ def get_parser(self, prog_name):
45214525
default='public',
45224526
help=_('Use other IP address (public, private, etc)'),
45234527
)
4528+
# Deprecated during the Yoga cycle
45244529
parser.add_argument(
45254530
'-v',
45264531
dest='verbose',
45274532
action='store_true',
45284533
default=False,
45294534
help=argparse.SUPPRESS,
45304535
)
4536+
parser.add_argument(
4537+
'ssh_args',
4538+
nargs='*',
4539+
metavar='-- <standard ssh args>',
4540+
help=(
4541+
'Any argument or option that ssh allows. '
4542+
'Use -- once between openstackclient args and SSH args.'
4543+
),
4544+
)
45314545
return parser
45324546

45334547
def take_action(self, parsed_args):
45344548

45354549
compute_client = self.app.client_manager.compute
4550+
45364551
server = utils.find_resource(
45374552
compute_client.servers,
45384553
parsed_args.server,
45394554
)
45404555

4541-
# Build the command
4542-
cmd = "ssh"
4556+
# first, handle the deprecated options
4557+
if any((
4558+
parsed_args.port,
4559+
parsed_args.identity,
4560+
parsed_args.option,
4561+
parsed_args.login,
4562+
parsed_args.verbose,
4563+
)):
4564+
msg = _(
4565+
'The ssh options have been deprecated. The ssh equivalent '
4566+
'options can be used instead as arguments after "--" on '
4567+
'the command line.'
4568+
)
4569+
self.log.warning(msg)
45434570

45444571
ip_address_family = [4, 6]
45454572
if parsed_args.ipv4:
45464573
ip_address_family = [4]
4547-
cmd += " -4"
45484574
if parsed_args.ipv6:
45494575
ip_address_family = [6]
4550-
cmd += " -6"
4576+
4577+
args = parsed_args.ssh_args[:]
45514578

45524579
if parsed_args.port:
4553-
cmd += " -p %d" % parsed_args.port
4580+
args.extend(['-p', str(parsed_args.port)])
4581+
45544582
if parsed_args.identity:
4555-
cmd += " -i %s" % parsed_args.identity
4583+
args.extend(['-i', parsed_args.identity])
4584+
45564585
if parsed_args.option:
4557-
cmd += " -o %s" % parsed_args.option
4586+
args.extend(['-o', parsed_args.option])
4587+
45584588
if parsed_args.login:
45594589
login = parsed_args.login
4560-
else:
4590+
args.extend(['-l', login])
4591+
elif '-l' not in args:
45614592
login = self.app.client_manager.auth_ref.username
4593+
args.extend(['-l', login])
4594+
45624595
if parsed_args.verbose:
4563-
cmd += " -v"
4564-
4565-
cmd += " %s@%s"
4566-
ip_address = _get_ip_address(server.addresses,
4567-
parsed_args.address_type,
4568-
ip_address_family)
4569-
LOG.debug("ssh command: %s", (cmd % (login, ip_address)))
4570-
os.system(cmd % (login, ip_address))
4596+
args.append('-v')
4597+
4598+
ip_address = _get_ip_address(
4599+
server.addresses,
4600+
parsed_args.address_type,
4601+
ip_address_family,
4602+
)
4603+
4604+
cmd = ' '.join(['ssh', ip_address] + args)
4605+
LOG.debug("ssh command: {cmd}".format(cmd=cmd))
4606+
os.system(cmd)
45714607

45724608

45734609
class StartServer(command.Command):

openstackclient/tests/unit/compute/v2/test_server.py

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8307,15 +8307,48 @@ def test_server_ssh_no_opts(self, mock_exec):
83078307
('ipv6', False),
83088308
('address_type', 'public'),
83098309
('verbose', False),
8310+
('ssh_args', []),
83108311
]
83118312
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
83128313

8313-
result = self.cmd.take_action(parsed_args)
8314+
with mock.patch.object(self.cmd.log, 'warning') as mock_warning:
8315+
result = self.cmd.take_action(parsed_args)
8316+
8317+
self.assertIsNone(result)
8318+
mock_exec.assert_called_once_with('ssh 192.168.1.30 -l cloud')
8319+
mock_warning.assert_not_called()
8320+
8321+
def test_server_ssh_passthrough_opts(self, mock_exec):
8322+
arglist = [
8323+
self.server.name,
8324+
'--',
8325+
'-l', 'username',
8326+
'-p', '2222',
8327+
]
8328+
verifylist = [
8329+
('server', self.server.name),
8330+
('login', None),
8331+
('port', None),
8332+
('identity', None),
8333+
('option', None),
8334+
('ipv4', False),
8335+
('ipv6', False),
8336+
('address_type', 'public'),
8337+
('verbose', False),
8338+
('ssh_args', ['-l', 'username', '-p', '2222']),
8339+
]
8340+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
8341+
8342+
with mock.patch.object(self.cmd.log, 'warning') as mock_warning:
8343+
result = self.cmd.take_action(parsed_args)
83148344

83158345
self.assertIsNone(result)
8316-
mock_exec.assert_called_once_with('ssh cloud@192.168.1.30')
8346+
mock_exec.assert_called_once_with(
8347+
'ssh 192.168.1.30 -l username -p 2222'
8348+
)
8349+
mock_warning.assert_not_called()
83178350

8318-
def test_server_ssh_opts(self, mock_exec):
8351+
def test_server_ssh_deprecated_opts(self, mock_exec):
83198352
arglist = [
83208353
self.server.name,
83218354
'-l', 'username',
@@ -8331,14 +8364,21 @@ def test_server_ssh_opts(self, mock_exec):
83318364
('ipv6', False),
83328365
('address_type', 'public'),
83338366
('verbose', False),
8367+
('ssh_args', []),
83348368
]
83358369
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
83368370

8337-
result = self.cmd.take_action(parsed_args)
8371+
with mock.patch.object(self.cmd.log, 'warning') as mock_warning:
8372+
result = self.cmd.take_action(parsed_args)
83388373

83398374
self.assertIsNone(result)
83408375
mock_exec.assert_called_once_with(
8341-
'ssh -p 2222 username@192.168.1.30'
8376+
'ssh 192.168.1.30 -p 2222 -l username'
8377+
)
8378+
mock_warning.assert_called_once()
8379+
self.assertIn(
8380+
'The ssh options have been deprecated.',
8381+
mock_warning.call_args[0][0],
83428382
)
83438383

83448384

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
features:
3+
- |
4+
Added the ability to pass arguments through to the ``ssh`` command When
5+
using ``openstack server ssh``. This allows the user to use any ``ssh``
6+
option without needing to add that option to the openstack client.
7+
Existing openstackclient options that mirror SSH options are now
8+
deprecated.
9+
deprecations:
10+
- |
11+
``openstack server ssh`` options that mirror ``ssh`` options are now
12+
deprecated (``--login, -l, --port, --identity, --option, -o, -vz``).
13+
The ``ssh`` equivalent of each deprecated option should be used instead.
14+
For example ``openstack server ssh instance -- -l user -i key``

0 commit comments

Comments
 (0)