Compute: Add 'keypair create --type' parameter
Change-Id: I2d251e1b97fb9a8069431c867fb7fc5f42d1fd6e Story: 2002606 Task: 22225
This commit is contained in:
parent
a48c05b90a
commit
4855fef8b8
openstackclient
releasenotes/notes
@ -20,6 +20,7 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from novaclient import api_versions
|
||||||
from osc_lib.command import command
|
from osc_lib.command import command
|
||||||
from osc_lib import exceptions
|
from osc_lib import exceptions
|
||||||
from osc_lib import utils
|
from osc_lib import utils
|
||||||
@ -53,6 +54,15 @@ class CreateKeypair(command.ShowOne):
|
|||||||
help=_("Filename for private key to save. If not used, "
|
help=_("Filename for private key to save. If not used, "
|
||||||
"print private key in console.")
|
"print private key in console.")
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--type',
|
||||||
|
metavar='<type>',
|
||||||
|
choices=['ssh', 'x509'],
|
||||||
|
help=_(
|
||||||
|
"Keypair type. Can be ssh or x509. "
|
||||||
|
"(Supported by API versions '2.2' - '2.latest')"
|
||||||
|
),
|
||||||
|
)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
@ -70,17 +80,28 @@ class CreateKeypair(command.ShowOne):
|
|||||||
"exception": e}
|
"exception": e}
|
||||||
)
|
)
|
||||||
|
|
||||||
keypair = compute_client.keypairs.create(
|
kwargs = {
|
||||||
parsed_args.name,
|
'name': parsed_args.name,
|
||||||
public_key=public_key,
|
'public_key': public_key,
|
||||||
)
|
}
|
||||||
|
if parsed_args.type:
|
||||||
|
if compute_client.api_version < api_versions.APIVersion('2.2'):
|
||||||
|
msg = _(
|
||||||
|
'--os-compute-api-version 2.2 or greater is required to '
|
||||||
|
'support the --type option.'
|
||||||
|
)
|
||||||
|
raise exceptions.CommandError(msg)
|
||||||
|
|
||||||
|
kwargs['key_type'] = parsed_args.type
|
||||||
|
|
||||||
|
keypair = compute_client.keypairs.create(**kwargs)
|
||||||
|
|
||||||
private_key = parsed_args.private_key
|
private_key = parsed_args.private_key
|
||||||
# Save private key into specified file
|
# Save private key into specified file
|
||||||
if private_key:
|
if private_key:
|
||||||
try:
|
try:
|
||||||
with io.open(
|
with io.open(
|
||||||
os.path.expanduser(parsed_args.private_key), 'w+'
|
os.path.expanduser(parsed_args.private_key), 'w+'
|
||||||
) as p:
|
) as p:
|
||||||
p.write(keypair.private_key)
|
p.write(keypair.private_key)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
@ -150,10 +171,13 @@ class ListKeypair(command.Lister):
|
|||||||
)
|
)
|
||||||
data = compute_client.keypairs.list()
|
data = compute_client.keypairs.list()
|
||||||
|
|
||||||
return (columns,
|
if compute_client.api_version >= api_versions.APIVersion('2.2'):
|
||||||
(utils.get_item_properties(
|
columns += ("Type", )
|
||||||
s, columns,
|
|
||||||
) for s in data))
|
return (
|
||||||
|
columns,
|
||||||
|
(utils.get_item_properties(s, columns) for s in data),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ShowKeypair(command.ShowOne):
|
class ShowKeypair(command.ShowOne):
|
||||||
|
@ -877,6 +877,7 @@ class FakeKeypair(object):
|
|||||||
# Set default attributes.
|
# Set default attributes.
|
||||||
keypair_info = {
|
keypair_info = {
|
||||||
'name': 'keypair-name-' + uuid.uuid4().hex,
|
'name': 'keypair-name-' + uuid.uuid4().hex,
|
||||||
|
'type': 'ssh',
|
||||||
'fingerprint': 'dummy',
|
'fingerprint': 'dummy',
|
||||||
'public_key': 'dummy',
|
'public_key': 'dummy',
|
||||||
'user_id': 'user'
|
'user_id': 'user'
|
||||||
|
@ -17,6 +17,7 @@ from unittest import mock
|
|||||||
from unittest.mock import call
|
from unittest.mock import call
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
from novaclient import api_versions
|
||||||
from osc_lib import exceptions
|
from osc_lib import exceptions
|
||||||
from osc_lib import utils
|
from osc_lib import utils
|
||||||
|
|
||||||
@ -45,11 +46,13 @@ class TestKeypairCreate(TestKeypair):
|
|||||||
self.columns = (
|
self.columns = (
|
||||||
'fingerprint',
|
'fingerprint',
|
||||||
'name',
|
'name',
|
||||||
|
'type',
|
||||||
'user_id'
|
'user_id'
|
||||||
)
|
)
|
||||||
self.data = (
|
self.data = (
|
||||||
self.keypair.fingerprint,
|
self.keypair.fingerprint,
|
||||||
self.keypair.name,
|
self.keypair.name,
|
||||||
|
self.keypair.type,
|
||||||
self.keypair.user_id
|
self.keypair.user_id
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -71,7 +74,7 @@ class TestKeypairCreate(TestKeypair):
|
|||||||
columns, data = self.cmd.take_action(parsed_args)
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
self.keypairs_mock.create.assert_called_with(
|
self.keypairs_mock.create.assert_called_with(
|
||||||
self.keypair.name,
|
name=self.keypair.name,
|
||||||
public_key=None
|
public_key=None
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -87,6 +90,7 @@ class TestKeypairCreate(TestKeypair):
|
|||||||
self.data = (
|
self.data = (
|
||||||
self.keypair.fingerprint,
|
self.keypair.fingerprint,
|
||||||
self.keypair.name,
|
self.keypair.name,
|
||||||
|
self.keypair.type,
|
||||||
self.keypair.user_id
|
self.keypair.user_id
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -96,7 +100,7 @@ class TestKeypairCreate(TestKeypair):
|
|||||||
]
|
]
|
||||||
verifylist = [
|
verifylist = [
|
||||||
('public_key', self.keypair.public_key),
|
('public_key', self.keypair.public_key),
|
||||||
('name', self.keypair.name)
|
('name', self.keypair.name),
|
||||||
]
|
]
|
||||||
|
|
||||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
@ -109,8 +113,8 @@ class TestKeypairCreate(TestKeypair):
|
|||||||
columns, data = self.cmd.take_action(parsed_args)
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
self.keypairs_mock.create.assert_called_with(
|
self.keypairs_mock.create.assert_called_with(
|
||||||
self.keypair.name,
|
name=self.keypair.name,
|
||||||
public_key=self.keypair.public_key
|
public_key=self.keypair.public_key,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(self.columns, columns)
|
self.assertEqual(self.columns, columns)
|
||||||
@ -124,7 +128,7 @@ class TestKeypairCreate(TestKeypair):
|
|||||||
]
|
]
|
||||||
verifylist = [
|
verifylist = [
|
||||||
('private_key', tmp_pk_file),
|
('private_key', tmp_pk_file),
|
||||||
('name', self.keypair.name)
|
('name', self.keypair.name),
|
||||||
]
|
]
|
||||||
|
|
||||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
@ -136,8 +140,8 @@ class TestKeypairCreate(TestKeypair):
|
|||||||
columns, data = self.cmd.take_action(parsed_args)
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
self.keypairs_mock.create.assert_called_with(
|
self.keypairs_mock.create.assert_called_with(
|
||||||
self.keypair.name,
|
name=self.keypair.name,
|
||||||
public_key=None
|
public_key=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
mock_open.assert_called_once_with(tmp_pk_file, 'w+')
|
mock_open.assert_called_once_with(tmp_pk_file, 'w+')
|
||||||
@ -146,6 +150,79 @@ class TestKeypairCreate(TestKeypair):
|
|||||||
self.assertEqual(self.columns, columns)
|
self.assertEqual(self.columns, columns)
|
||||||
self.assertEqual(self.data, data)
|
self.assertEqual(self.data, data)
|
||||||
|
|
||||||
|
def test_keypair_create_with_key_type(self):
|
||||||
|
self.app.client_manager.compute.api_version = api_versions.APIVersion(
|
||||||
|
'2.2')
|
||||||
|
|
||||||
|
for key_type in ['x509', 'ssh']:
|
||||||
|
self.keypair = compute_fakes.FakeKeypair.create_one_keypair(
|
||||||
|
no_pri=True)
|
||||||
|
self.keypairs_mock.create.return_value = self.keypair
|
||||||
|
|
||||||
|
self.data = (
|
||||||
|
self.keypair.fingerprint,
|
||||||
|
self.keypair.name,
|
||||||
|
self.keypair.type,
|
||||||
|
self.keypair.user_id,
|
||||||
|
)
|
||||||
|
arglist = [
|
||||||
|
'--public-key', self.keypair.public_key,
|
||||||
|
self.keypair.name,
|
||||||
|
'--type', key_type,
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('public_key', self.keypair.public_key),
|
||||||
|
('name', self.keypair.name),
|
||||||
|
('type', key_type),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
with mock.patch('io.open') as mock_open:
|
||||||
|
mock_open.return_value = mock.MagicMock()
|
||||||
|
m_file = mock_open.return_value.__enter__.return_value
|
||||||
|
m_file.read.return_value = 'dummy'
|
||||||
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
self.keypairs_mock.create.assert_called_with(
|
||||||
|
name=self.keypair.name,
|
||||||
|
public_key=self.keypair.public_key,
|
||||||
|
key_type=key_type,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(self.columns, columns)
|
||||||
|
self.assertEqual(self.data, data)
|
||||||
|
|
||||||
|
def test_keypair_create_with_key_type_pre_v22(self):
|
||||||
|
self.app.client_manager.compute.api_version = api_versions.APIVersion(
|
||||||
|
'2.1')
|
||||||
|
|
||||||
|
for key_type in ['x509', 'ssh']:
|
||||||
|
arglist = [
|
||||||
|
'--public-key', self.keypair.public_key,
|
||||||
|
self.keypair.name,
|
||||||
|
'--type', 'ssh',
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('public_key', self.keypair.public_key),
|
||||||
|
('name', self.keypair.name),
|
||||||
|
('type', 'ssh'),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
with mock.patch('io.open') as mock_open:
|
||||||
|
mock_open.return_value = mock.MagicMock()
|
||||||
|
m_file = mock_open.return_value.__enter__.return_value
|
||||||
|
m_file.read.return_value = 'dummy'
|
||||||
|
|
||||||
|
ex = self.assertRaises(
|
||||||
|
exceptions.CommandError,
|
||||||
|
self.cmd.take_action,
|
||||||
|
parsed_args)
|
||||||
|
|
||||||
|
self.assertIn(
|
||||||
|
'--os-compute-api-version 2.2 or greater is required',
|
||||||
|
str(ex))
|
||||||
|
|
||||||
|
|
||||||
class TestKeypairDelete(TestKeypair):
|
class TestKeypairDelete(TestKeypair):
|
||||||
|
|
||||||
@ -227,16 +304,6 @@ class TestKeypairList(TestKeypair):
|
|||||||
# Return value of self.keypairs_mock.list().
|
# Return value of self.keypairs_mock.list().
|
||||||
keypairs = compute_fakes.FakeKeypair.create_keypairs(count=1)
|
keypairs = compute_fakes.FakeKeypair.create_keypairs(count=1)
|
||||||
|
|
||||||
columns = (
|
|
||||||
"Name",
|
|
||||||
"Fingerprint"
|
|
||||||
)
|
|
||||||
|
|
||||||
data = ((
|
|
||||||
keypairs[0].name,
|
|
||||||
keypairs[0].fingerprint
|
|
||||||
), )
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestKeypairList, self).setUp()
|
super(TestKeypairList, self).setUp()
|
||||||
|
|
||||||
@ -247,8 +314,7 @@ class TestKeypairList(TestKeypair):
|
|||||||
|
|
||||||
def test_keypair_list_no_options(self):
|
def test_keypair_list_no_options(self):
|
||||||
arglist = []
|
arglist = []
|
||||||
verifylist = [
|
verifylist = []
|
||||||
]
|
|
||||||
|
|
||||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
@ -261,8 +327,39 @@ class TestKeypairList(TestKeypair):
|
|||||||
|
|
||||||
self.keypairs_mock.list.assert_called_with()
|
self.keypairs_mock.list.assert_called_with()
|
||||||
|
|
||||||
self.assertEqual(self.columns, columns)
|
self.assertEqual(('Name', 'Fingerprint'), columns)
|
||||||
self.assertEqual(tuple(self.data), tuple(data))
|
self.assertEqual(
|
||||||
|
((self.keypairs[0].name, self.keypairs[0].fingerprint), ),
|
||||||
|
tuple(data)
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_keypair_list_v22(self):
|
||||||
|
self.app.client_manager.compute.api_version = api_versions.APIVersion(
|
||||||
|
'2.2')
|
||||||
|
|
||||||
|
arglist = []
|
||||||
|
verifylist = []
|
||||||
|
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
# In base command class Lister in cliff, abstract method take_action()
|
||||||
|
# returns a tuple containing the column names and an iterable
|
||||||
|
# containing the data to be listed.
|
||||||
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
# Set expected values
|
||||||
|
|
||||||
|
self.keypairs_mock.list.assert_called_with()
|
||||||
|
|
||||||
|
self.assertEqual(('Name', 'Fingerprint', 'Type'), columns)
|
||||||
|
self.assertEqual(
|
||||||
|
((
|
||||||
|
self.keypairs[0].name,
|
||||||
|
self.keypairs[0].fingerprint,
|
||||||
|
self.keypairs[0].type,
|
||||||
|
), ),
|
||||||
|
tuple(data)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestKeypairShow(TestKeypair):
|
class TestKeypairShow(TestKeypair):
|
||||||
@ -279,16 +376,18 @@ class TestKeypairShow(TestKeypair):
|
|||||||
self.columns = (
|
self.columns = (
|
||||||
"fingerprint",
|
"fingerprint",
|
||||||
"name",
|
"name",
|
||||||
|
"type",
|
||||||
"user_id"
|
"user_id"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.data = (
|
self.data = (
|
||||||
self.keypair.fingerprint,
|
self.keypair.fingerprint,
|
||||||
self.keypair.name,
|
self.keypair.name,
|
||||||
|
self.keypair.type,
|
||||||
self.keypair.user_id
|
self.keypair.user_id
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_show_no_options(self):
|
def test_keypair_show_no_options(self):
|
||||||
|
|
||||||
arglist = []
|
arglist = []
|
||||||
verifylist = []
|
verifylist = []
|
||||||
@ -306,6 +405,7 @@ class TestKeypairShow(TestKeypair):
|
|||||||
self.data = (
|
self.data = (
|
||||||
self.keypair.fingerprint,
|
self.keypair.fingerprint,
|
||||||
self.keypair.name,
|
self.keypair.name,
|
||||||
|
self.keypair.type,
|
||||||
self.keypair.user_id
|
self.keypair.user_id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Add ``--key-type`` option to ``keypair create`` command to set keypair
|
||||||
|
type. Can be ssh or x509. Note that ``--os-compute-api-version 2.2`` or
|
||||||
|
later is required.
|
Loading…
x
Reference in New Issue
Block a user