diff options
| -rw-r--r-- | openstackclient/common/clientmanager.py | 14 | ||||
| -rw-r--r-- | openstackclient/compute/v2/security_group.py | 12 | ||||
| -rw-r--r-- | openstackclient/compute/v2/server.py | 2 | ||||
| -rw-r--r-- | openstackclient/identity/client.py | 31 | ||||
| -rw-r--r-- | openstackclient/identity/v3/endpoint.py | 28 | ||||
| -rw-r--r-- | openstackclient/object/v1/container.py | 8 | ||||
| -rw-r--r-- | openstackclient/object/v1/lib/container.py | 49 | ||||
| -rw-r--r-- | openstackclient/object/v1/lib/object.py | 46 | ||||
| -rw-r--r-- | openstackclient/object/v1/object.py | 8 | ||||
| -rw-r--r-- | openstackclient/shell.py | 63 | ||||
| -rw-r--r-- | openstackclient/tests/common/test_clientmanager.py | 104 | ||||
| -rw-r--r-- | openstackclient/tests/fakes.py | 17 | ||||
| -rw-r--r-- | openstackclient/tests/identity/v3/test_endpoint.py | 96 | ||||
| -rw-r--r-- | openstackclient/tests/object/v1/lib/test_container.py | 72 | ||||
| -rw-r--r-- | openstackclient/tests/object/v1/lib/test_object.py | 103 | ||||
| -rw-r--r-- | openstackclient/tests/object/v1/test_container.py | 16 | ||||
| -rw-r--r-- | openstackclient/tests/object/v1/test_object.py | 18 | ||||
| -rw-r--r-- | openstackclient/tests/volume/v1/test_volume.py | 20 | ||||
| -rw-r--r-- | setup.cfg | 3 |
19 files changed, 478 insertions, 232 deletions
diff --git a/openstackclient/common/clientmanager.py b/openstackclient/common/clientmanager.py index a2f85aff..4dcec8e0 100644 --- a/openstackclient/common/clientmanager.py +++ b/openstackclient/common/clientmanager.py @@ -19,6 +19,7 @@ import logging import pkg_resources import sys +from openstackclient.common import restapi from openstackclient.identity import client as identity_client @@ -77,7 +78,18 @@ class ClientManager(object): self._insecure = not verify else: self._cacert = verify - self._insecure = True + self._insecure = False + + self.session = restapi.RESTApi( + verify=verify, + debug=True, + ) + + # Get logging from root logger + root_logger = logging.getLogger('') + LOG.setLevel(root_logger.getEffectiveLevel()) + restapi_logger = logging.getLogger('restapi') + restapi_logger.setLevel(root_logger.getEffectiveLevel()) self.auth_ref = None diff --git a/openstackclient/compute/v2/security_group.py b/openstackclient/compute/v2/security_group.py index 0ba55c98..cd330857 100644 --- a/openstackclient/compute/v2/security_group.py +++ b/openstackclient/compute/v2/security_group.py @@ -23,6 +23,7 @@ from cliff import command from cliff import lister from cliff import show +from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc from novaclient.v1_1 import security_group_rules from openstackclient.common import parseractions from openstackclient.common import utils @@ -150,10 +151,15 @@ class ListSecurityGroup(lister.Lister): search = {'all_tenants': parsed_args.all_projects} data = compute_client.security_groups.list(search_opts=search) - projects = self.app.client_manager.identity.projects.list() project_hash = {} - for project in projects: - project_hash[project.id] = project + try: + projects = self.app.client_manager.identity.projects.list() + except ksc_exc.Forbidden: + # This fails when the user is not an admin, just move along + pass + else: + for project in projects: + project_hash[project.id] = project return (column_headers, (utils.get_item_properties( diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index cb12a6ff..ec7f212d 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -175,7 +175,7 @@ class AddServerSecurityGroup(command.Command): parsed_args.group, ) - server.add_security_group(security_group) + server.add_security_group(security_group.name) return diff --git a/openstackclient/identity/client.py b/openstackclient/identity/client.py index 7f5390c8..820d08cb 100644 --- a/openstackclient/identity/client.py +++ b/openstackclient/identity/client.py @@ -66,10 +66,41 @@ def make_client(instance): insecure=instance._insecure, trust_id=instance._trust_id, ) + + # TODO(dtroyer): the identity v2 role commands use this yet, fix that + # so we can remove it instance.auth_ref = client.auth_ref + + # NOTE(dtroyer): this is hanging around until restapi is replace by + # ksc session + instance.session.set_auth( + client.auth_ref.auth_token, + ) + return client +def build_option_parser(parser): + """Hook to add global options""" + parser.add_argument( + '--os-identity-api-version', + metavar='<identity-api-version>', + default=utils.env( + 'OS_IDENTITY_API_VERSION', + default=DEFAULT_IDENTITY_API_VERSION), + help='Identity API version, default=' + + DEFAULT_IDENTITY_API_VERSION + + ' (Env: OS_IDENTITY_API_VERSION)') + parser.add_argument( + '--os-trust-id', + metavar='<trust-id>', + default=utils.env('OS_TRUST_ID'), + help='Trust ID to use when authenticating. ' + 'This can only be used with Keystone v3 API ' + '(Env: OS_TRUST_ID)') + return parser + + class IdentityClientv2_0(identity_client_v2_0.Client): """Tweak the earlier client class to deal with some changes""" def __getattr__(self, name): diff --git a/openstackclient/identity/v3/endpoint.py b/openstackclient/identity/v3/endpoint.py index 5ab5dac4..39798b2d 100644 --- a/openstackclient/identity/v3/endpoint.py +++ b/openstackclient/identity/v3/endpoint.py @@ -114,12 +114,38 @@ class ListEndpoint(lister.Lister): log = logging.getLogger(__name__ + '.ListEndpoint') + def get_parser(self, prog_name): + parser = super(ListEndpoint, self).get_parser(prog_name) + parser.add_argument( + '--service', + metavar='<service>', + help='Filter by a specific service') + parser.add_argument( + '--interface', + metavar='<interface>', + choices=['admin', 'public', 'internal'], + help='Filter by a specific interface, must be admin, public or' + ' internal') + parser.add_argument( + '--region', + metavar='<region>', + help='Filter by a specific region') + return parser + def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity columns = ('ID', 'Region', 'Service Name', 'Service Type', 'Enabled', 'Interface', 'URL') - data = identity_client.endpoints.list() + kwargs = {} + if parsed_args.service: + service = common.find_service(identity_client, parsed_args.service) + kwargs['service'] = service.id + if parsed_args.interface: + kwargs['interface'] = parsed_args.interface + if parsed_args.region: + kwargs['region'] = parsed_args.region + data = identity_client.endpoints.list(**kwargs) for ep in data: service = common.find_service(identity_client, ep.service_id) diff --git a/openstackclient/object/v1/container.py b/openstackclient/object/v1/container.py index ae4013fc..1ca07f3a 100644 --- a/openstackclient/object/v1/container.py +++ b/openstackclient/object/v1/container.py @@ -45,7 +45,7 @@ class CreateContainer(show.ShowOne): self.log.debug('take_action(%s)', parsed_args) data = lib_container.create_container( - self.app.restapi, + self.app.client_manager.session, self.app.client_manager.object_store.endpoint, parsed_args.container, ) @@ -71,7 +71,7 @@ class DeleteContainer(command.Command): self.log.debug('take_action(%s)', parsed_args) lib_container.delete_container( - self.app.restapi, + self.app.client_manager.session, self.app.client_manager.object_store.endpoint, parsed_args.container, ) @@ -140,7 +140,7 @@ class ListContainer(lister.Lister): kwargs['full_listing'] = True data = lib_container.list_containers( - self.app.restapi, + self.app.client_manager.session, self.app.client_manager.object_store.endpoint, **kwargs ) @@ -170,7 +170,7 @@ class ShowContainer(show.ShowOne): self.log.debug('take_action(%s)', parsed_args) data = lib_container.show_container( - self.app.restapi, + self.app.client_manager.session, self.app.client_manager.object_store.endpoint, parsed_args.container, ) diff --git a/openstackclient/object/v1/lib/container.py b/openstackclient/object/v1/lib/container.py index bd509555..65a9fe4d 100644 --- a/openstackclient/object/v1/lib/container.py +++ b/openstackclient/object/v1/lib/container.py @@ -23,46 +23,46 @@ except ImportError: def create_container( - api, + session, url, container, ): """Create a container - :param api: a restapi object + :param session: a restapi object :param url: endpoint :param container: name of container to create :returns: dict of returned headers """ - response = api.put("%s/%s" % (url, container)) + response = session.put("%s/%s" % (url, container)) url_parts = urlparse(url) data = { 'account': url_parts.path.split('/')[-1], 'container': container, + 'x-trans-id': response.headers.get('x-trans-id', None), } - data['x-trans-id'] = response.headers.get('x-trans-id', None) return data def delete_container( - api, + session, url, container, ): """Delete a container - :param api: a restapi object + :param session: a restapi object :param url: endpoint :param container: name of container to delete """ - api.delete("%s/%s" % (url, container)) + session.delete("%s/%s" % (url, container)) def list_containers( - api, + session, url, marker=None, limit=None, @@ -72,7 +72,7 @@ def list_containers( ): """Get containers in an account - :param api: a restapi object + :param session: a restapi object :param url: endpoint :param marker: marker query :param limit: limit query @@ -85,7 +85,7 @@ def list_containers( if full_listing: data = listing = list_containers( - api, + session, url, marker, limit, @@ -95,7 +95,7 @@ def list_containers( while listing: marker = listing[-1]['name'] listing = list_containers( - api, + session, url, marker, limit, @@ -117,34 +117,35 @@ def list_containers( params['end_marker'] = end_marker if prefix: params['prefix'] = prefix - return api.list(url, params=params) + return session.get(url, params=params).json() def show_container( - api, + session, url, container, ): """Get container details - :param api: a restapi object + :param session: a restapi object :param url: endpoint :param container: name of container to show :returns: dict of returned headers """ - response = api.head("%s/%s" % (url, container)) - url_parts = urlparse(url) + response = session.head("%s/%s" % (url, container)) data = { - 'account': url_parts.path.split('/')[-1], + 'account': response.headers.get('x-container-meta-owner', None), 'container': container, + 'object_count': response.headers.get( + 'x-container-object-count', + None, + ), + 'bytes_used': response.headers.get('x-container-bytes-used', None), + 'read_acl': response.headers.get('x-container-read', None), + 'write_acl': response.headers.get('x-container-write', None), + 'sync_to': response.headers.get('x-container-sync-to', None), + 'sync_key': response.headers.get('x-container-sync-key', None), } - data['object_count'] = response.headers.get( - 'x-container-object-count', None) - data['bytes_used'] = response.headers.get('x-container-bytes-used', None) - data['read_acl'] = response.headers.get('x-container-read', None) - data['write_acl'] = response.headers.get('x-container-write', None) - data['sync_to'] = response.headers.get('x-container-sync-to', None) - data['sync_key'] = response.headers.get('x-container-sync-key', None) return data diff --git a/openstackclient/object/v1/lib/object.py b/openstackclient/object/v1/lib/object.py index 2473caa3..0ded0dad 100644 --- a/openstackclient/object/v1/lib/object.py +++ b/openstackclient/object/v1/lib/object.py @@ -25,14 +25,14 @@ except ImportError: def create_object( - api, + session, url, container, object, ): """Create an object, upload it to a container - :param api: a restapi object + :param session: a restapi object :param url: endpoint :param container: name of container to store object :param object: local path to object @@ -40,38 +40,38 @@ def create_object( """ full_url = "%s/%s/%s" % (url, container, object) - response = api.put(full_url, data=open(object)) + response = session.put(full_url, data=open(object)) url_parts = urlparse(url) data = { 'account': url_parts.path.split('/')[-1], 'container': container, 'object': object, + 'x-trans-id': response.headers.get('X-Trans-Id', None), + 'etag': response.headers.get('Etag', None), } - data['x-trans-id'] = response.headers.get('X-Trans-Id', None) - data['etag'] = response.headers.get('Etag', None) return data def delete_object( - api, + session, url, container, object, ): """Delete an object stored in a container - :param api: a restapi object + :param session: a restapi object :param url: endpoint :param container: name of container that stores object :param container: name of object to delete """ - api.delete("%s/%s/%s" % (url, container, object)) + session.delete("%s/%s/%s" % (url, container, object)) def list_objects( - api, + session, url, container, marker=None, @@ -84,7 +84,7 @@ def list_objects( ): """Get objects in a container - :param api: a restapi object + :param session: a restapi object :param url: endpoint :param container: container name to get a listing for :param marker: marker query @@ -101,7 +101,7 @@ def list_objects( if full_listing: data = listing = list_objects( - api, + session, url, container, marker, @@ -117,7 +117,7 @@ def list_objects( else: marker = listing[-1]['name'] listing = list_objects( - api, + session, url, container, marker, @@ -131,7 +131,6 @@ def list_objects( data.extend(listing) return data - object_url = url params = { 'format': 'json', } @@ -147,32 +146,31 @@ def list_objects( params['prefix'] = prefix if path: params['path'] = path - url = "%s/%s" % (object_url, container) - return api.list(url, params=params) + requrl = "%s/%s" % (url, container) + return session.get(requrl, params=params).json() def show_object( - api, + session, url, container, obj, ): """Get object details - :param api: a restapi object + :param session: a restapi object :param url: endpoint :param container: container name to get a listing for :returns: dict of object properties """ - response = api.head("%s/%s/%s" % (url, container, obj)) - url_parts = urlparse(url) + response = session.head("%s/%s/%s" % (url, container, obj)) data = { - 'account': url_parts.path.split('/')[-1], + 'account': response.headers.get('x-container-meta-owner', None), 'container': container, 'object': obj, + 'content-type': response.headers.get('content-type', None), } - data['content-type'] = response.headers.get('content-type', None) if 'content-length' in response.headers: data['content-length'] = response.headers.get('content-length', None) if 'last-modified' in response.headers: @@ -184,10 +182,10 @@ def show_object( 'x-object-manifest', None) for key, value in six.iteritems(response.headers): if key.startswith('x-object-meta-'): - data[key[len('x-object-meta-'):].title()] = value + data[key[len('x-object-meta-'):].lower()] = value elif key not in ( 'content-type', 'content-length', 'last-modified', - 'etag', 'date', 'x-object-manifest'): - data[key.title()] = value + 'etag', 'date', 'x-object-manifest', 'x-container-meta-owner'): + data[key.lower()] = value return data diff --git a/openstackclient/object/v1/object.py b/openstackclient/object/v1/object.py index 4a99a8f1..812ad6e1 100644 --- a/openstackclient/object/v1/object.py +++ b/openstackclient/object/v1/object.py @@ -50,7 +50,7 @@ class CreateObject(show.ShowOne): self.log.debug('take_action(%s)', parsed_args) data = lib_object.create_object( - self.app.restapi, + self.app.client_manager.session, self.app.client_manager.object_store.endpoint, parsed_args.container, parsed_args.object, @@ -82,7 +82,7 @@ class DeleteObject(command.Command): self.log.debug('take_action(%s)', parsed_args) lib_object.delete_object( - self.app.restapi, + self.app.client_manager.session, self.app.client_manager.object_store.endpoint, parsed_args.container, parsed_args.object, @@ -170,7 +170,7 @@ class ListObject(lister.Lister): kwargs['full_listing'] = True data = lib_object.list_objects( - self.app.restapi, + self.app.client_manager.session, self.app.client_manager.object_store.endpoint, parsed_args.container, **kwargs @@ -206,7 +206,7 @@ class ShowObject(show.ShowOne): self.log.debug('take_action(%s)', parsed_args) data = lib_object.show_object( - self.app.restapi, + self.app.client_manager.session, self.app.client_manager.object_store.endpoint, parsed_args.container, parsed_args.object, diff --git a/openstackclient/shell.py b/openstackclient/shell.py index 28724343..24804343 100644 --- a/openstackclient/shell.py +++ b/openstackclient/shell.py @@ -31,10 +31,8 @@ import openstackclient from openstackclient.common import clientmanager from openstackclient.common import commandmanager from openstackclient.common import exceptions as exc -from openstackclient.common import restapi from openstackclient.common import timing from openstackclient.common import utils -from openstackclient.identity import client as identity_client KEYRING_SERVICE = 'openstack' @@ -76,6 +74,8 @@ class OpenStackShell(app.App): version=openstackclient.__version__, command_manager=commandmanager.CommandManager('openstack.cli')) + self.api_version = {} + # Until we have command line arguments parsed, dump any stack traces self.dump_stack_trace = True @@ -86,10 +86,14 @@ class OpenStackShell(app.App): # Assume TLS host certificate verification is enabled self.verify = True - # Get list of extension modules + # Get list of base modules self.ext_modules = clientmanager.get_extension_modules( - 'openstack.cli.extension', + 'openstack.cli.base', ) + # Append list of extension modules + self.ext_modules.extend(clientmanager.get_extension_modules( + 'openstack.cli.extension', + )) # Loop through extensions to get parser additions for mod in self.ext_modules: @@ -312,23 +316,6 @@ class OpenStackShell(app.App): help="Print API call timing info", ) - parser.add_argument( - '--os-identity-api-version', - metavar='<identity-api-version>', - default=env( - 'OS_IDENTITY_API_VERSION', - default=identity_client.DEFAULT_IDENTITY_API_VERSION), - help='Identity API version, default=' + - identity_client.DEFAULT_IDENTITY_API_VERSION + - ' (Env: OS_IDENTITY_API_VERSION)') - parser.add_argument( - '--os-trust-id', - metavar='<trust-id>', - default=utils.env('OS_TRUST_ID'), - help='Trust ID to use when authenticating. ' - 'This can only be used with Keystone v3 API ' - '(Env: OS_TRUST_ID)') - return parser def authenticate_user(self): @@ -437,24 +424,19 @@ class OpenStackShell(app.App): # Save default domain self.default_domain = self.options.os_default_domain - # Stash selected API versions for later - self.api_version = { - 'identity': self.options.os_identity_api_version, - } # Loop through extensions to get API versions for mod in self.ext_modules: - ver = getattr(self.options, mod.API_VERSION_OPTION, None) - if ver: - self.api_version[mod.API_NAME] = ver - self.log.debug('%(name)s API version %(version)s', - {'name': mod.API_NAME, 'version': ver}) - - # Add the API version-specific commands - for api in self.api_version.keys(): - version = '.v' + self.api_version[api].replace('.', '_') - cmd_group = 'openstack.' + api.replace('-', '_') + version - self.log.debug('command group %s', cmd_group) - self.command_manager.add_command_group(cmd_group) + version_opt = getattr(self.options, mod.API_VERSION_OPTION, None) + if version_opt: + api = mod.API_NAME + self.api_version[api] = version_opt + version = '.v' + version_opt.replace('.', '_') + cmd_group = 'openstack.' + api.replace('-', '_') + version + self.command_manager.add_command_group(cmd_group) + self.log.debug( + '%(name)s API version %(version)s, cmd group %(group)s', + {'name': api, 'version': version_opt, 'group': cmd_group} + ) # Commands that span multiple APIs self.command_manager.add_command_group( @@ -484,10 +466,6 @@ class OpenStackShell(app.App): self.verify = self.options.os_cacert else: self.verify = not self.options.insecure - self.restapi = restapi.RESTApi( - verify=self.verify, - debug=self.options.debug, - ) def prepare_to_run_command(self, cmd): """Set up auth and API versions""" @@ -498,12 +476,10 @@ class OpenStackShell(app.App): if cmd.best_effort: try: self.authenticate_user() - self.restapi.set_auth(self.client_manager.identity.auth_token) except Exception: pass else: self.authenticate_user() - self.restapi.set_auth(self.client_manager.identity.auth_token) return def clean_up(self, cmd, result, err): @@ -539,7 +515,6 @@ class OpenStackShell(app.App): # NOTE(dtroyer): Maintain the old behaviour for interactive use as # this path does not call prepare_to_run_command() self.authenticate_user() - self.restapi.set_auth(self.client_manager.identity.auth_token) super(OpenStackShell, self).interact() diff --git a/openstackclient/tests/common/test_clientmanager.py b/openstackclient/tests/common/test_clientmanager.py index 6aee711d..5a25fa2c 100644 --- a/openstackclient/tests/common/test_clientmanager.py +++ b/openstackclient/tests/common/test_clientmanager.py @@ -14,11 +14,26 @@ # from openstackclient.common import clientmanager +from openstackclient.common import restapi from openstackclient.tests import utils +AUTH_REF = {'a': 1} AUTH_TOKEN = "foobar" AUTH_URL = "http://0.0.0.0" +USERNAME = "itchy" +PASSWORD = "scratchy" +SERVICE_CATALOG = {'sc': '123'} + + +def FakeMakeClient(instance): + return FakeClient() + + +class FakeClient(object): + auth_ref = AUTH_REF + auth_token = AUTH_TOKEN + service_catalog = SERVICE_CATALOG class Container(object): @@ -28,31 +43,96 @@ class Container(object): pass +class TestClientCache(utils.TestCase): + + def test_singleton(self): + # NOTE(dtroyer): Verify that the ClientCache descriptor only invokes + # the factory one time and always returns the same value after that. + c = Container() + self.assertEqual(c.attr, c.attr) + + class TestClientManager(utils.TestCase): def setUp(self): super(TestClientManager, self).setUp() - api_version = {"identity": "2.0"} + clientmanager.ClientManager.identity = \ + clientmanager.ClientCache(FakeMakeClient) - self.client_manager = clientmanager.ClientManager( + def test_client_manager_token(self): + + client_manager = clientmanager.ClientManager( token=AUTH_TOKEN, url=AUTH_URL, + verify=True, + ) + + self.assertEqual( + AUTH_TOKEN, + client_manager._token, + ) + self.assertEqual( + AUTH_URL, + client_manager._url, + ) + self.assertIsInstance( + client_manager.session, + restapi.RESTApi, + ) + self.assertFalse(client_manager._insecure) + self.assertTrue(client_manager._verify) + + def test_client_manager_password(self): + + client_manager = clientmanager.ClientManager( auth_url=AUTH_URL, - api_version=api_version, + username=USERNAME, + password=PASSWORD, + verify=False, ) - def test_singleton(self): - # NOTE(dtroyer): Verify that the ClientCache descriptor only invokes - # the factory one time and always returns the same value after that. - c = Container() - self.assertEqual(c.attr, c.attr) + self.assertEqual( + AUTH_URL, + client_manager._auth_url, + ) + self.assertEqual( + USERNAME, + client_manager._username, + ) + self.assertEqual( + PASSWORD, + client_manager._password, + ) + self.assertIsInstance( + client_manager.session, + restapi.RESTApi, + ) + self.assertTrue(client_manager._insecure) + self.assertFalse(client_manager._verify) - def test_make_client_identity_default(self): + # These need to stick around until the old-style clients are gone + self.assertEqual( + AUTH_REF, + client_manager.auth_ref, + ) self.assertEqual( - self.client_manager.identity.auth_token, AUTH_TOKEN, + client_manager._token, ) self.assertEqual( - self.client_manager.identity.management_url, - AUTH_URL, + SERVICE_CATALOG, + client_manager._service_catalog, ) + + def test_client_manager_password_verify_ca(self): + + client_manager = clientmanager.ClientManager( + auth_url=AUTH_URL, + username=USERNAME, + password=PASSWORD, + verify='cafile', + ) + + self.assertFalse(client_manager._insecure) + self.assertTrue(client_manager._verify) + self.assertEqual('cafile', client_manager._cacert) diff --git a/openstackclient/tests/fakes.py b/openstackclient/tests/fakes.py index fb27ef94..263640ee 100644 --- a/openstackclient/tests/fakes.py +++ b/openstackclient/tests/fakes.py @@ -13,9 +13,12 @@ # under the License. # +import json import six import sys +import requests + AUTH_TOKEN = "foobar" AUTH_URL = "http://0.0.0.0" @@ -42,7 +45,6 @@ class FakeApp(object): self.stdin = sys.stdin self.stdout = _stdout or sys.stdout self.stderr = sys.stderr - self.restapi = None class FakeClientManager(object): @@ -53,6 +55,7 @@ class FakeClientManager(object): self.object = None self.volume = None self.network = None + self.session = None self.auth_ref = None @@ -78,3 +81,15 @@ class FakeResource(object): k != 'manager') info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys) return "<%s %s>" % (self.__class__.__name__, info) + + +class FakeResponse(requests.Response): + def __init__(self, headers={}, status_code=200, data=None, encoding=None): + super(FakeResponse, self).__init__() + + self.status_code = status_code + + self.headers.update(headers) + self._content = json.dumps(data) + if not isinstance(self._content, six.binary_type): + self._content = self._content.encode() diff --git a/openstackclient/tests/identity/v3/test_endpoint.py b/openstackclient/tests/identity/v3/test_endpoint.py index b90ba719..ea05326e 100644 --- a/openstackclient/tests/identity/v3/test_endpoint.py +++ b/openstackclient/tests/identity/v3/test_endpoint.py @@ -317,6 +317,102 @@ class TestEndpointList(TestEndpoint): ),) self.assertEqual(datalist, tuple(data)) + def test_endpoint_list_service(self): + arglist = [ + '--service', identity_fakes.service_name, + ] + verifylist = [ + ('service', identity_fakes.service_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # Set expected values + kwargs = { + 'service': identity_fakes.service_id, + } + self.endpoints_mock.list.assert_called_with(**kwargs) + + collist = ('ID', 'Region', 'Service Name', 'Service Type', + 'Enabled', 'Interface', 'URL') + self.assertEqual(collist, columns) + datalist = (( + identity_fakes.endpoint_id, + identity_fakes.endpoint_region, + identity_fakes.service_name, + identity_fakes.service_type, + True, + identity_fakes.endpoint_interface, + identity_fakes.endpoint_url, + ),) + self.assertEqual(datalist, tuple(data)) + + def test_endpoint_list_interface(self): + arglist = [ + '--interface', identity_fakes.endpoint_interface, + ] + verifylist = [ + ('interface', identity_fakes.endpoint_interface), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # Set expected values + kwargs = { + 'interface': identity_fakes.endpoint_interface, + } + self.endpoints_mock.list.assert_called_with(**kwargs) + + collist = ('ID', 'Region', 'Service Name', 'Service Type', + 'Enabled', 'Interface', 'URL') + self.assertEqual(collist, columns) + datalist = (( + identity_fakes.endpoint_id, + identity_fakes.endpoint_region, + identity_fakes.service_name, + identity_fakes.service_type, + True, + identity_fakes.endpoint_interface, + identity_fakes.endpoint_url, + ),) + self.assertEqual(datalist, tuple(data)) + + def test_endpoint_list_region(self): + arglist = [ + '--region', identity_fakes.endpoint_region, + ] + verifylist = [ + ('region', identity_fakes.endpoint_region), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # Set expected values + kwargs = { + 'region': identity_fakes.endpoint_region, + } + self.endpoints_mock.list.assert_called_with(**kwargs) + + collist = ('ID', 'Region', 'Service Name', 'Service Type', + 'Enabled', 'Interface', 'URL') + self.assertEqual(collist, columns) + datalist = (( + identity_fakes.endpoint_id, + identity_fakes.endpoint_region, + identity_fakes.service_name, + identity_fakes.service_type, + True, + identity_fakes.endpoint_interface, + identity_fakes.endpoint_url, + ),) + self.assertEqual(datalist, tuple(data)) + class TestEndpointSet(TestEndpoint): diff --git a/openstackclient/tests/object/v1/lib/test_container.py b/openstackclient/tests/object/v1/lib/test_container.py index f7355592..ce70b835 100644 --- a/openstackclient/tests/object/v1/lib/test_container.py +++ b/openstackclient/tests/object/v1/lib/test_container.py @@ -18,7 +18,7 @@ import mock from openstackclient.object.v1.lib import container as lib_container -from openstackclient.tests.common import test_restapi as restapi +from openstackclient.tests import fakes from openstackclient.tests.object.v1 import fakes as object_fakes @@ -39,156 +39,158 @@ class TestContainer(object_fakes.TestObjectv1): def setUp(self): super(TestContainer, self).setUp() - self.app.restapi = mock.MagicMock() + self.app.client_manager.session = mock.MagicMock() class TestContainerList(TestContainer): def test_container_list_no_options(self): resp = [{'name': 'is-name'}] - self.app.restapi.list.return_value = resp + self.app.client_manager.session.get().json.return_value = resp data = lib_container.list_containers( - self.app.restapi, + self.app.client_manager.session, fake_url, ) # Check expected values - self.app.restapi.list.assert_called_with( + self.app.client_manager.session.get.assert_called_with( fake_url, params={ 'format': 'json', } ) - self.assertEqual(data, resp) + self.assertEqual(resp, data) def test_container_list_marker(self): resp = [{'name': 'is-name'}] - self.app.restapi.list.return_value = resp + self.app.client_manager.session.get().json.return_value = resp data = lib_container.list_containers( - self.app.restapi, + self.app.client_manager.session, fake_url, marker='next', ) # Check expected values - self.app.restapi.list.assert_called_with( + self.app.client_manager.session.get.assert_called_with( fake_url, params={ 'format': 'json', 'marker': 'next', } ) - self.assertEqual(data, resp) + self.assertEqual(resp, data) def test_container_list_limit(self): resp = [{'name': 'is-name'}] - self.app.restapi.list.return_value = resp + self.app.client_manager.session.get().json.return_value = resp data = lib_container.list_containers( - self.app.restapi, + self.app.client_manager.session, fake_url, limit=5, ) # Check expected values - self.app.restapi.list.assert_called_with( + self.app.client_manager.session.get.assert_called_with( fake_url, params={ 'format': 'json', 'limit': 5, } ) - self.assertEqual(data, resp) + self.assertEqual(resp, data) def test_container_list_end_marker(self): resp = [{'name': 'is-name'}] - self.app.restapi.list.return_value = resp + self.app.client_manager.session.get().json.return_value = resp data = lib_container.list_containers( - self.app.restapi, + self.app.client_manager.session, fake_url, end_marker='last', ) # Check expected values - self.app.restapi.list.assert_called_with( + self.app.client_manager.session.get.assert_called_with( fake_url, params={ 'format': 'json', 'end_marker': 'last', } ) - self.assertEqual(data, resp) + self.assertEqual(resp, data) def test_container_list_prefix(self): resp = [{'name': 'is-name'}] - self.app.restapi.list.return_value = resp + self.app.client_manager.session.get().json.return_value = resp data = lib_container.list_containers( - self.app.restapi, + self.app.client_manager.session, fake_url, prefix='foo/', ) # Check expected values - self.app.restapi.list.assert_called_with( + self.app.client_manager.session.get.assert_called_with( fake_url, params={ 'format': 'json', 'prefix': 'foo/', } ) - self.assertEqual(data, resp) + self.assertEqual(resp, data) def test_container_list_full_listing(self): + sess = self.app.client_manager.session def side_effect(*args, **kwargs): - rv = self.app.restapi.list.return_value - self.app.restapi.list.return_value = [] - self.app.restapi.list.side_effect = None + rv = sess.get().json.return_value + sess.get().json.return_value = [] + sess.get().json.side_effect = None return rv resp = [{'name': 'is-name'}] - self.app.restapi.list.return_value = resp - self.app.restapi.list.side_effect = side_effect + sess.get().json.return_value = resp + sess.get().json.side_effect = side_effect data = lib_container.list_containers( - self.app.restapi, + self.app.client_manager.session, fake_url, full_listing=True, ) # Check expected values - self.app.restapi.list.assert_called_with( + sess.get.assert_called_with( fake_url, params={ 'format': 'json', 'marker': 'is-name', } ) - self.assertEqual(data, resp) + self.assertEqual(resp, data) class TestContainerShow(TestContainer): def test_container_show_no_options(self): resp = { + 'X-Container-Meta-Owner': fake_account, 'x-container-object-count': 1, 'x-container-bytes-used': 577, } - self.app.restapi.head.return_value = \ - restapi.FakeResponse(headers=resp) + self.app.client_manager.session.head.return_value = \ + fakes.FakeResponse(headers=resp) data = lib_container.show_container( - self.app.restapi, + self.app.client_manager.session, fake_url, 'is-name', ) # Check expected values - self.app.restapi.head.assert_called_with( + self.app.client_manager.session.head.assert_called_with( fake_url + '/is-name', ) @@ -202,4 +204,4 @@ class TestContainerShow(TestContainer): 'sync_to': None, 'sync_key': None, } - self.assertEqual(data, data_expected) + self.assertEqual(data_expected, data) diff --git a/openstackclient/tests/object/v1/lib/test_object.py b/openstackclient/tests/object/v1/lib/test_object.py index 064efb53..f96732b4 100644 --- a/openstackclient/tests/object/v1/lib/test_object.py +++ b/openstackclient/tests/object/v1/lib/test_object.py @@ -18,7 +18,7 @@ import mock from openstackclient.object.v1.lib import object as lib_object -from openstackclient.tests.common import test_restapi as restapi +from openstackclient.tests import fakes from openstackclient.tests.object.v1 import fakes as object_fakes @@ -40,99 +40,99 @@ class TestObject(object_fakes.TestObjectv1): def setUp(self): super(TestObject, self).setUp() - self.app.restapi = mock.MagicMock() + self.app.client_manager.session = mock.MagicMock() class TestObjectListObjects(TestObject): def test_list_objects_no_options(self): resp = [{'name': 'is-name'}] - self.app.restapi.list.return_value = resp + self.app.client_manager.session.get().json.return_value = resp data = lib_object.list_objects( - self.app.restapi, + self.app.client_manager.session, fake_url, fake_container, ) # Check expected values - self.app.restapi.list.assert_called_with( + self.app.client_manager.session.get.assert_called_with( fake_url + '/' + fake_container, params={ 'format': 'json', } ) - self.assertEqual(data, resp) + self.assertEqual(resp, data) def test_list_objects_marker(self): resp = [{'name': 'is-name'}] - self.app.restapi.list.return_value = resp + self.app.client_manager.session.get().json.return_value = resp data = lib_object.list_objects( - self.app.restapi, + self.app.client_manager.session, fake_url, fake_container, marker='next', ) # Check expected values - self.app.restapi.list.assert_called_with( + self.app.client_manager.session.get.assert_called_with( fake_url + '/' + fake_container, params={ 'format': 'json', 'marker': 'next', } ) - self.assertEqual(data, resp) + self.assertEqual(resp, data) def test_list_objects_limit(self): resp = [{'name': 'is-name'}] - self.app.restapi.list.return_value = resp + self.app.client_manager.session.get().json.return_value = resp data = lib_object.list_objects( - self.app.restapi, + self.app.client_manager.session, fake_url, fake_container, limit=5, ) # Check expected values - self.app.restapi.list.assert_called_with( + self.app.client_manager.session.get.assert_called_with( fake_url + '/' + fake_container, params={ 'format': 'json', 'limit': 5, } ) - self.assertEqual(data, resp) + self.assertEqual(resp, data) def test_list_objects_end_marker(self): resp = [{'name': 'is-name'}] - self.app.restapi.list.return_value = resp + self.app.client_manager.session.get().json.return_value = resp data = lib_object.list_objects( - self.app.restapi, + self.app.client_manager.session, fake_url, fake_container, end_marker='last', ) # Check expected values - self.app.restapi.list.assert_called_with( + self.app.client_manager.session.get.assert_called_with( fake_url + '/' + fake_container, params={ 'format': 'json', 'end_marker': 'last', } ) - self.assertEqual(data, resp) + self.assertEqual(resp, data) def test_list_objects_delimiter(self): resp = [{'name': 'is-name'}] - self.app.restapi.list.return_value = resp + self.app.client_manager.session.get().json.return_value = resp data = lib_object.list_objects( - self.app.restapi, + self.app.client_manager.session, fake_url, fake_container, delimiter='|', @@ -142,85 +142,86 @@ class TestObjectListObjects(TestObject): # NOTE(dtroyer): requests handles the URL encoding and we're # mocking that so use the otherwise-not-legal # pipe '|' char in the response. - self.app.restapi.list.assert_called_with( + self.app.client_manager.session.get.assert_called_with( fake_url + '/' + fake_container, params={ 'format': 'json', 'delimiter': '|', } ) - self.assertEqual(data, resp) + self.assertEqual(resp, data) def test_list_objects_prefix(self): resp = [{'name': 'is-name'}] - self.app.restapi.list.return_value = resp + self.app.client_manager.session.get().json.return_value = resp data = lib_object.list_objects( - self.app.restapi, + self.app.client_manager.session, fake_url, fake_container, prefix='foo/', ) # Check expected values - self.app.restapi.list.assert_called_with( + self.app.client_manager.session.get.assert_called_with( fake_url + '/' + fake_container, params={ 'format': 'json', 'prefix': 'foo/', } ) - self.assertEqual(data, resp) + self.assertEqual(resp, data) def test_list_objects_path(self): resp = [{'name': 'is-name'}] - self.app.restapi.list.return_value = resp + self.app.client_manager.session.get().json.return_value = resp data = lib_object.list_objects( - self.app.restapi, + self.app.client_manager.session, fake_url, fake_container, path='next', ) # Check expected values - self.app.restapi.list.assert_called_with( + self.app.client_manager.session.get.assert_called_with( fake_url + '/' + fake_container, params={ 'format': 'json', 'path': 'next', } ) - self.assertEqual(data, resp) + self.assertEqual(resp, data) def test_list_objects_full_listing(self): + sess = self.app.client_manager.session def side_effect(*args, **kwargs): - rv = self.app.restapi.list.return_value - self.app.restapi.list.return_value = [] - self.app.restapi.list.side_effect = None + rv = sess.get().json.return_value + sess.get().json.return_value = [] + sess.get().json.side_effect = None return rv resp = [{'name': 'is-name'}] - self.app.restapi.list.return_value = resp - self.app.restapi.list.side_effect = side_effect + sess.get().json.return_value = resp + sess.get().json.side_effect = side_effect data = lib_object.list_objects( - self.app.restapi, + sess, fake_url, fake_container, full_listing=True, ) # Check expected values - self.app.restapi.list.assert_called_with( + sess.get.assert_called_with( fake_url + '/' + fake_container, params={ 'format': 'json', 'marker': 'is-name', } ) - self.assertEqual(data, resp) + self.assertEqual(resp, data) class TestObjectShowObjects(TestObject): @@ -228,19 +229,20 @@ class TestObjectShowObjects(TestObject): def test_object_show_no_options(self): resp = { 'content-type': 'text/alpha', + 'x-container-meta-owner': fake_account, } - self.app.restapi.head.return_value = \ - restapi.FakeResponse(headers=resp) + self.app.client_manager.session.head.return_value = \ + fakes.FakeResponse(headers=resp) data = lib_object.show_object( - self.app.restapi, + self.app.client_manager.session, fake_url, fake_container, fake_object, ) # Check expected values - self.app.restapi.head.assert_called_with( + self.app.client_manager.session.head.assert_called_with( fake_url + '/%s/%s' % (fake_container, fake_object), ) @@ -250,7 +252,7 @@ class TestObjectShowObjects(TestObject): 'object': fake_object, 'content-type': 'text/alpha', } - self.assertEqual(data, data_expected) + self.assertEqual(data_expected, data) def test_object_show_all_options(self): resp = { @@ -258,22 +260,23 @@ class TestObjectShowObjects(TestObject): 'content-length': 577, 'last-modified': '20130101', 'etag': 'qaz', + 'x-container-meta-owner': fake_account, 'x-object-manifest': None, 'x-object-meta-wife': 'Wilma', 'x-tra-header': 'yabba-dabba-do', } - self.app.restapi.head.return_value = \ - restapi.FakeResponse(headers=resp) + self.app.client_manager.session.head.return_value = \ + fakes.FakeResponse(headers=resp) data = lib_object.show_object( - self.app.restapi, + self.app.client_manager.session, fake_url, fake_container, fake_object, ) # Check expected values - self.app.restapi.head.assert_called_with( + self.app.client_manager.session.head.assert_called_with( fake_url + '/%s/%s' % (fake_container, fake_object), ) @@ -286,7 +289,7 @@ class TestObjectShowObjects(TestObject): 'last-modified': '20130101', 'etag': 'qaz', 'x-object-manifest': None, - 'Wife': 'Wilma', - 'X-Tra-Header': 'yabba-dabba-do', + 'wife': 'Wilma', + 'x-tra-header': 'yabba-dabba-do', } - self.assertEqual(data, data_expected) + self.assertEqual(data_expected, data) diff --git a/openstackclient/tests/object/v1/test_container.py b/openstackclient/tests/object/v1/test_container.py index 4afb1006..b72c79d6 100644 --- a/openstackclient/tests/object/v1/test_container.py +++ b/openstackclient/tests/object/v1/test_container.py @@ -77,7 +77,7 @@ class TestContainerList(TestObject): kwargs = { } c_mock.assert_called_with( - self.app.restapi, + self.app.client_manager.session, AUTH_URL, **kwargs ) @@ -113,7 +113,7 @@ class TestContainerList(TestObject): 'prefix': 'bit', } c_mock.assert_called_with( - self.app.restapi, + self.app.client_manager.session, AUTH_URL, **kwargs ) @@ -148,7 +148,7 @@ class TestContainerList(TestObject): 'marker': object_fakes.container_name, } c_mock.assert_called_with( - self.app.restapi, + self.app.client_manager.session, AUTH_URL, **kwargs ) @@ -183,7 +183,7 @@ class TestContainerList(TestObject): 'end_marker': object_fakes.container_name_3, } c_mock.assert_called_with( - self.app.restapi, + self.app.client_manager.session, AUTH_URL, **kwargs ) @@ -218,7 +218,7 @@ class TestContainerList(TestObject): 'limit': 2, } c_mock.assert_called_with( - self.app.restapi, + self.app.client_manager.session, AUTH_URL, **kwargs ) @@ -252,7 +252,7 @@ class TestContainerList(TestObject): kwargs = { } c_mock.assert_called_with( - self.app.restapi, + self.app.client_manager.session, AUTH_URL, **kwargs ) @@ -296,7 +296,7 @@ class TestContainerList(TestObject): 'full_listing': True, } c_mock.assert_called_with( - self.app.restapi, + self.app.client_manager.session, AUTH_URL, **kwargs ) @@ -341,7 +341,7 @@ class TestContainerShow(TestObject): } # lib.container.show_container(api, url, container) c_mock.assert_called_with( - self.app.restapi, + self.app.client_manager.session, AUTH_URL, object_fakes.container_name, **kwargs diff --git a/openstackclient/tests/object/v1/test_object.py b/openstackclient/tests/object/v1/test_object.py index bea0d270..26d07b2c 100644 --- a/openstackclient/tests/object/v1/test_object.py +++ b/openstackclient/tests/object/v1/test_object.py @@ -71,7 +71,7 @@ class TestObjectList(TestObject): columns, data = self.cmd.take_action(parsed_args) o_mock.assert_called_with( - self.app.restapi, + self.app.client_manager.session, AUTH_URL, object_fakes.container_name, ) @@ -107,7 +107,7 @@ class TestObjectList(TestObject): 'prefix': 'floppy', } o_mock.assert_called_with( - self.app.restapi, + self.app.client_manager.session, AUTH_URL, object_fakes.container_name_2, **kwargs @@ -143,7 +143,7 @@ class TestObjectList(TestObject): 'delimiter': '=', } o_mock.assert_called_with( - self.app.restapi, + self.app.client_manager.session, AUTH_URL, object_fakes.container_name_2, **kwargs @@ -179,7 +179,7 @@ class TestObjectList(TestObject): 'marker': object_fakes.object_name_2, } o_mock.assert_called_with( - self.app.restapi, + self.app.client_manager.session, AUTH_URL, object_fakes.container_name_2, **kwargs @@ -215,7 +215,7 @@ class TestObjectList(TestObject): 'end_marker': object_fakes.object_name_2, } o_mock.assert_called_with( - self.app.restapi, + self.app.client_manager.session, AUTH_URL, object_fakes.container_name_2, **kwargs @@ -251,7 +251,7 @@ class TestObjectList(TestObject): 'limit': 2, } o_mock.assert_called_with( - self.app.restapi, + self.app.client_manager.session, AUTH_URL, object_fakes.container_name_2, **kwargs @@ -287,7 +287,7 @@ class TestObjectList(TestObject): kwargs = { } o_mock.assert_called_with( - self.app.restapi, + self.app.client_manager.session, AUTH_URL, object_fakes.container_name, **kwargs @@ -337,7 +337,7 @@ class TestObjectList(TestObject): 'full_listing': True, } o_mock.assert_called_with( - self.app.restapi, + self.app.client_manager.session, AUTH_URL, object_fakes.container_name, **kwargs @@ -384,7 +384,7 @@ class TestObjectShow(TestObject): } # lib.container.show_container(api, url, container) c_mock.assert_called_with( - self.app.restapi, + self.app.client_manager.session, AUTH_URL, object_fakes.container_name, object_fakes.object_name_1, diff --git a/openstackclient/tests/volume/v1/test_volume.py b/openstackclient/tests/volume/v1/test_volume.py index cb006b10..f020791a 100644 --- a/openstackclient/tests/volume/v1/test_volume.py +++ b/openstackclient/tests/volume/v1/test_volume.py @@ -101,7 +101,7 @@ class TestVolumeCreate(TestVolume): 'status', 'type', ) - self.assertEqual(columns, collist) + self.assertEqual(collist, columns) datalist = ( 'detached', volume_fakes.volume_zone, @@ -113,7 +113,7 @@ class TestVolumeCreate(TestVolume): '', volume_fakes.volume_type, ) - self.assertEqual(data, datalist) + self.assertEqual(datalist, data) def test_volume_create_options(self): arglist = [ @@ -165,7 +165,7 @@ class TestVolumeCreate(TestVolume): 'status', 'type', ) - self.assertEqual(columns, collist) + self.assertEqual(collist, columns) datalist = ( 'detached', volume_fakes.volume_zone, @@ -177,7 +177,7 @@ class TestVolumeCreate(TestVolume): '', volume_fakes.volume_type, ) - self.assertEqual(data, datalist) + self.assertEqual(datalist, data) def test_volume_create_user_project_id(self): # Return a project @@ -240,7 +240,7 @@ class TestVolumeCreate(TestVolume): 'status', 'type', ) - self.assertEqual(columns, collist) + self.assertEqual(collist, columns) datalist = ( 'detached', volume_fakes.volume_zone, @@ -252,7 +252,7 @@ class TestVolumeCreate(TestVolume): '', volume_fakes.volume_type, ) - self.assertEqual(data, datalist) + self.assertEqual(datalist, data) def test_volume_create_user_project_name(self): # Return a project @@ -315,7 +315,7 @@ class TestVolumeCreate(TestVolume): 'status', 'type', ) - self.assertEqual(columns, collist) + self.assertEqual(collist, columns) datalist = ( 'detached', volume_fakes.volume_zone, @@ -327,7 +327,7 @@ class TestVolumeCreate(TestVolume): '', volume_fakes.volume_type, ) - self.assertEqual(data, datalist) + self.assertEqual(datalist, data) def test_volume_create_properties(self): arglist = [ @@ -376,7 +376,7 @@ class TestVolumeCreate(TestVolume): 'status', 'type', ) - self.assertEqual(columns, collist) + self.assertEqual(collist, columns) datalist = ( 'detached', volume_fakes.volume_zone, @@ -388,4 +388,4 @@ class TestVolumeCreate(TestVolume): '', volume_fakes.volume_type, ) - self.assertEqual(data, datalist) + self.assertEqual(datalist, data) @@ -30,8 +30,9 @@ console_scripts = openstack.cli = module_list = openstackclient.common.module:ListModule -openstack.cli.extension = +openstack.cli.base = compute = openstackclient.compute.client + identity = openstackclient.identity.client image = openstackclient.image.client network = openstackclient.network.client object_store = openstackclient.object.client |
