From bbd2561507538282c5fb1c549b298226399237a1 Mon Sep 17 00:00:00 2001 From: Dean Troyer Date: Thu, 2 Feb 2012 23:16:01 -0600 Subject: [PATCH] Add tenant commands to cli * Adds tenant-list, tenant-get and tenant-update to keystone command * Removes tenant-enable and tenant-disable * Fixes more overlap in cli args, clean up command args, particularly removing nargs from arguments that are not optional. * Fixes bug 932235 Change-Id: I1aafec1b2a3943e0f6c86f0228ab29f181a7ffce --- keystoneclient/v2_0/shell.py | 146 ++++++++++++++++++--------------- keystoneclient/v2_0/tenants.py | 17 +++- tests/test_shell.py | 56 ++++++++++++- 3 files changed, 145 insertions(+), 74 deletions(-) diff --git a/keystoneclient/v2_0/shell.py b/keystoneclient/v2_0/shell.py index 7c8c65ba6..a71b045fa 100755 --- a/keystoneclient/v2_0/shell.py +++ b/keystoneclient/v2_0/shell.py @@ -21,11 +21,8 @@ from keystoneclient import utils CLIENT_CLASS = client.Client -@utils.arg('tenant', - metavar='', - help='ID of Tenant. (Optional)', - nargs='?', - default=None) +@utils.arg('tenant', metavar='', nargs='?', + help='ID of Tenant. (Optional)', default=None) def do_user_list(kc, args): users = kc.users.list(tenant_id=args.tenant) utils.print_list(users, ['id', 'enabled', 'email', 'name', 'tenantId']) @@ -48,8 +45,7 @@ def do_user_create(kc, args): utils.print_dict(user._info) -@utils.arg('id', metavar='', nargs='?', - help='User ID to update.') +@utils.arg('id', metavar='', help='User ID to update.') @utils.arg('name', metavar='', nargs='?', help='New desired user name.') @utils.arg('email', metavar='', nargs='?', @@ -65,7 +61,7 @@ def do_user_enable(kc, args): kc.users.update_enabled(args.id, True) print 'User has been enabled.' except: - 'Unable to enable user.' + print 'Unable to enable user.' @utils.arg('id', metavar='', nargs='?', help='User ID to disable.') @@ -74,34 +70,44 @@ def do_user_disable(kc, args): kc.users.update_enabled(args.id, False) print 'User has been disabled.' except: - 'Unable to disable user.' + print 'Unable to disable user.' -@utils.arg('id', metavar='', nargs='?', help='User ID to update.') -@utils.arg('password', metavar='', nargs='?', - help='New desired password.') +@utils.arg('id', metavar='', help='User ID to update.') +@utils.arg('password', metavar='', help='New desired password.') def do_user_update_password(kc, args): try: kc.users.update_password(args.id, args.password) print 'User password has been udpated.' except: - 'Unable to update users password.' + print 'Unable to update users password.' -@utils.arg('id', metavar='', nargs='?', help='User ID to delete.') +@utils.arg('id', metavar='', help='User ID to delete.') def do_user_delete(kc, args): try: kc.users.delete(args.id) print 'User has been deleted.' except: - 'Unable to delete user.' + print 'Unable to delete user.' -@utils.arg('--name', metavar='', nargs='?', +def do_tenant_list(kc, args): + tenants = kc.tenants.list() + utils.print_list(tenants, ['id', 'name', 'enabled']) + + +@utils.arg('id', metavar='', help='Tenant ID to show.') +def do_tenant_get(kc, args): + tenant = kc.tenants.get(args.id) + utils.print_dict(tenant._info) + + +@utils.arg('--name', metavar='', nargs='?', help='Desired name of new tenant.') @utils.arg('--description', metavar='', nargs='?', default=None, help='Useful description of new tenant (optional, default is None)') -@utils.arg('--enabled', metavar='', nargs='?', default=True, +@utils.arg('--enabled', metavar='', nargs='?', default=True, help='Enable user immediately (Optional, default True)') def do_tenant_create(kc, args): tenant = kc.tenants.create(args.name, @@ -110,36 +116,48 @@ def do_tenant_create(kc, args): utils.print_dict(tenant._info) -@utils.arg('id', metavar='', nargs='?', help='Tenant ID to enable.') -def do_tenant_enable(kc, args): +@utils.arg('--name', metavar='', nargs='?', + help='Desired name of tenant.') +@utils.arg('--description', metavar='', nargs='?', default=None, + help='Desired description of tenant') +@utils.arg('--enabled', metavar='', nargs='?', const=True, + help='Enable/disable tenant') +@utils.arg('id', metavar='', help='Tenant ID to update') +def do_tenant_update(kc, args): + """Update tenant name, description, enabled status""" + tenant = kc.tenants.get(args.id) + kwargs = {} + if args.name: + kwargs.update({'name': args.name}) + if args.description: + kwargs.update({'description': args.description}) + if args.enabled: + new_enable = args.enabled.lower() in ['true', 'yes', '1'] + kwargs.update({'enabled': new_enable}) + + if kwargs == {}: + print "Tenant not updated, no arguments present." + return + try: - kc.tenants.update(args.id, enabled=True) - print 'Tenant has been enabled.' - except: - 'Unable to enable tenant.' + tenant.update(**kwargs) + print 'Tenant has been updated.' + except Exception, e: + print 'Unable to update tenant: %s' % e -@utils.arg('id', metavar='', nargs='?', help='Tenant ID to disable') -def do_tenant_disable(kc, args): - try: - kc.tenants.update_enabled(args.id, enabled=False) - print 'Tenant has been disabled.' - except: - 'Unable to disable tenant.' - - -@utils.arg('id', metavar='', nargs='?', help='Tenant ID to delete') +@utils.arg('id', metavar='', help='Tenant ID to delete') def do_tenant_delete(kc, args): try: kc.tenants.delete(args.id) print 'Tenant has been deleted.' except: - 'Unable to delete tenant.' + print 'Unable to delete tenant.' -@utils.arg('--name', metavar='', nargs='?', +@utils.arg('--name', metavar='', help='Desired name of service. (unique)') -@utils.arg('--type', metavar='', nargs='?', +@utils.arg('--type', metavar='', help='Possible service types: identity, compute, network, \ image, or object-store.') @utils.arg('--description', metavar='', nargs='?', @@ -156,19 +174,13 @@ def do_service_list(kc, args): utils.print_list(services, ['id', 'name', 'type', 'description']) -@utils.arg('id', - metavar='', - help='ID of Service to retrieve.', - nargs='?') +@utils.arg('id', metavar='', help='ID of Service to retrieve.') def do_service_get(kc, args): service = kc.services.get(args.id) utils.print_dict(service._info) -@utils.arg('id', - metavar='', - help='ID of Service to delete', - nargs='?') +@utils.arg('id', metavar='', help='ID of Service to delete') def do_service_delete(kc, args): try: kc.services.delete(args.id) @@ -182,20 +194,19 @@ def do_role_list(kc, args): utils.print_list(roles, ['id', 'name']) -@utils.arg('id', metavar='', help='ID of Role to fetch.', nargs='?') +@utils.arg('id', metavar='', help='ID of Role to fetch.') def do_role_get(kc, args): role = kc.roles.get(args.id) utils.print_dict(role._info) -@utils.arg('--name', metavar='', nargs='?', - help='Desired name of new role.') +@utils.arg('--name', metavar='', help='Desired name of new role.') def do_role_create(kc, args): role = kc.roles.create(args.name) utils.print_dict(role._info) -@utils.arg('id', metavar='', help='ID of Role to delete.', nargs='?') +@utils.arg('id', metavar='', help='ID of Role to delete.') def do_role_delete(kc, args): try: kc.roles.delete(args.id) @@ -205,30 +216,31 @@ def do_role_delete(kc, args): # TODO(jakedahn): refactor this to allow role, user, and tenant names. -@utils.arg('user_id', metavar='', help='ID of User', nargs='?') -@utils.arg('role_id', metavar='', help='ID of Role', nargs='?') -@utils.arg('tenant_id', metavar='', help='ID of Tenant', nargs='?') +@utils.arg('user_id', metavar='', help='ID of User') +@utils.arg('role_id', metavar='', help='ID of Role') +@utils.arg('tenant', metavar='', + help='ID of Tenant', nargs='?') def do_add_user_role(kc, args): - kc.roles.add_user_role(args.user_id, args.role_id, args.tenant_id) + kc.roles.add_user_role(args.user_id, args.role_id, args.tenant) # TODO(jakedahn): refactor this to allow role, user, and tenant names. -@utils.arg('user_id', metavar='', help='ID of User', nargs='?') -@utils.arg('role_id', metavar='', help='ID of Role', nargs='?') -@utils.arg('tenant_id', metavar='', help='ID of Tenant', nargs='?') +@utils.arg('user_id', metavar='', help='ID of User') +@utils.arg('role_id', metavar='', help='ID of Role') +@utils.arg('tenant', metavar='', + help='ID of Tenant', nargs='?') def do_remove_user_role(kc, args): - kc.roles.remove_user_role(args.user_id, args.role_id, args.tenant_id) + kc.roles.remove_user_role(args.user_id, args.role_id, args.tenant) -@utils.arg('--tenant_id', metavar='', help='ID of Tenant', - nargs='?') -@utils.arg('--user_id', metavar='', help='ID of User', nargs='?') +@utils.arg('--tenant_id', metavar='', help='ID of Tenant') +@utils.arg('--user_id', metavar='', help='ID of User') def do_ec2_create_credentials(kc, args): credentials = kc.ec2.create(args.user_id, args.tenant_id) utils.print_dict(credentials._info) -@utils.arg('user_id', metavar='', help='ID of User', nargs='?') +@utils.arg('user_id', metavar='', help='ID of User') def do_ec2_list_credentials(kc, args): credentials = kc.ec2.list(args.user_id) for cred in credentials: @@ -236,8 +248,8 @@ def do_ec2_list_credentials(kc, args): utils.print_list(credentials, ['tenant', 'key', 'secret']) -@utils.arg('user_id', metavar='', help='ID of User', nargs='?') -@utils.arg('key', metavar='', help='Access Key', nargs='?') +@utils.arg('user_id', metavar='', help='ID of User') +@utils.arg('key', metavar='', help='Access Key') def do_ec2_delete_credentials(kc, args): try: kc.ec2.delete(args.user_id, args.key) @@ -247,7 +259,7 @@ def do_ec2_delete_credentials(kc, args): @utils.arg('--service', metavar='', - help='Service type to return', nargs='?', default=None) + help='Service type to return', nargs='?', default=None) def do_catalog(kc, args): """List service catalog, possibly filtered by service""" endpoints = kc.service_catalog.get_endpoints(service_type=args.service) @@ -259,13 +271,13 @@ def do_catalog(kc, args): @utils.arg('--endpoint_type', metavar='', - help='Endpoint type to select', nargs='?', default='publicURL') + help='Endpoint type to select', nargs='?', default='publicURL') @utils.arg('--service', metavar='', - help='Service type to select', nargs='?', required=True) + help='Service type to select', nargs='?', required=True) @utils.arg('--attr', metavar='', - help='Attribute to match', nargs='?') + help='Attribute to match', nargs='?') @utils.arg('--value', metavar='', - help='Value of attribute to match', nargs='?') + help='Value of attribute to match', nargs='?') def do_endpoint_get(kc, args): """Find endpoint filtered by a specific attribute or service type""" kwargs = { diff --git a/keystoneclient/v2_0/tenants.py b/keystoneclient/v2_0/tenants.py index bcef77f3b..4d2a900ea 100644 --- a/keystoneclient/v2_0/tenants.py +++ b/keystoneclient/v2_0/tenants.py @@ -26,9 +26,20 @@ class Tenant(base.Resource): def delete(self): return self.manager.delete(self) - def update(self, description=None, enabled=None): - # FIXME(ja): set the attributes in this object if successful - return self.manager.update(self.id, description, enabled) + def update(self, name=None, description=None, enabled=None): + # Preserve the existing settings; keystone legacy resets these? + new_name = name if name else self.name + new_description = description if description else self.description + new_enabled = enabled if enabled else self.enabled + + try: + retval = self.manager.update(self.id, tenant_name=new_name, + description=new_description, + enabled=new_enabled) + self = retval + except Exception, e: + retval = None + return retval def add_user(self, user, role): return self.manager.api.roles.add_user_to_tenant(self.id, diff --git a/tests/test_shell.py b/tests/test_shell.py index 9c99bc298..0b46d68d3 100644 --- a/tests/test_shell.py +++ b/tests/test_shell.py @@ -3,20 +3,29 @@ import mock import httplib2 from keystoneclient import shell as openstack_shell +from keystoneclient.v2_0 import shell as shell_v2_0 from keystoneclient import exceptions from tests import utils +DEFAULT_USERNAME = 'username' +DEFAULT_PASSWORD = 'password' +DEFAULT_TENANT_ID = 'tenant_id' +DEFAULT_TENANT_NAME = 'tenant_name' +DEFAULT_AUTH_URL = 'http://127.0.0.1:5000/v2.0/' + + class ShellTest(utils.TestCase): # Patch os.environ to avoid required auth info. def setUp(self): global _old_env fake_env = { - 'OS_USERNAME': 'username', - 'OS_PASSWORD': 'password', - 'OS_TENANT_ID': 'tenant_id', - 'OS_AUTH_URL': 'http://127.0.0.1:5000/v2.0', + 'OS_USERNAME': DEFAULT_USERNAME, + 'OS_PASSWORD': DEFAULT_PASSWORD, + 'OS_TENANT_ID': DEFAULT_TENANT_ID, + 'OS_TENANT_NAME': DEFAULT_TENANT_NAME, + 'OS_AUTH_URL': DEFAULT_AUTH_URL, } _old_env, os.environ = os.environ, fake_env.copy() @@ -37,3 +46,42 @@ class ShellTest(utils.TestCase): httplib2.debuglevel = 0 shell('--debug help') assert httplib2.debuglevel == 1 + + def test_shell_args(self): + do_tenant_mock = mock.MagicMock() + with mock.patch('keystoneclient.v2_0.shell.do_user_list', + do_tenant_mock): + shell('user-list') + assert do_tenant_mock.called + ((a, b), c) = do_tenant_mock.call_args + assert (b.auth_url, b.password, b.tenant_id, + b.tenant_name, b.username, b.version) == \ + (DEFAULT_AUTH_URL, DEFAULT_PASSWORD, DEFAULT_TENANT_ID, + DEFAULT_TENANT_NAME, DEFAULT_USERNAME, '') + shell('--auth-url http://0.0.0.0:5000/ --password xyzpdq ' + '--tenant_id 1234 --tenant_name fred --username barney ' + '--version 2.0 user-list') + assert do_tenant_mock.called + ((a, b), c) = do_tenant_mock.call_args + assert (b.auth_url, b.password, b.tenant_id, + b.tenant_name, b.username, b.version) == \ + ('http://0.0.0.0:5000/', 'xyzpdq', '1234', + 'fred', 'barney', '2.0') + + def test_do_tenant_create(self): + do_tenant_mock = mock.MagicMock() + with mock.patch('keystoneclient.v2_0.shell.do_tenant_create', + do_tenant_mock): + shell('tenant-create') + assert do_tenant_mock.called + # FIXME(dtroyer): how do you test the decorators? + #shell('tenant-create --tenant-name wilma ' + # '--description "fred\'s wife"') + #assert do_tenant_mock.called + + def test_do_tenant_list(self): + do_tenant_mock = mock.MagicMock() + with mock.patch('keystoneclient.v2_0.shell.do_tenant_list', + do_tenant_mock): + shell('tenant-list') + assert do_tenant_mock.called