[microversions] Add support for 2.10

2.10 - Added user_id parameter to os-keypairs plugin, as well as a new
property in the request body, for the create operation. Administrators will
be able to list, get details and delete keypairs owned by users other than
themselves and to create new keypairs on behalf of their users.

Change-Id: I13ca3f8a4dd9cf11bec79966bb8a2ab48847be22
This commit is contained in:
Andrey Kurilin 2015-11-30 19:44:11 +02:00 committed by Andrey Kurilin
parent 96a7e1ddc4
commit 65658ed6fc
5 changed files with 194 additions and 4 deletions

View File

@ -25,4 +25,4 @@ API_MIN_VERSION = api_versions.APIVersion("2.1")
# when client supported the max version, and bumped sequentially, otherwise
# the client may break due to server side new version may include some
# backward incompatible change.
API_MAX_VERSION = api_versions.APIVersion("2.9")
API_MAX_VERSION = api_versions.APIVersion("2.10")

View File

@ -10,6 +10,9 @@
# License for the specific language governing permissions and limitations
# under the License.
import tempest_lib.cli.base
from novaclient.tests.functional import base
from novaclient.tests.functional.v2 import fake_crypto
from novaclient.tests.functional.v2.legacy import test_keypairs
@ -42,3 +45,77 @@ class TestKeypairsNovaClientV22(test_keypairs.TestKeypairsNovaClient):
keypair = self._test_import_keypair(fingerprint, key_type='x509',
pub_key=pub_key_file)
self.assertIn('x509', keypair)
class TestKeypairsNovaClientV210(base.ClientTestBase):
"""Keypairs functional tests for v2.10 nova-api microversion.
"""
COMPUTE_API_VERSION = "2.10"
def setUp(self):
super(TestKeypairsNovaClientV210, self).setUp()
user_name = self.name_generate("v2.10")
password = "password"
user = self.cli_clients.keystone(
"user-create --name %(name)s --pass %(pass)s --tenant %(tenant)s" %
{"name": user_name, "pass": password,
"tenant": self.cli_clients.tenant_name})
self.user_id = self._get_value_from_the_table(user, "id")
self.addCleanup(self.cli_clients.keystone,
"user-delete %s" % self.user_id)
self.cli_clients_2 = tempest_lib.cli.base.CLIClient(
username=user_name,
password=password,
tenant_name=self.cli_clients.tenant_name,
uri=self.cli_clients.uri,
cli_dir=self.cli_clients.cli_dir)
def another_nova(self, action, flags='', params='', fail_ok=False,
endpoint_type='publicURL', merge_stderr=False):
flags += " --os-compute-api-version %s " % self.COMPUTE_API_VERSION
return self.cli_clients_2.nova(action, flags, params, fail_ok,
endpoint_type, merge_stderr)
def test_create_and_list_keypair(self):
name = self.name_generate("v2_10")
self.nova("keypair-add %s --user %s" % (name, self.user_id))
self.addCleanup(self.another_nova, "keypair-delete %s" % name)
output = self.nova("keypair-list")
self.assertRaises(ValueError, self._get_value_from_the_table,
output, name)
output_1 = self.another_nova("keypair-list")
output_2 = self.nova("keypair-list --user %s" % self.user_id)
self.assertEqual(output_1, output_2)
# it should be table with one key-pair
self.assertEqual(name, self._get_column_value_from_single_row_table(
output_1, "Name"))
output_1 = self.another_nova("keypair-show %s " % name)
output_2 = self.nova("keypair-show --user %s %s" % (self.user_id,
name))
self.assertEqual(output_1, output_2)
self.assertEqual(self.user_id,
self._get_value_from_the_table(output_1, "user_id"))
def test_create_and_delete(self):
name = self.name_generate("v2_10")
def cleanup():
# We should check keypair existence and remove it from correct user
# if keypair is presented
o = self.another_nova("keypair-list")
if name in o:
self.another_nova("keypair-delete %s" % name)
self.nova("keypair-add %s --user %s" % (name, self.user_id))
self.addCleanup(cleanup)
output = self.another_nova("keypair-list")
self.assertEqual(name, self._get_column_value_from_single_row_table(
output, "Name"))
self.nova("keypair-delete %s --user %s " % (name, self.user_id))
output = self.another_nova("keypair-list")
self.assertRaises(
ValueError,
self._get_column_value_from_single_row_table, output, "Name")

