diff --git a/novaclient/__init__.py b/novaclient/__init__.py index 94ff3e494..37c73086a 100644 --- a/novaclient/__init__.py +++ b/novaclient/__init__.py @@ -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") diff --git a/novaclient/tests/functional/v2/test_keypairs.py b/novaclient/tests/functional/v2/test_keypairs.py index c02c2cac5..f330e2d0f 100644 --- a/novaclient/tests/functional/v2/test_keypairs.py +++ b/novaclient/tests/functional/v2/test_keypairs.py @@ -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 @@ -41,3 +44,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") diff --git a/novaclient/tests/unit/v2/test_shell.py b/novaclient/tests/unit/v2/test_shell.py index 24d0ad7f8..635507524 100644 --- a/novaclient/tests/unit/v2/test_shell.py +++ b/novaclient/tests/unit/v2/test_shell.py @@ -2552,7 +2552,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)) diff --git a/novaclient/v2/keypairs.py b/novaclient/v2/keypairs.py index 021960517..70ab8da57 100644 --- a/novaclient/v2/keypairs.py +++ b/novaclient/v2/keypairs.py @@ -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') diff --git a/novaclient/v2/shell.py b/novaclient/v2/shell.py index 05a0e74d4..5b6028e77 100644 --- a/novaclient/v2/shell.py +++ b/novaclient/v2/shell.py @@ -2993,11 +2993,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='', help=_('Name of key.')) @cliutils.arg( '--pub-key', @@ -3013,6 +3019,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='', + 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 @@ -3037,6 +3049,7 @@ def do_keypair_add(cs, args): print(private_key) +@api_versions.wraps("2.0", "2.9") @cliutils.arg('name', metavar='', help=_('Keypair name to delete.')) def do_keypair_delete(cs, args): """Delete keypair given by its name.""" @@ -3044,6 +3057,18 @@ def do_keypair_delete(cs, args): cs.keypairs.delete(name) +@api_versions.wraps("2.10") +@cliutils.arg('name', metavar='', help=_('Keypair name to delete.')) +@cliutils.arg( + '--user', + metavar='', + 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'] @@ -3054,6 +3079,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() @@ -3061,6 +3087,19 @@ def do_keypair_list(cs, args): utils.print_list(keypairs, columns) +@api_versions.wraps("2.10") +@cliutils.arg( + '--user', + metavar='', + 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') @@ -3068,6 +3107,7 @@ def _print_keypair(keypair): print(_("Public key: %s") % pk) +@api_versions.wraps("2.0", "2.9") @cliutils.arg( 'keypair', metavar='', @@ -3078,6 +3118,22 @@ def do_keypair_show(cs, args): _print_keypair(keypair) +@api_versions.wraps("2.10") +@cliutils.arg( + 'keypair', + metavar='', + help=_("Name of keypair.")) +@cliutils.arg( + '--user', + metavar='', + 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)