diff options
Diffstat (limited to 'openstackclient')
43 files changed, 1050 insertions, 572 deletions
diff --git a/openstackclient/common/clientmanager.py b/openstackclient/common/clientmanager.py index 85f544e4..a0224064 100644 --- a/openstackclient/common/clientmanager.py +++ b/openstackclient/common/clientmanager.py @@ -16,12 +16,10 @@ """Manage access to the clients, including authenticating when needed.""" import logging +import pkg_resources +import sys -from openstackclient.compute import client as compute_client from openstackclient.identity import client as identity_client -from openstackclient.image import client as image_client -from openstackclient.object import client as object_client -from openstackclient.volume import client as volume_client LOG = logging.getLogger(__name__) @@ -42,11 +40,7 @@ class ClientCache(object): class ClientManager(object): """Manages access to API clients, including authentication.""" - compute = ClientCache(compute_client.make_client) identity = ClientCache(identity_client.make_client) - image = ClientCache(image_client.make_client) - object = ClientCache(object_client.make_client) - volume = ClientCache(volume_client.make_client) def __init__(self, token=None, url=None, auth_url=None, project_name=None, project_id=None, username=None, password=None, @@ -93,3 +87,26 @@ class ClientManager(object): # Hope we were given the correct URL. endpoint = self._url return endpoint + + +def get_extension_modules(group): + """Add extension clients""" + mod_list = [] + for ep in pkg_resources.iter_entry_points(group): + LOG.debug('found extension %r' % ep.name) + + __import__(ep.module_name) + module = sys.modules[ep.module_name] + mod_list.append(module) + init_func = getattr(module, 'Initialize', None) + if init_func: + init_func('x') + + setattr( + ClientManager, + ep.name, + ClientCache( + getattr(sys.modules[ep.module_name], 'make_client', None) + ), + ) + return mod_list diff --git a/openstackclient/common/commandmanager.py b/openstackclient/common/commandmanager.py index e366034a..553bc920 100644 --- a/openstackclient/common/commandmanager.py +++ b/openstackclient/common/commandmanager.py @@ -1,4 +1,4 @@ -# Copyright 2012-2013 OpenStack, LLC. +# Copyright 2012-2013 OpenStack Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -25,18 +25,32 @@ LOG = logging.getLogger(__name__) class CommandManager(cliff.commandmanager.CommandManager): - """Alters Cliff's default CommandManager behaviour to load additiona + """Alters Cliff's default CommandManager behaviour to load additional command groups after initialization. """ + def __init__(self, namespace, convert_underscores=True): + self.group_list = [] + super(CommandManager, self).__init__(namespace, convert_underscores) + def _load_commands(self, group=None): if not group: group = self.namespace + self.group_list.append(group) for ep in pkg_resources.iter_entry_points(group): LOG.debug('found command %r' % ep.name) - self.commands[ep.name.replace('_', ' ')] = ep + cmd_name = ( + ep.name.replace('_', ' ') + if self.convert_underscores + else ep.name + ) + self.commands[cmd_name] = ep return def add_command_group(self, group=None): """Adds another group of command entrypoints""" if group: self._load_commands(group) + + def get_command_groups(self): + """Returns a list of the loaded command groups""" + return self.group_list diff --git a/openstackclient/compute/client.py b/openstackclient/compute/client.py index 4d3b1b71..4ccb2f6d 100644 --- a/openstackclient/compute/client.py +++ b/openstackclient/compute/client.py @@ -19,6 +19,8 @@ from openstackclient.common import utils LOG = logging.getLogger(__name__) +DEFAULT_COMPUTE_API_VERSION = '2' +API_VERSION_OPTION = 'os_compute_api_version' API_NAME = 'compute' API_VERSIONS = { '1.1': 'novaclient.v1_1.client.Client', @@ -60,3 +62,17 @@ def make_client(instance): client.client.service_catalog = instance._service_catalog client.client.auth_token = instance._token return client + + +def build_option_parser(parser): + """Hook to add global options""" + parser.add_argument( + '--os-compute-api-version', + metavar='<compute-api-version>', + default=utils.env( + 'OS_COMPUTE_API_VERSION', + default=DEFAULT_COMPUTE_API_VERSION), + help='Compute API version, default=' + + DEFAULT_COMPUTE_API_VERSION + + ' (Env: OS_COMPUTE_API_VERSION)') + return parser diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index 1de9f1ba..87f5f689 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -384,6 +384,73 @@ class CreateServer(show.ShowOne): return zip(*sorted(six.iteritems(details))) +class CreateServerImage(show.ShowOne): + """Create a new disk image from a running server""" + + log = logging.getLogger(__name__ + '.CreateServerImage') + + def get_parser(self, prog_name): + parser = super(CreateServerImage, self).get_parser(prog_name) + parser.add_argument( + 'server', + metavar='<server', + help='Server (name or ID)', + ) + parser.add_argument( + '--name', + metavar='<image-name>', + help='Name of new image (default is server name)', + ) + parser.add_argument( + '--wait', + action='store_true', + help='Wait for image create to complete', + ) + return parser + + def take_action(self, parsed_args): + self.log.debug('take_action(%s)' % parsed_args) + compute_client = self.app.client_manager.compute + image_client = self.app.client_manager.image + server = utils.find_resource( + compute_client.servers, + parsed_args.server, + ) + if parsed_args.name: + name = parsed_args.name + else: + name = server.name + + image = compute_client.servers.create_image( + server, + name, + ) + + if parsed_args.wait: + if utils.wait_for_status( + image_client.images.get, + image, + callback=_show_progress, + ): + sys.stdout.write('\n') + else: + self.log.error( + 'Error creating server snapshot: %s' % + parsed_args.image_name, + ) + sys.stdout.write('\nError creating server snapshot') + raise SystemExit + + image = utils.find_resource( + image_client.images, + image.id, + ) + + info = {} + info.update(image._info) + return zip(*sorted(six.iteritems(info))) + + class DeleteServer(command.Command): """Delete server command""" diff --git a/openstackclient/identity/client.py b/openstackclient/identity/client.py index 4814bc3e..305d4cc4 100644 --- a/openstackclient/identity/client.py +++ b/openstackclient/identity/client.py @@ -21,6 +21,8 @@ from openstackclient.common import utils LOG = logging.getLogger(__name__) +DEFAULT_IDENTITY_API_VERSION = '2.0' +API_VERSION_OPTION = 'os_identity_api_version' API_NAME = 'identity' API_VERSIONS = { '2.0': 'openstackclient.identity.client.IdentityClientv2_0', diff --git a/openstackclient/image/client.py b/openstackclient/image/client.py index d56ca3b2..9edffded 100644 --- a/openstackclient/image/client.py +++ b/openstackclient/image/client.py @@ -23,6 +23,8 @@ from openstackclient.common import utils LOG = logging.getLogger(__name__) +DEFAULT_IMAGE_API_VERSION = '1' +API_VERSION_OPTION = 'os_image_api_version' API_NAME = "image" API_VERSIONS = { "1": "openstackclient.image.client.Client_v1", @@ -48,6 +50,20 @@ def make_client(instance): ) +def build_option_parser(parser): + """Hook to add global options""" + parser.add_argument( + '--os-image-api-version', + metavar='<image-api-version>', + default=utils.env( + 'OS_IMAGE_API_VERSION', + default=DEFAULT_IMAGE_API_VERSION), + help='Image API version, default=' + + DEFAULT_IMAGE_API_VERSION + + ' (Env: OS_IMAGE_API_VERSION)') + return parser + + # NOTE(dtroyer): glanceclient.v1.image.ImageManager() doesn't have a find() # method so add one here until the common client libs arrive # A similar subclass will be required for v2 diff --git a/openstackclient/image/v1/image.py b/openstackclient/image/v1/image.py index 8827d079..40f9fce1 100644 --- a/openstackclient/image/v1/image.py +++ b/openstackclient/image/v1/image.py @@ -213,7 +213,7 @@ class DeleteImage(command.Command): image_client.images, parsed_args.image, ) - image_client.images.delete(image) + image_client.images.delete(image.id) class ListImage(lister.Lister): diff --git a/openstackclient/object/client.py b/openstackclient/object/client.py index a83a5c0a..273bea6e 100644 --- a/openstackclient/object/client.py +++ b/openstackclient/object/client.py @@ -21,6 +21,8 @@ from openstackclient.common import utils LOG = logging.getLogger(__name__) +DEFAULT_OBJECT_API_VERSION = '1' +API_VERSION_OPTION = 'os_object_api_version' API_NAME = 'object-store' API_VERSIONS = { '1': 'openstackclient.object.client.ObjectClientv1', @@ -45,6 +47,20 @@ def make_client(instance): return client +def build_option_parser(parser): + """Hook to add global options""" + parser.add_argument( + '--os-object-api-version', + metavar='<object-api-version>', + default=utils.env( + 'OS_OBJECT_API_VERSION', + default=DEFAULT_OBJECT_API_VERSION), + help='Object API version, default=' + + DEFAULT_OBJECT_API_VERSION + + ' (Env: OS_OBJECT_API_VERSION)') + return parser + + class ObjectClientv1(object): def __init__( diff --git a/openstackclient/object/v1/container.py b/openstackclient/object/v1/container.py index 68b14fc5..fcfbd783 100644 --- a/openstackclient/object/v1/container.py +++ b/openstackclient/object/v1/container.py @@ -90,7 +90,7 @@ class ListContainer(lister.Lister): data = lib_container.list_containers( self.app.restapi, - self.app.client_manager.object.endpoint, + self.app.client_manager.object_store.endpoint, **kwargs ) @@ -120,7 +120,7 @@ class ShowContainer(show.ShowOne): data = lib_container.show_container( self.app.restapi, - self.app.client_manager.object.endpoint, + self.app.client_manager.object_store.endpoint, parsed_args.container, ) diff --git a/openstackclient/object/v1/object.py b/openstackclient/object/v1/object.py index 426a52ad..f6a77030 100644 --- a/openstackclient/object/v1/object.py +++ b/openstackclient/object/v1/object.py @@ -108,7 +108,7 @@ class ListObject(lister.Lister): data = lib_object.list_objects( self.app.restapi, - self.app.client_manager.object.endpoint, + self.app.client_manager.object_store.endpoint, parsed_args.container, **kwargs ) @@ -144,7 +144,7 @@ class ShowObject(show.ShowOne): data = lib_object.show_object( self.app.restapi, - self.app.client_manager.object.endpoint, + self.app.client_manager.object_store.endpoint, parsed_args.container, parsed_args.object, ) diff --git a/openstackclient/shell.py b/openstackclient/shell.py index d0905fd9..4ac7683f 100644 --- a/openstackclient/shell.py +++ b/openstackclient/shell.py @@ -20,6 +20,7 @@ import getpass import logging import os import sys +import traceback from cliff import app from cliff import command @@ -32,15 +33,11 @@ from openstackclient.common import exceptions as exc from openstackclient.common import openstackkeyring from openstackclient.common import restapi from openstackclient.common import utils +from openstackclient.identity import client as identity_client KEYRING_SERVICE = 'openstack' -DEFAULT_COMPUTE_API_VERSION = '2' -DEFAULT_IDENTITY_API_VERSION = '2.0' -DEFAULT_IMAGE_API_VERSION = '1' -DEFAULT_OBJECT_API_VERSION = '1' -DEFAULT_VOLUME_API_VERSION = '1' DEFAULT_DOMAIN = 'default' @@ -75,6 +72,9 @@ class OpenStackShell(app.App): version=openstackclient.__version__, command_manager=commandmanager.CommandManager('openstack.cli')) + # Until we have command line arguments parsed, dump any stack traces + self.dump_stack_trace = True + # This is instantiated in initialize_app() only when using # password flow auth self.auth_client = None @@ -82,6 +82,15 @@ class OpenStackShell(app.App): # Assume TLS host certificate verification is enabled self.verify = True + # Get list of extension modules + self.ext_modules = clientmanager.get_extension_modules( + 'openstack.cli.extension', + ) + + # Loop through extensions to get parser additions + for mod in self.ext_modules: + self.parser = mod.build_option_parser(self.parser) + # NOTE(dtroyer): This hack changes the help action that Cliff # automatically adds to the parser so we can defer # its execution until after the api-versioned commands @@ -111,6 +120,18 @@ class OpenStackShell(app.App): help="show this help message and exit", ) + def run(self, argv): + try: + return super(OpenStackShell, self).run(argv) + except Exception as e: + if not logging.getLogger('').handlers: + logging.basicConfig() + if self.dump_stack_trace: + self.log.error(traceback.format_exc(e)) + else: + self.log.error('Exception raised: ' + str(e)) + return 1 + def build_option_parser(self, description, version): parser = super(OpenStackShell, self).build_option_parser( description, @@ -187,51 +208,6 @@ class OpenStackShell(app.App): DEFAULT_DOMAIN + ' (Env: OS_DEFAULT_DOMAIN)') parser.add_argument( - '--os-identity-api-version', - metavar='<identity-api-version>', - default=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-compute-api-version', - metavar='<compute-api-version>', - default=env( - 'OS_COMPUTE_API_VERSION', - default=DEFAULT_COMPUTE_API_VERSION), - help='Compute API version, default=' + - DEFAULT_COMPUTE_API_VERSION + - ' (Env: OS_COMPUTE_API_VERSION)') - parser.add_argument( - '--os-image-api-version', - metavar='<image-api-version>', - default=env( - 'OS_IMAGE_API_VERSION', - default=DEFAULT_IMAGE_API_VERSION), - help='Image API version, default=' + - DEFAULT_IMAGE_API_VERSION + - ' (Env: OS_IMAGE_API_VERSION)') - parser.add_argument( - '--os-object-api-version', - metavar='<object-api-version>', - default=env( - 'OS_OBJECT_API_VERSION', - default=DEFAULT_OBJECT_API_VERSION), - help='Object API version, default=' + - DEFAULT_OBJECT_API_VERSION + - ' (Env: OS_OBJECT_API_VERSION)') - parser.add_argument( - '--os-volume-api-version', - metavar='<volume-api-version>', - default=env( - 'OS_VOLUME_API_VERSION', - default=DEFAULT_VOLUME_API_VERSION), - help='Volume API version, default=' + - DEFAULT_VOLUME_API_VERSION + - ' (Env: OS_VOLUME_API_VERSION)') - parser.add_argument( '--os-token', metavar='<token>', default=env('OS_TOKEN'), @@ -254,6 +230,16 @@ class OpenStackShell(app.App): help='Use keyring to store password, ' 'default=False (Env: OS_USE_KEYRING)') + 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)') + return parser def authenticate_user(self): @@ -365,25 +351,30 @@ class OpenStackShell(app.App): requests_log = logging.getLogger("requests") if self.options.debug: requests_log.setLevel(logging.DEBUG) + self.dump_stack_trace = True else: requests_log.setLevel(logging.WARNING) + self.dump_stack_trace = False # Save default domain self.default_domain = self.options.os_default_domain # Stash selected API versions for later self.api_version = { - 'compute': self.options.os_compute_api_version, 'identity': self.options.os_identity_api_version, - 'image': self.options.os_image_api_version, - 'object-store': self.options.os_object_api_version, - 'volume': self.options.os_volume_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('%s API version %s' % (mod.API_NAME, 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) # Commands that span multiple APIs @@ -402,6 +393,8 @@ class OpenStackShell(app.App): # } self.command_manager.add_command_group( 'openstack.extension') + # call InitializeXxx() here + # set up additional clients to stuff in to client_manager?? # Handle deferred help and exit if self.options.deferred_help: @@ -437,11 +430,7 @@ class OpenStackShell(app.App): def main(argv=sys.argv[1:]): - try: - return OpenStackShell().run(argv) - except Exception: - return 1 - + return OpenStackShell().run(argv) if __name__ == "__main__": sys.exit(main(sys.argv[1:])) diff --git a/openstackclient/tests/common/test_commandmanager.py b/openstackclient/tests/common/test_commandmanager.py index 4953c297..088ea21e 100644 --- a/openstackclient/tests/common/test_commandmanager.py +++ b/openstackclient/tests/common/test_commandmanager.py @@ -1,4 +1,4 @@ -# Copyright 2012-2013 OpenStack, LLC. +# Copyright 2012-2013 OpenStack Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -40,9 +40,11 @@ class FakeCommandManager(commandmanager.CommandManager): if not group: self.commands['one'] = FAKE_CMD_ONE self.commands['two'] = FAKE_CMD_TWO + self.group_list.append(self.namespace) else: self.commands['alpha'] = FAKE_CMD_ALPHA self.commands['beta'] = FAKE_CMD_BETA + self.group_list.append(group) class TestCommandManager(utils.TestCase): @@ -69,3 +71,18 @@ class TestCommandManager(utils.TestCase): # Ensure that the original commands were not overwritten cmd_two, name, args = mgr.find_command(['two']) self.assertEqual(cmd_two, FAKE_CMD_TWO) + + def test_get_command_groups(self): + mgr = FakeCommandManager('test') + + # Make sure add_command() still functions + mock_cmd_one = mock.Mock() + mgr.add_command('mock', mock_cmd_one) + cmd_mock, name, args = mgr.find_command(['mock']) + self.assertEqual(cmd_mock, mock_cmd_one) + + # Load another command group + mgr.add_command_group('latin') + + gl = mgr.get_command_groups() + self.assertEqual(['test', 'latin'], gl) diff --git a/openstackclient/tests/compute/test_compute.py b/openstackclient/tests/compute/test_compute.py deleted file mode 100644 index 9d2061d2..00000000 --- a/openstackclient/tests/compute/test_compute.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2013 OpenStack, LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# - -import mock - -from openstackclient.common import clientmanager -from openstackclient.compute import client as compute_client -from openstackclient.tests import utils - - -AUTH_TOKEN = "foobar" -AUTH_URL = "http://0.0.0.0" - - -class FakeClient(object): - def __init__(self, endpoint=None, **kwargs): - self.client = mock.MagicMock() - self.client.auth_url = AUTH_URL - - -class TestCompute(utils.TestCase): - def setUp(self): - super(TestCompute, self).setUp() - - api_version = {"compute": "2"} - - compute_client.API_VERSIONS = { - "2": "openstackclient.tests.compute.test_compute.FakeClient" - } - - self.cm = clientmanager.ClientManager(token=AUTH_TOKEN, - url=AUTH_URL, - auth_url=AUTH_URL, - api_version=api_version) - - def test_make_client(self): - self.assertEqual(self.cm.compute.client.auth_token, AUTH_TOKEN) - self.assertEqual(self.cm.compute.client.auth_url, AUTH_URL) diff --git a/openstackclient/tests/identity/v3/test_identity.py b/openstackclient/tests/compute/v2/__init__.py index 4b55ee45..c534c012 100644 --- a/openstackclient/tests/identity/v3/test_identity.py +++ b/openstackclient/tests/compute/v2/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2013 Nebula Inc. +# Copyright 2013 OpenStack Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -12,20 +12,3 @@ # License for the specific language governing permissions and limitations # under the License. # - -from openstackclient.tests.identity.v3 import fakes -from openstackclient.tests import utils - - -AUTH_TOKEN = "foobar" -AUTH_URL = "http://0.0.0.0" - - -class TestIdentityv3(utils.TestCommand): - def setUp(self): - super(TestIdentityv3, self).setUp() - - self.app.client_manager.identity = fakes.FakeIdentityv3Client( - endpoint=AUTH_URL, - token=AUTH_TOKEN, - ) diff --git a/openstackclient/tests/compute/v2/fakes.py b/openstackclient/tests/compute/v2/fakes.py new file mode 100644 index 00000000..03ebd67c --- /dev/null +++ b/openstackclient/tests/compute/v2/fakes.py @@ -0,0 +1,54 @@ +# Copyright 2013 Nebula Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import mock + +from openstackclient.tests import fakes +from openstackclient.tests.image.v2 import fakes as image_fakes +from openstackclient.tests import utils + + +server_id = 'serv1' +server_name = 'waiter' + +SERVER = { + 'id': server_id, + 'name': server_name, +} + + +class FakeComputev2Client(object): + def __init__(self, **kwargs): + self.images = mock.Mock() + self.images.resource_class = fakes.FakeResource(None, {}) + self.servers = mock.Mock() + self.servers.resource_class = fakes.FakeResource(None, {}) + self.auth_token = kwargs['token'] + self.management_url = kwargs['endpoint'] + + +class TestComputev2(utils.TestCommand): + def setUp(self): + super(TestComputev2, self).setUp() + + self.app.client_manager.compute = FakeComputev2Client( + endpoint=fakes.AUTH_URL, + token=fakes.AUTH_TOKEN, + ) + + self.app.client_manager.image = image_fakes.FakeImagev2Client( + endpoint=fakes.AUTH_URL, + token=fakes.AUTH_TOKEN, + ) diff --git a/openstackclient/tests/compute/v2/test_server.py b/openstackclient/tests/compute/v2/test_server.py new file mode 100644 index 00000000..4cd294cc --- /dev/null +++ b/openstackclient/tests/compute/v2/test_server.py @@ -0,0 +1,154 @@ +# Copyright 2013 Nebula Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import copy + +from openstackclient.compute.v2 import server +from openstackclient.tests.compute.v2 import fakes as compute_fakes +from openstackclient.tests import fakes +from openstackclient.tests.image.v2 import fakes as image_fakes + + +class TestServer(compute_fakes.TestComputev2): + + def setUp(self): + super(TestServer, self).setUp() + + # Get a shortcut to the ServerManager Mock + self.servers_mock = self.app.client_manager.compute.servers + self.servers_mock.reset_mock() + + # Get a shortcut to the ImageManager Mock + self.images_mock = self.app.client_manager.image.images + self.images_mock.reset_mock() + + +class TestServerDelete(TestServer): + + def setUp(self): + super(TestServerDelete, self).setUp() + + # This is the return value for utils.find_resource() + self.servers_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(compute_fakes.SERVER), + loaded=True, + ) + self.servers_mock.delete.return_value = None + + # Get the command object to test + self.cmd = server.DeleteServer(self.app, None) + + def test_server_delete_no_options(self): + arglist = [ + compute_fakes.server_id, + ] + verifylist = [ + ('server', compute_fakes.server_id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + self.cmd.take_action(parsed_args) + + self.servers_mock.delete.assert_called_with( + compute_fakes.server_id, + ) + + +class TestServerImageCreate(TestServer): + + def setUp(self): + super(TestServerImageCreate, self).setUp() + + # This is the return value for utils.find_resource() + self.servers_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(compute_fakes.SERVER), + loaded=True, + ) + + self.servers_mock.create_image.return_value = fakes.FakeResource( + None, + copy.deepcopy(image_fakes.IMAGE), + loaded=True, + ) + + self.images_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(image_fakes.IMAGE), + loaded=True, + ) + + # Get the command object to test + self.cmd = server.CreateServerImage(self.app, None) + + def test_server_image_create_no_options(self): + arglist = [ + compute_fakes.server_id, + ] + verifylist = [ + ('server', compute_fakes.server_id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # ServerManager.create_image(server, image_name, metadata=) + self.servers_mock.create_image.assert_called_with( + self.servers_mock.get.return_value, + compute_fakes.server_name, + ) + + collist = ('id', 'is_public', 'name', 'owner') + self.assertEqual(columns, collist) + datalist = ( + image_fakes.image_id, + False, + image_fakes.image_name, + image_fakes.image_owner, + ) + self.assertEqual(data, datalist) + + def test_server_image_create_name(self): + arglist = [ + '--name', 'img-nam', + compute_fakes.server_id, + ] + verifylist = [ + ('name', 'img-nam'), + ('server', compute_fakes.server_id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # ServerManager.create_image(server, image_name, metadata=) + self.servers_mock.create_image.assert_called_with( + self.servers_mock.get.return_value, + 'img-nam', + ) + + collist = ('id', 'is_public', 'name', 'owner') + self.assertEqual(columns, collist) + datalist = ( + image_fakes.image_id, + False, + image_fakes.image_name, + image_fakes.image_owner, + ) + self.assertEqual(data, datalist) diff --git a/openstackclient/tests/fakes.py b/openstackclient/tests/fakes.py index d6cf1d74..bb89f762 100644 --- a/openstackclient/tests/fakes.py +++ b/openstackclient/tests/fakes.py @@ -16,6 +16,10 @@ import sys +AUTH_TOKEN = "foobar" +AUTH_URL = "http://0.0.0.0" + + class FakeStdout: def __init__(self): self.content = [] @@ -45,6 +49,7 @@ class FakeClientManager(object): self.compute = None self.identity = None self.image = None + self.object = None self.volume = None self.auth_ref = None diff --git a/openstackclient/tests/identity/v2_0/fakes.py b/openstackclient/tests/identity/v2_0/fakes.py index b1aeabd4..80febd29 100644 --- a/openstackclient/tests/identity/v2_0/fakes.py +++ b/openstackclient/tests/identity/v2_0/fakes.py @@ -16,6 +16,8 @@ import mock from openstackclient.tests import fakes +from openstackclient.tests import utils + project_id = '8-9-64' project_name = 'beatles' @@ -83,3 +85,13 @@ class FakeIdentityv2Client(object): self.ec2.resource_class = fakes.FakeResource(None, {}) self.auth_token = kwargs['token'] self.management_url = kwargs['endpoint'] + + +class TestIdentityv2(utils.TestCommand): + def setUp(self): + super(TestIdentityv2, self).setUp() + + self.app.client_manager.identity = FakeIdentityv2Client( + endpoint=fakes.AUTH_URL, + token=fakes.AUTH_TOKEN, + ) diff --git a/openstackclient/tests/identity/v2_0/test_project.py b/openstackclient/tests/identity/v2_0/test_project.py index 933bd094..30f4278b 100644 --- a/openstackclient/tests/identity/v2_0/test_project.py +++ b/openstackclient/tests/identity/v2_0/test_project.py @@ -18,10 +18,9 @@ import copy from openstackclient.identity.v2_0 import project from openstackclient.tests import fakes from openstackclient.tests.identity.v2_0 import fakes as identity_fakes -from openstackclient.tests.identity.v2_0 import test_identity -class TestProject(test_identity.TestIdentityv2): +class TestProject(identity_fakes.TestIdentityv2): def setUp(self): super(TestProject, self).setUp() diff --git a/openstackclient/tests/identity/v2_0/test_role.py b/openstackclient/tests/identity/v2_0/test_role.py index 56e9d4cb..d515bd7c 100644 --- a/openstackclient/tests/identity/v2_0/test_role.py +++ b/openstackclient/tests/identity/v2_0/test_role.py @@ -20,10 +20,9 @@ from openstackclient.common import exceptions from openstackclient.identity.v2_0 import role from openstackclient.tests import fakes from openstackclient.tests.identity.v2_0 import fakes as identity_fakes -from openstackclient.tests.identity.v2_0 import test_identity -class TestRole(test_identity.TestIdentityv2): +class TestRole(identity_fakes.TestIdentityv2): def setUp(self): super(TestRole, self).setUp() diff --git a/openstackclient/tests/identity/v2_0/test_service.py b/openstackclient/tests/identity/v2_0/test_service.py index f09c4137..6c93574b 100644 --- a/openstackclient/tests/identity/v2_0/test_service.py +++ b/openstackclient/tests/identity/v2_0/test_service.py @@ -18,10 +18,9 @@ import copy from openstackclient.identity.v2_0 import service from openstackclient.tests import fakes from openstackclient.tests.identity.v2_0 import fakes as identity_fakes -from openstackclient.tests.identity.v2_0 import test_identity -class TestService(test_identity.TestIdentityv2): +class TestService(identity_fakes.TestIdentityv2): def setUp(self): super(TestService, self).setUp() diff --git a/openstackclient/tests/identity/v2_0/test_user.py b/openstackclient/tests/identity/v2_0/test_user.py index 2fe585ed..a18d13d8 100644 --- a/openstackclient/tests/identity/v2_0/test_user.py +++ b/openstackclient/tests/identity/v2_0/test_user.py @@ -18,10 +18,9 @@ import copy from openstackclient.identity.v2_0 import user from openstackclient.tests import fakes from openstackclient.tests.identity.v2_0 import fakes as identity_fakes -from openstackclient.tests.identity.v2_0 import test_identity -class TestUser(test_identity.TestIdentityv2): +class TestUser(identity_fakes.TestIdentityv2): def setUp(self): super(TestUser, self).setUp() diff --git a/openstackclient/tests/identity/v3/fakes.py b/openstackclient/tests/identity/v3/fakes.py index 13385536..9d40d9db 100644 --- a/openstackclient/tests/identity/v3/fakes.py +++ b/openstackclient/tests/identity/v3/fakes.py @@ -16,6 +16,7 @@ import mock from openstackclient.tests import fakes +from openstackclient.tests import utils domain_id = 'd1' @@ -104,3 +105,13 @@ class FakeIdentityv3Client(object): self.users.resource_class = fakes.FakeResource(None, {}) self.auth_token = kwargs['token'] self.management_url = kwargs['endpoint'] + + +class TestIdentityv3(utils.TestCommand): + def setUp(self): + super(TestIdentityv3, self).setUp() + + self.app.client_manager.identity = FakeIdentityv3Client( + endpoint=fakes.AUTH_URL, + token=fakes.AUTH_TOKEN, + ) diff --git a/openstackclient/tests/identity/v3/test_project.py b/openstackclient/tests/identity/v3/test_project.py index 91c15e24..02cb41be 100644 --- a/openstackclient/tests/identity/v3/test_project.py +++ b/openstackclient/tests/identity/v3/test_project.py @@ -18,10 +18,9 @@ import copy from openstackclient.identity.v3 import project from openstackclient.tests import fakes from openstackclient.tests.identity.v3 import fakes as identity_fakes -from openstackclient.tests.identity.v3 import test_identity -class TestProject(test_identity.TestIdentityv3): +class TestProject(identity_fakes.TestIdentityv3): def setUp(self): super(TestProject, self).setUp() diff --git a/openstackclient/tests/identity/v3/test_role.py b/openstackclient/tests/identity/v3/test_role.py index ef2b3e05..040c39dd 100644 --- a/openstackclient/tests/identity/v3/test_role.py +++ b/openstackclient/tests/identity/v3/test_role.py @@ -18,10 +18,9 @@ import copy from openstackclient.identity.v3 import role from openstackclient.tests import fakes from openstackclient.tests.identity.v3 import fakes as identity_fakes -from openstackclient.tests.identity.v3 import test_identity -class TestRole(test_identity.TestIdentityv3): +class TestRole(identity_fakes.TestIdentityv3): def setUp(self): super(TestRole, self).setUp() diff --git a/openstackclient/tests/identity/v3/test_service.py b/openstackclient/tests/identity/v3/test_service.py index 1c3ae21e..10d249c5 100644 --- a/openstackclient/tests/identity/v3/test_service.py +++ b/openstackclient/tests/identity/v3/test_service.py @@ -18,10 +18,9 @@ import copy from openstackclient.identity.v3 import service from openstackclient.tests import fakes from openstackclient.tests.identity.v3 import fakes as identity_fakes -from openstackclient.tests.identity.v3 import test_identity -class TestService(test_identity.TestIdentityv3): +class TestService(identity_fakes.TestIdentityv3): def setUp(self): super(TestService, self).setUp() diff --git a/openstackclient/tests/identity/v3/test_user.py b/openstackclient/tests/identity/v3/test_user.py index 8f195805..4321b047 100644 --- a/openstackclient/tests/identity/v3/test_user.py +++ b/openstackclient/tests/identity/v3/test_user.py @@ -18,10 +18,9 @@ import copy from openstackclient.identity.v3 import user from openstackclient.tests import fakes from openstackclient.tests.identity.v3 import fakes as identity_fakes -from openstackclient.tests.identity.v3 import test_identity -class TestUser(test_identity.TestIdentityv3): +class TestUser(identity_fakes.TestIdentityv3): def setUp(self): super(TestUser, self).setUp() diff --git a/openstackclient/tests/image/test_image.py b/openstackclient/tests/image/test_image.py deleted file mode 100644 index f4c8d72e..00000000 --- a/openstackclient/tests/image/test_image.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2013 OpenStack, LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# - -import mock - -from openstackclient.common import clientmanager -from openstackclient.image import client as image_client -from openstackclient.tests import utils - - -AUTH_TOKEN = "foobar" -AUTH_URL = "http://0.0.0.0" - - -class FakeClient(object): - def __init__(self, endpoint=None, **kwargs): - self.client = mock.MagicMock() - self.client.auth_token = AUTH_TOKEN - self.client.auth_url = AUTH_URL - - -class TestImage(utils.TestCase): - def setUp(self): - super(TestImage, self).setUp() - - api_version = {"image": "2"} - - image_client.API_VERSIONS = { - "2": "openstackclient.tests.image.test_image.FakeClient" - } - - self.cm = clientmanager.ClientManager(token=AUTH_TOKEN, - url=AUTH_URL, - auth_url=AUTH_URL, - api_version=api_version) - - def test_make_client(self): - self.assertEqual(self.cm.image.client.auth_token, AUTH_TOKEN) - self.assertEqual(self.cm.image.client.auth_url, AUTH_URL) diff --git a/openstackclient/tests/identity/v2_0/test_identity.py b/openstackclient/tests/image/v1/__init__.py index 8a50a48a..ebf59b32 100644 --- a/openstackclient/tests/identity/v2_0/test_identity.py +++ b/openstackclient/tests/image/v1/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2013 Nebula Inc. +# Copyright 2013 OpenStack, LLC. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -12,20 +12,3 @@ # License for the specific language governing permissions and limitations # under the License. # - -from openstackclient.tests.identity.v2_0 import fakes -from openstackclient.tests import utils - - -AUTH_TOKEN = "foobar" -AUTH_URL = "http://0.0.0.0" - - -class TestIdentityv2(utils.TestCommand): - def setUp(self): - super(TestIdentityv2, self).setUp() - - self.app.client_manager.identity = fakes.FakeIdentityv2Client( - endpoint=AUTH_URL, - token=AUTH_TOKEN, - ) diff --git a/openstackclient/tests/image/v1/fakes.py b/openstackclient/tests/image/v1/fakes.py new file mode 100644 index 00000000..ea2af84c --- /dev/null +++ b/openstackclient/tests/image/v1/fakes.py @@ -0,0 +1,46 @@ +# Copyright 2013 Nebula Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import mock + +from openstackclient.tests import fakes +from openstackclient.tests import utils + + +image_id = 'im1' +image_name = 'graven' + +IMAGE = { + 'id': image_id, + 'name': image_name +} + + +class FakeImagev1Client(object): + def __init__(self, **kwargs): + self.images = mock.Mock() + self.images.resource_class = fakes.FakeResource(None, {}) + self.auth_token = kwargs['token'] + self.management_url = kwargs['endpoint'] + + +class TestImagev1(utils.TestCommand): + def setUp(self): + super(TestImagev1, self).setUp() + + self.app.client_manager.image = FakeImagev1Client( + endpoint=fakes.AUTH_URL, + token=fakes.AUTH_TOKEN, + ) diff --git a/openstackclient/tests/image/v1/test_image.py b/openstackclient/tests/image/v1/test_image.py new file mode 100644 index 00000000..a410674d --- /dev/null +++ b/openstackclient/tests/image/v1/test_image.py @@ -0,0 +1,63 @@ +# Copyright 2013 Nebula Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import copy + +from openstackclient.image.v1 import image +from openstackclient.tests import fakes +from openstackclient.tests.image.v1 import fakes as image_fakes + + +class TestImage(image_fakes.TestImagev1): + + def setUp(self): + super(TestImage, self).setUp() + + # Get a shortcut to the ServerManager Mock + self.images_mock = self.app.client_manager.image.images + self.images_mock.reset_mock() + + +class TestImageDelete(TestImage): + + def setUp(self): + super(TestImageDelete, self).setUp() + + # This is the return value for utils.find_resource() + self.images_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(image_fakes.IMAGE), + loaded=True, + ) + self.images_mock.delete.return_value = None + + # Get the command object to test + self.cmd = image.DeleteImage(self.app, None) + + def test_image_delete_no_options(self): + arglist = [ + image_fakes.image_id, + ] + verifylist = [ + ('image', image_fakes.image_id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + self.cmd.take_action(parsed_args) + + self.images_mock.delete.assert_called_with( + image_fakes.image_id, + ) diff --git a/openstackclient/tests/image/v2/__init__.py b/openstackclient/tests/image/v2/__init__.py new file mode 100644 index 00000000..ebf59b32 --- /dev/null +++ b/openstackclient/tests/image/v2/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2013 OpenStack, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# diff --git a/openstackclient/tests/image/v2/fakes.py b/openstackclient/tests/image/v2/fakes.py new file mode 100644 index 00000000..96255cd4 --- /dev/null +++ b/openstackclient/tests/image/v2/fakes.py @@ -0,0 +1,49 @@ +# Copyright 2013 Nebula Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import mock + +from openstackclient.tests import fakes +from openstackclient.tests import utils + + +image_id = 'im1' +image_name = 'graven' +image_owner = 'baal' + +IMAGE = { + 'id': image_id, + 'name': image_name, + 'is_public': False, + 'owner': image_owner, +} + + +class FakeImagev2Client(object): + def __init__(self, **kwargs): + self.images = mock.Mock() + self.images.resource_class = fakes.FakeResource(None, {}) + self.auth_token = kwargs['token'] + self.management_url = kwargs['endpoint'] + + +class TestImagev2(utils.TestCommand): + def setUp(self): + super(TestImagev2, self).setUp() + + self.app.client_manager.image = FakeImagev2Client( + endpoint=fakes.AUTH_URL, + token=fakes.AUTH_TOKEN, + ) diff --git a/openstackclient/tests/image/v2/test_image.py b/openstackclient/tests/image/v2/test_image.py new file mode 100644 index 00000000..ef84e2c0 --- /dev/null +++ b/openstackclient/tests/image/v2/test_image.py @@ -0,0 +1,63 @@ +# Copyright 2013 Nebula Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import copy + +from openstackclient.image.v1 import image +from openstackclient.tests import fakes +from openstackclient.tests.image.v2 import fakes as image_fakes + + +class TestImage(image_fakes.TestImagev2): + + def setUp(self): + super(TestImage, self).setUp() + + # Get a shortcut to the ServerManager Mock + self.images_mock = self.app.client_manager.image.images + self.images_mock.reset_mock() + + +class TestImageDelete(TestImage): + + def setUp(self): + super(TestImageDelete, self).setUp() + + # This is the return value for utils.find_resource() + self.images_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(image_fakes.IMAGE), + loaded=True, + ) + self.images_mock.delete.return_value = None + + # Get the command object to test + self.cmd = image.DeleteImage(self.app, None) + + def test_image_delete_no_options(self): + arglist = [ + image_fakes.image_id, + ] + verifylist = [ + ('image', image_fakes.image_id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + self.cmd.take_action(parsed_args) + + self.images_mock.delete.assert_called_with( + image_fakes.image_id, + ) diff --git a/openstackclient/tests/object/fakes.py b/openstackclient/tests/object/v1/fakes.py index fbc784aa..87f6cab6 100644 --- a/openstackclient/tests/object/fakes.py +++ b/openstackclient/tests/object/v1/fakes.py @@ -13,6 +13,10 @@ # under the License. # +from openstackclient.tests import fakes +from openstackclient.tests import utils + + container_name = 'bit-bucket' container_bytes = 1024 container_count = 1 @@ -65,3 +69,19 @@ OBJECT_2 = { 'content_type': object_content_type_2, 'last_modified': object_modified_2, } + + +class FakeObjectv1Client(object): + def __init__(self, **kwargs): + self.endpoint = kwargs['endpoint'] + self.token = kwargs['token'] + + +class TestObjectv1(utils.TestCommand): + def setUp(self): + super(TestObjectv1, self).setUp() + + self.app.client_manager.object_store = FakeObjectv1Client( + endpoint=fakes.AUTH_URL, + token=fakes.AUTH_TOKEN, + ) diff --git a/openstackclient/tests/object/v1/lib/test_container.py b/openstackclient/tests/object/v1/lib/test_container.py index 3b9976a1..c3fdea72 100644 --- a/openstackclient/tests/object/v1/lib/test_container.py +++ b/openstackclient/tests/object/v1/lib/test_container.py @@ -19,8 +19,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 import utils +from openstackclient.tests.object.v1 import fakes as object_fakes fake_account = 'q12we34r' @@ -36,12 +35,10 @@ class FakeClient(object): self.token = fake_auth -class TestContainer(utils.TestCommand): +class TestContainer(object_fakes.TestObjectv1): def setUp(self): super(TestContainer, self).setUp() - self.app.client_manager = fakes.FakeClientManager() - self.app.client_manager.object = FakeClient() self.app.restapi = mock.MagicMock() @@ -53,7 +50,7 @@ class TestContainerList(TestContainer): data = lib_container.list_containers( self.app.restapi, - self.app.client_manager.object.endpoint, + fake_url, ) # Check expected values @@ -69,7 +66,7 @@ class TestContainerList(TestContainer): data = lib_container.list_containers( self.app.restapi, - self.app.client_manager.object.endpoint, + fake_url, marker='next', ) @@ -86,7 +83,7 @@ class TestContainerList(TestContainer): data = lib_container.list_containers( self.app.restapi, - self.app.client_manager.object.endpoint, + fake_url, limit=5, ) @@ -103,7 +100,7 @@ class TestContainerList(TestContainer): data = lib_container.list_containers( self.app.restapi, - self.app.client_manager.object.endpoint, + fake_url, end_marker='last', ) @@ -120,7 +117,7 @@ class TestContainerList(TestContainer): data = lib_container.list_containers( self.app.restapi, - self.app.client_manager.object.endpoint, + fake_url, prefix='foo/', ) @@ -147,7 +144,7 @@ class TestContainerList(TestContainer): data = lib_container.list_containers( self.app.restapi, - self.app.client_manager.object.endpoint, + fake_url, full_listing=True, ) @@ -171,7 +168,7 @@ class TestContainerShow(TestContainer): data = lib_container.show_container( self.app.restapi, - self.app.client_manager.object.endpoint, + fake_url, 'is-name', ) diff --git a/openstackclient/tests/object/v1/lib/test_object.py b/openstackclient/tests/object/v1/lib/test_object.py index 0104183e..ef93877a 100644 --- a/openstackclient/tests/object/v1/lib/test_object.py +++ b/openstackclient/tests/object/v1/lib/test_object.py @@ -19,8 +19,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 import utils +from openstackclient.tests.object.v1 import fakes as object_fakes fake_account = 'q12we34r' @@ -37,12 +36,10 @@ class FakeClient(object): self.token = fake_auth -class TestObject(utils.TestCommand): +class TestObject(object_fakes.TestObjectv1): def setUp(self): super(TestObject, self).setUp() - self.app.client_manager = fakes.FakeClientManager() - self.app.client_manager.object = FakeClient() self.app.restapi = mock.MagicMock() @@ -54,7 +51,7 @@ class TestObjectListObjects(TestObject): data = lib_object.list_objects( self.app.restapi, - self.app.client_manager.object.endpoint, + fake_url, fake_container, ) @@ -71,7 +68,7 @@ class TestObjectListObjects(TestObject): data = lib_object.list_objects( self.app.restapi, - self.app.client_manager.object.endpoint, + fake_url, fake_container, marker='next', ) @@ -89,7 +86,7 @@ class TestObjectListObjects(TestObject): data = lib_object.list_objects( self.app.restapi, - self.app.client_manager.object.endpoint, + fake_url, fake_container, limit=5, ) @@ -107,7 +104,7 @@ class TestObjectListObjects(TestObject): data = lib_object.list_objects( self.app.restapi, - self.app.client_manager.object.endpoint, + fake_url, fake_container, end_marker='last', ) @@ -125,7 +122,7 @@ class TestObjectListObjects(TestObject): data = lib_object.list_objects( self.app.restapi, - self.app.client_manager.object.endpoint, + fake_url, fake_container, delimiter='|', ) @@ -146,7 +143,7 @@ class TestObjectListObjects(TestObject): data = lib_object.list_objects( self.app.restapi, - self.app.client_manager.object.endpoint, + fake_url, fake_container, prefix='foo/', ) @@ -164,7 +161,7 @@ class TestObjectListObjects(TestObject): data = lib_object.list_objects( self.app.restapi, - self.app.client_manager.object.endpoint, + fake_url, fake_container, path='next', ) @@ -192,7 +189,7 @@ class TestObjectListObjects(TestObject): data = lib_object.list_objects( self.app.restapi, - self.app.client_manager.object.endpoint, + fake_url, fake_container, full_listing=True, ) @@ -216,7 +213,7 @@ class TestObjectShowObjects(TestObject): data = lib_object.show_object( self.app.restapi, - self.app.client_manager.object.endpoint, + fake_url, fake_container, fake_object, ) @@ -250,7 +247,7 @@ class TestObjectShowObjects(TestObject): data = lib_object.show_object( self.app.restapi, - self.app.client_manager.object.endpoint, + fake_url, fake_container, fake_object, ) diff --git a/openstackclient/tests/object/test_container.py b/openstackclient/tests/object/v1/test_container.py index 24d67633..4afb1006 100644 --- a/openstackclient/tests/object/test_container.py +++ b/openstackclient/tests/object/v1/test_container.py @@ -16,10 +16,8 @@ import copy import mock -from openstackclient.common import clientmanager from openstackclient.object.v1 import container -from openstackclient.tests.object import fakes as object_fakes -from openstackclient.tests import utils +from openstackclient.tests.object.v1 import fakes as object_fakes AUTH_TOKEN = "foobar" @@ -32,24 +30,22 @@ class FakeClient(object): self.token = AUTH_TOKEN -class TestObject(utils.TestCommand): +class TestObject(object_fakes.TestObjectv1): def setUp(self): super(TestObject, self).setUp() - api_version = {"object-store": "1"} - self.app.client_manager = clientmanager.ClientManager( - token=AUTH_TOKEN, - url=AUTH_URL, - auth_url=AUTH_URL, - api_version=api_version, - ) - class TestObjectClient(TestObject): def test_make_client(self): - self.assertEqual(self.app.client_manager.object.endpoint, AUTH_URL) - self.assertEqual(self.app.client_manager.object.token, AUTH_TOKEN) + self.assertEqual( + self.app.client_manager.object_store.endpoint, + AUTH_URL, + ) + self.assertEqual( + self.app.client_manager.object_store.token, + AUTH_TOKEN, + ) @mock.patch( diff --git a/openstackclient/tests/object/test_object.py b/openstackclient/tests/object/v1/test_object.py index 1ceb0a59..bea0d270 100644 --- a/openstackclient/tests/object/test_object.py +++ b/openstackclient/tests/object/v1/test_object.py @@ -16,40 +16,30 @@ import copy import mock -from openstackclient.common import clientmanager from openstackclient.object.v1 import object as obj -from openstackclient.tests.object import fakes as object_fakes -from openstackclient.tests import utils +from openstackclient.tests.object.v1 import fakes as object_fakes AUTH_TOKEN = "foobar" AUTH_URL = "http://0.0.0.0" -class FakeClient(object): - def __init__(self, endpoint=None, **kwargs): - self.endpoint = AUTH_URL - self.token = AUTH_TOKEN - - -class TestObject(utils.TestCommand): +class TestObject(object_fakes.TestObjectv1): def setUp(self): super(TestObject, self).setUp() - api_version = {"object-store": "1"} - self.app.client_manager = clientmanager.ClientManager( - token=AUTH_TOKEN, - url=AUTH_URL, - auth_url=AUTH_URL, - api_version=api_version, - ) - class TestObjectClient(TestObject): def test_make_client(self): - self.assertEqual(self.app.client_manager.object.endpoint, AUTH_URL) - self.assertEqual(self.app.client_manager.object.token, AUTH_TOKEN) + self.assertEqual( + self.app.client_manager.object_store.endpoint, + AUTH_URL, + ) + self.assertEqual( + self.app.client_manager.object_store.token, + AUTH_TOKEN, + ) @mock.patch( diff --git a/openstackclient/tests/volume/v1/fakes.py b/openstackclient/tests/volume/v1/fakes.py index a382dbb8..b25dfaf7 100644 --- a/openstackclient/tests/volume/v1/fakes.py +++ b/openstackclient/tests/volume/v1/fakes.py @@ -16,6 +16,9 @@ import mock from openstackclient.tests import fakes +from openstackclient.tests.identity.v2_0 import fakes as identity_fakes +from openstackclient.tests import utils + volume_id = 'vvvvvvvv-vvvv-vvvv-vvvvvvvv' volume_name = 'nigel' @@ -42,3 +45,18 @@ class FakeVolumev1Client(object): self.services.resource_class = fakes.FakeResource(None, {}) self.auth_token = kwargs['token'] self.management_url = kwargs['endpoint'] + + +class TestVolumev1(utils.TestCommand): + def setUp(self): + super(TestVolumev1, self).setUp() + + self.app.client_manager.volume = FakeVolumev1Client( + endpoint=fakes.AUTH_URL, + token=fakes.AUTH_TOKEN, + ) + + self.app.client_manager.identity = identity_fakes.FakeIdentityv2Client( + endpoint=fakes.AUTH_URL, + token=fakes.AUTH_TOKEN, + ) diff --git a/openstackclient/tests/volume/v1/test_volume.py b/openstackclient/tests/volume/v1/test_volume.py index 58024f0b..4e033dfe 100644 --- a/openstackclient/tests/volume/v1/test_volume.py +++ b/openstackclient/tests/volume/v1/test_volume.py @@ -1,4 +1,4 @@ -# Copyright 2013 OpenStack, LLC. +# Copyright 2013 Nebula Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -13,25 +13,256 @@ # under the License. # +import copy + +from openstackclient.tests import fakes from openstackclient.tests.identity.v2_0 import fakes as identity_fakes -from openstackclient.tests import utils -from openstackclient.tests.volume.v1 import fakes +from openstackclient.tests.volume.v1 import fakes as volume_fakes +from openstackclient.volume.v1 import volume + + +class TestVolume(volume_fakes.TestVolumev1): + + def setUp(self): + super(TestVolume, self).setUp() + # Get a shortcut to the VolumeManager Mock + self.volumes_mock = self.app.client_manager.volume.volumes + self.volumes_mock.reset_mock() -AUTH_TOKEN = "foobar" -AUTH_URL = "http://0.0.0.0" + # Get a shortcut to the TenantManager Mock + self.projects_mock = self.app.client_manager.identity.tenants + self.projects_mock.reset_mock() + # Get a shortcut to the UserManager Mock + self.users_mock = self.app.client_manager.identity.users + self.users_mock.reset_mock() + + +# TODO(dtroyer): The volume create tests are incomplete, only the minimal +# options and the options that require additional processing +# are implemented at this time. + +class TestVolumeCreate(TestVolume): -class TestVolumev1(utils.TestCommand): def setUp(self): - super(TestVolumev1, self).setUp() + super(TestVolumeCreate, self).setUp() + + self.volumes_mock.create.return_value = fakes.FakeResource( + None, + copy.deepcopy(volume_fakes.VOLUME), + loaded=True, + ) + + # Get the command object to test + self.cmd = volume.CreateVolume(self.app, None) + + def test_volume_create_min_options(self): + arglist = [ + '--size', str(volume_fakes.volume_size), + volume_fakes.volume_name, + ] + verifylist = [ + ('size', volume_fakes.volume_size), + ('name', volume_fakes.volume_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 = { + # 'metadata': volume_fakes.volume_metadata, + #} + # VolumeManager.create(size, snapshot_id=, source_volid=, + # display_name=, display_description=, + # volume_type=, user_id=, + # project_id=, availability_zone=, + # metadata=, imageRef=) + self.volumes_mock.create.assert_called_with( + volume_fakes.volume_size, + None, + None, + volume_fakes.volume_name, + None, + None, + None, + None, + None, + None, + None, + ) + + collist = ( + 'attach_status', + 'display_description', + 'display_name', + 'id', + 'properties', + 'size', + 'status', + ) + self.assertEqual(columns, collist) + datalist = ( + 'detatched', + volume_fakes.volume_description, + volume_fakes.volume_name, + volume_fakes.volume_id, + '', + volume_fakes.volume_size, + '', + ) + self.assertEqual(data, datalist) + + def test_volume_create_user_project_id(self): + # Return a project + self.projects_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.PROJECT), + loaded=True, + ) + # Return a user + self.users_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.USER), + loaded=True, + ) + + arglist = [ + '--size', str(volume_fakes.volume_size), + '--project', identity_fakes.project_id, + '--user', identity_fakes.user_id, + volume_fakes.volume_name, + ] + verifylist = [ + ('size', volume_fakes.volume_size), + ('project', identity_fakes.project_id), + ('user', identity_fakes.user_id), + ('name', volume_fakes.volume_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.app.client_manager.volume = fakes.FakeVolumev1Client( - endpoint=AUTH_URL, - token=AUTH_TOKEN, + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # Set expected values + #kwargs = { + # 'metadata': volume_fakes.volume_metadata, + #} + # VolumeManager.create(size, snapshot_id=, source_volid=, + # display_name=, display_description=, + # volume_type=, user_id=, + # project_id=, availability_zone=, + # metadata=, imageRef=) + self.volumes_mock.create.assert_called_with( + volume_fakes.volume_size, + None, + None, + volume_fakes.volume_name, + #volume_fakes.volume_description, + None, + None, + identity_fakes.user_id, + identity_fakes.project_id, + None, + None, + None, + ) + + collist = ( + 'attach_status', + 'display_description', + 'display_name', + 'id', + 'properties', + 'size', + 'status', + ) + self.assertEqual(columns, collist) + datalist = ( + 'detatched', + volume_fakes.volume_description, + volume_fakes.volume_name, + volume_fakes.volume_id, + '', + volume_fakes.volume_size, + '', ) + self.assertEqual(data, datalist) - self.app.client_manager.identity = identity_fakes.FakeIdentityv2Client( - endpoint=AUTH_URL, - token=AUTH_TOKEN, + def test_volume_create_user_project_name(self): + # Return a project + self.projects_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.PROJECT), + loaded=True, + ) + # Return a user + self.users_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.USER), + loaded=True, + ) + + arglist = [ + '--size', str(volume_fakes.volume_size), + '--project', identity_fakes.project_name, + '--user', identity_fakes.user_name, + volume_fakes.volume_name, + ] + verifylist = [ + ('size', volume_fakes.volume_size), + ('project', identity_fakes.project_name), + ('user', identity_fakes.user_name), + ('name', volume_fakes.volume_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 = { + # 'metadata': volume_fakes.volume_metadata, + #} + # VolumeManager.create(size, snapshot_id=, source_volid=, + # display_name=, display_description=, + # volume_type=, user_id=, + # project_id=, availability_zone=, + # metadata=, imageRef=) + self.volumes_mock.create.assert_called_with( + volume_fakes.volume_size, + None, + None, + volume_fakes.volume_name, + #volume_fakes.volume_description, + None, + None, + identity_fakes.user_id, + identity_fakes.project_id, + None, + None, + None, + ) + + collist = ( + 'attach_status', + 'display_description', + 'display_name', + 'id', + 'properties', + 'size', + 'status', + ) + self.assertEqual(columns, collist) + datalist = ( + 'detatched', + volume_fakes.volume_description, + volume_fakes.volume_name, + volume_fakes.volume_id, + '', + volume_fakes.volume_size, + '', ) + self.assertEqual(data, datalist) diff --git a/openstackclient/tests/volume/v1/test_volumecmd.py b/openstackclient/tests/volume/v1/test_volumecmd.py deleted file mode 100644 index 1f5ed882..00000000 --- a/openstackclient/tests/volume/v1/test_volumecmd.py +++ /dev/null @@ -1,269 +0,0 @@ -# Copyright 2013 Nebula Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# - -import copy - -from openstackclient.tests import fakes -from openstackclient.tests.identity.v2_0 import fakes as identity_fakes -from openstackclient.tests.volume.v1 import fakes as volume_fakes -from openstackclient.tests.volume.v1 import test_volume -from openstackclient.volume.v1 import volume - - -class TestVolume(test_volume.TestVolumev1): - - def setUp(self): - super(TestVolume, self).setUp() - - # Get a shortcut to the VolumeManager Mock - self.volumes_mock = self.app.client_manager.volume.volumes - self.volumes_mock.reset_mock() - - # Get a shortcut to the TenantManager Mock - self.projects_mock = self.app.client_manager.identity.tenants - self.projects_mock.reset_mock() - - # Get a shortcut to the UserManager Mock - self.users_mock = self.app.client_manager.identity.users - self.users_mock.reset_mock() - - -# TODO(dtroyer): The volume create tests are incomplete, only the minimal -# options and the options that require additional processing -# are implemented at this time. - -class TestVolumeCreate(TestVolume): - - def setUp(self): - super(TestVolumeCreate, self).setUp() - - self.volumes_mock.create.return_value = fakes.FakeResource( - None, - copy.deepcopy(volume_fakes.VOLUME), - loaded=True, - ) - - # Get the command object to test - self.cmd = volume.CreateVolume(self.app, None) - - def test_volume_create_min_options(self): - arglist = [ - '--size', str(volume_fakes.volume_size), - volume_fakes.volume_name, - ] - verifylist = [ - ('size', volume_fakes.volume_size), - ('name', volume_fakes.volume_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 = { - # 'metadata': volume_fakes.volume_metadata, - #} - # VolumeManager.create(size, snapshot_id=, source_volid=, - # display_name=, display_description=, - # volume_type=, user_id=, - # project_id=, availability_zone=, - # metadata=, imageRef=) - self.volumes_mock.create.assert_called_with( - volume_fakes.volume_size, - None, - None, - volume_fakes.volume_name, - None, - None, - None, - None, - None, - None, - None, - ) - - collist = ( - 'attach_status', - 'display_description', - 'display_name', - 'id', - 'properties', - 'size', - 'status', - ) - self.assertEqual(columns, collist) - datalist = ( - 'detatched', - volume_fakes.volume_description, - volume_fakes.volume_name, - volume_fakes.volume_id, - '', - volume_fakes.volume_size, - '', - ) - self.assertEqual(data, datalist) - - def test_volume_create_user_project_id(self): - # Return a project - self.projects_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.PROJECT), - loaded=True, - ) - # Return a user - self.users_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.USER), - loaded=True, - ) - - arglist = [ - '--size', str(volume_fakes.volume_size), - '--project', identity_fakes.project_id, - '--user', identity_fakes.user_id, - volume_fakes.volume_name, - ] - verifylist = [ - ('size', volume_fakes.volume_size), - ('project', identity_fakes.project_id), - ('user', identity_fakes.user_id), - ('name', volume_fakes.volume_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 = { - # 'metadata': volume_fakes.volume_metadata, - #} - # VolumeManager.create(size, snapshot_id=, source_volid=, - # display_name=, display_description=, - # volume_type=, user_id=, - # project_id=, availability_zone=, - # metadata=, imageRef=) - self.volumes_mock.create.assert_called_with( - volume_fakes.volume_size, - None, - None, - volume_fakes.volume_name, - #volume_fakes.volume_description, - None, - None, - identity_fakes.user_id, - identity_fakes.project_id, - None, - None, - None, - ) - - collist = ( - 'attach_status', - 'display_description', - 'display_name', - 'id', - 'properties', - 'size', - 'status', - ) - self.assertEqual(columns, collist) - datalist = ( - 'detatched', - volume_fakes.volume_description, - volume_fakes.volume_name, - volume_fakes.volume_id, - '', - volume_fakes.volume_size, - '', - ) - self.assertEqual(data, datalist) - - def test_volume_create_user_project_name(self): - # Return a project - self.projects_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.PROJECT), - loaded=True, - ) - # Return a user - self.users_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.USER), - loaded=True, - ) - - arglist = [ - '--size', str(volume_fakes.volume_size), - '--project', identity_fakes.project_name, - '--user', identity_fakes.user_name, - volume_fakes.volume_name, - ] - verifylist = [ - ('size', volume_fakes.volume_size), - ('project', identity_fakes.project_name), - ('user', identity_fakes.user_name), - ('name', volume_fakes.volume_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 = { - # 'metadata': volume_fakes.volume_metadata, - #} - # VolumeManager.create(size, snapshot_id=, source_volid=, - # display_name=, display_description=, - # volume_type=, user_id=, - # project_id=, availability_zone=, - # metadata=, imageRef=) - self.volumes_mock.create.assert_called_with( - volume_fakes.volume_size, - None, - None, - volume_fakes.volume_name, - #volume_fakes.volume_description, - None, - None, - identity_fakes.user_id, - identity_fakes.project_id, - None, - None, - None, - ) - - collist = ( - 'attach_status', - 'display_description', - 'display_name', - 'id', - 'properties', - 'size', - 'status', - ) - self.assertEqual(columns, collist) - datalist = ( - 'detatched', - volume_fakes.volume_description, - volume_fakes.volume_name, - volume_fakes.volume_id, - '', - volume_fakes.volume_size, - '', - ) - self.assertEqual(data, datalist) diff --git a/openstackclient/volume/client.py b/openstackclient/volume/client.py index 626b23f1..e04e8cd7 100644 --- a/openstackclient/volume/client.py +++ b/openstackclient/volume/client.py @@ -20,6 +20,8 @@ from openstackclient.common import utils LOG = logging.getLogger(__name__) +DEFAULT_VOLUME_API_VERSION = '1' +API_VERSION_OPTION = 'os_volume_api_version' API_NAME = "volume" API_VERSIONS = { "1": "cinderclient.v1.client.Client" @@ -45,3 +47,17 @@ def make_client(instance): ) return client + + +def build_option_parser(parser): + """Hook to add global options""" + parser.add_argument( + '--os-volume-api-version', + metavar='<volume-api-version>', + default=utils.env( + 'OS_VOLUME_API_VERSION', + default=DEFAULT_VOLUME_API_VERSION), + help='Volume API version, default=' + + DEFAULT_VOLUME_API_VERSION + + ' (Env: OS_VOLUME_API_VERSION)') + return parser |