View File

@ -2535,7 +2535,6 @@ class ShellTest(utils.TestCase):
5, # Not implemented when test added, should not apply to adds.
7, # doesn't require any changes in novaclient
9, # doesn't require any changes in novaclient
10, # Not implemented when test added, should not apply to adds.
])
versions_supported = set(range(0,
novaclient.API_MAX_VERSION.ver_minor + 1))

View File

@ -56,6 +56,7 @@ class KeypairManager(base.ManagerWithFind):
keypair_prefix = "os-keypairs"
is_alphanum_id_allowed = True
@api_versions.wraps("2.0", "2.9")
def get(self, keypair):
"""
Get a keypair.
@ -66,6 +67,20 @@ class KeypairManager(base.ManagerWithFind):
return self._get("/%s/%s" % (self.keypair_prefix, base.getid(keypair)),
"keypair")
@api_versions.wraps("2.10")
def get(self, keypair, user_id=None):
"""
Get a keypair.
:param keypair: The ID of the keypair to get.
:param user_id: Id of key-pair owner (Admin only).
:rtype: :class:`Keypair`
"""
query_string = "?user_id=%s" % user_id if user_id else ""
url = "/%s/%s%s" % (self.keypair_prefix, base.getid(keypair),
query_string)
return self._get(url, "keypair")
@api_versions.wraps("2.0", "2.1")
def create(self, name, public_key=None):
"""
@ -79,7 +94,7 @@ class KeypairManager(base.ManagerWithFind):
body['keypair']['public_key'] = public_key
return self._create('/%s' % self.keypair_prefix, body, 'keypair')
@api_versions.wraps("2.2")
@api_versions.wraps("2.2", "2.9")
def create(self, name, public_key=None, key_type="ssh"):
"""
Create a keypair
@ -94,6 +109,25 @@ class KeypairManager(base.ManagerWithFind):
body['keypair']['public_key'] = public_key
return self._create('/%s' % self.keypair_prefix, body, 'keypair')
@api_versions.wraps("2.10")
def create(self, name, public_key=None, key_type="ssh", user_id=None):
"""
Create a keypair
:param name: name for the keypair to create
:param public_key: existing public key to import
:param key_type: keypair type to create
:param user_id: user to add.
"""
body = {'keypair': {'name': name,
'type': key_type}}
if public_key:
body['keypair']['public_key'] = public_key
if user_id:
body['keypair']['user_id'] = user_id
return self._create('/%s' % self.keypair_prefix, body, 'keypair')
@api_versions.wraps("2.0", "2.9")
def delete(self, key):
"""
Delete a keypair
@ -102,8 +136,32 @@ class KeypairManager(base.ManagerWithFind):
"""
self._delete('/%s/%s' % (self.keypair_prefix, base.getid(key)))
@api_versions.wraps("2.10")
def delete(self, key, user_id=None):
"""
Delete a keypair
:param key: The :class:`Keypair` (or its ID) to delete.
:param user_id: Id of key-pair owner (Admin only).
"""
query_string = "?user_id=%s" % user_id if user_id else ""
url = '/%s/%s%s' % (self.keypair_prefix, base.getid(key), query_string)
self._delete(url)
@api_versions.wraps("2.0", "2.9")
def list(self):
"""
Get a list of keypairs.
"""
return self._list('/%s' % self.keypair_prefix, 'keypairs')
@api_versions.wraps("2.10")
def list(self, user_id=None):
"""
Get a list of keypairs.
:param user_id: Id of key-pairs owner (Admin only).
"""
query_string = "?user_id=%s" % user_id if user_id else ""
url = '/%s%s' % (self.keypair_prefix, query_string)
return self._list(url, 'keypairs')

View File

@ -2977,11 +2977,17 @@ def _keypair_create(cs, args, name, pub_key):
return cs.keypairs.create(name, pub_key)
@api_versions.wraps("2.2")
@api_versions.wraps("2.2", "2.9")
def _keypair_create(cs, args, name, pub_key):
return cs.keypairs.create(name, pub_key, key_type=args.key_type)
@api_versions.wraps("2.10")
def _keypair_create(cs, args, name, pub_key):
return cs.keypairs.create(name, pub_key, key_type=args.key_type,
user_id=args.user)
@cliutils.arg('name', metavar='<name>', help=_('Name of key.'))
@cliutils.arg(
'--pub-key',
@ -2997,6 +3003,12 @@ def _keypair_create(cs, args, name, pub_key):
default='ssh',
help=_('Keypair type. Can be ssh or x509.'),
start_version="2.2")
@cliutils.arg(
'--user',
metavar='<user-id>',
default=None,
help=_('ID of user to whom to add key-pair (Admin only).'),
start_version="2.10")
def do_keypair_add(cs, args):
"""Create a new key pair for use with servers."""
name = args.name
@ -3021,6 +3033,7 @@ def do_keypair_add(cs, args):
print(private_key)
@api_versions.wraps("2.0", "2.9")
@cliutils.arg('name', metavar='<name>', help=_('Keypair name to delete.'))
def do_keypair_delete(cs, args):
"""Delete keypair given by its name."""
@ -3028,6 +3041,18 @@ def do_keypair_delete(cs, args):
cs.keypairs.delete(name)
@api_versions.wraps("2.10")
@cliutils.arg('name', metavar='<name>', help=_('Keypair name to delete.'))
@cliutils.arg(
'--user',
metavar='<user-id>',
default=None,
help=_('Id of key-pair owner (Admin only).'))
def do_keypair_delete(cs, args):
"""Delete keypair given by its name."""
cs.keypairs.delete(args.name, args.user)
@api_versions.wraps("2.0", "2.1")
def _get_keypairs_list_columns(cs, args):
return ['Name', 'Fingerprint']
@ -3038,6 +3063,7 @@ def _get_keypairs_list_columns(cs, args):
return ['Name', 'Type', 'Fingerprint']
@api_versions.wraps("2.0", "2.9")
def do_keypair_list(cs, args):
"""Print a list of keypairs for a user"""
keypairs = cs.keypairs.list()
@ -3045,6 +3071,19 @@ def do_keypair_list(cs, args):
utils.print_list(keypairs, columns)
@api_versions.wraps("2.10")
@cliutils.arg(
'--user',
metavar='<user-id>',
default=None,
help=_('List key-pairs of specified user id (Admin only).'))
def do_keypair_list(cs, args):
"""Print a list of keypairs for a user"""
keypairs = cs.keypairs.list(args.user)
columns = _get_keypairs_list_columns(cs, args)
utils.print_list(keypairs, columns)
def _print_keypair(keypair):
kp = keypair._info.copy()
pk = kp.pop('public_key')
@ -3052,6 +3091,7 @@ def _print_keypair(keypair):
print(_("Public key: %s") % pk)
@api_versions.wraps("2.0", "2.9")
@cliutils.arg(
'keypair',
metavar='<keypair>',
@ -3062,6 +3102,22 @@ def do_keypair_show(cs, args):
_print_keypair(keypair)
@api_versions.wraps("2.10")
@cliutils.arg(
'keypair',
metavar='<keypair>',
help=_("Name of keypair."))
@cliutils.arg(
'--user',
metavar='<user-id>',
default=None,
help=_('Id of key-pair owner (Admin only).'))
def do_keypair_show(cs, args):
"""Show details about the given keypair."""
keypair = cs.keypairs.get(args.keypair, args.user)
_print_keypair(keypair)
def _find_keypair(cs, keypair):
"""Get a keypair by name."""
return utils.find_resource(cs.keypairs, keypair)