diff options
22 files changed, 527 insertions, 85 deletions
diff --git a/doc/source/command-objects/server.rst b/doc/source/command-objects/server.rst index 6ae4d254..405c1830 100644 --- a/doc/source/command-objects/server.rst +++ b/doc/source/command-objects/server.rst @@ -187,6 +187,7 @@ List servers [--all-projects] [--project <project> [--project-domain <project-domain>]] [--long] + [--marker <server>] .. option:: --reservation-id <reservation-id> @@ -250,6 +251,11 @@ List servers List additional fields in output +.. option:: --marker <server> + + The last server (name or ID) of the previous page. Display list of servers + after marker. Display all servers if not specified. + server lock ----------- @@ -720,3 +726,18 @@ Unset server properties .. describe:: <server> Server (name or ID) + +server unshelve +--------------- + +Unshelve server(s) + +.. program:: server unshelve +.. code:: bash + + os server unshelve + <server> [<server> ...] + +.. describe:: <server> + + Server(s) to unshelve (name or ID) diff --git a/doc/source/command-objects/snapshot.rst b/doc/source/command-objects/snapshot.rst index 7bfd1d92..e05673b8 100644 --- a/doc/source/command-objects/snapshot.rst +++ b/doc/source/command-objects/snapshot.rst @@ -60,6 +60,11 @@ List snapshots .. code:: bash os snapshot list + [--all-projects] + +.. option:: --all-projects + + Include all projects (admin only) .. option:: --long diff --git a/doc/source/command-wrappers.rst b/doc/source/command-wrappers.rst new file mode 100644 index 00000000..b14eccdd --- /dev/null +++ b/doc/source/command-wrappers.rst @@ -0,0 +1,52 @@ +====================== +Command Class Wrappers +====================== + +When we want to deprecate a command, policy says we need to alert the user. +We do this with a message logged at WARNING level before any command output +is emitted. + +OpenStackClient command classes are derived from the ``cliff`` classes. +Cliff uses ``setuptools`` entry points for dispatching the parsed command +to the respective handler classes. This lends itself to modifying the +command execution at run-time. + +The obvious approach to adding the deprecation message would be to just add +the message to the command class ``take_action()`` method directly. But then +the various deprecations are scattered throughout the code base. If we +instead wrap the deprecated command class with a new class we can put all of +the wrappers into a separate, dedicated module. This also lets us leave the +original class unmodified and puts all of the deprecation bits in one place. + +This is an example of a minimal wrapper around a command class that logs a +deprecation message as a warning to the user then calls the original class. + +* Subclass the deprecated command. + +* Set class attribute ``deprecated`` to ``True`` to signal cliff to not + emit help text for this command. + +* Log the deprecation message at WARNING level and refer to the replacement + for the deprecated command in the log warning message. + +* Change the entry point class in ``setup.cfg`` to point to the new class. + +Example Deprecation Class +------------------------- + +.. code-block: python + + class ListFooOld(ListFoo): + """List resources""" + + # This notifies cliff to not display the help for this command + deprecated = True + + log = logging.getLogger('deprecated') + + def take_action(self, parsed_args): + self.log.warning( + "%s is deprecated, use 'foobar list'", + getattr(self, 'cmd_name', 'this command'), + ) + return super(ListFooOld, self).take_action(parsed_args) diff --git a/doc/source/commands.rst b/doc/source/commands.rst index 90aa481e..e0742ab4 100644 --- a/doc/source/commands.rst +++ b/doc/source/commands.rst @@ -183,7 +183,7 @@ Those actions with an opposite action are noted in parens if applicable. * ``revoke`` (``issue``) - revoke a token * ``save`` - download an object locally * ``set`` (``unset``) - set a property on the object, formerly called metadata -* ``shelve`` (``unshelve``) - shelve one or more server +* ``shelve`` (``unshelve``) - shelve one or more servers * ``show`` - display detailed information about the specific object * ``start`` (``stop``) - start one or more servers * ``stop`` (``start``) - stop one or more servers @@ -192,6 +192,7 @@ Those actions with an opposite action are noted in parens if applicable. * ``unpause`` (``pause``) - return one or more paused servers to running state * ``unrescue`` (``rescue``) - return a server to normal boot mode * ``unset`` (``set``) - remove an attribute of the object +* ``unshelve`` (``shelve``) - unshelve one or more servers Implementation diff --git a/doc/source/index.rst b/doc/source/index.rst index 50b1fd24..66afc2b5 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -38,6 +38,7 @@ Developer Documentation developing command-options + command-wrappers Project Goals ------------- diff --git a/openstackclient/common/quota.py b/openstackclient/common/quota.py index c5404f07..8a9b910f 100644 --- a/openstackclient/common/quota.py +++ b/openstackclient/common/quota.py @@ -173,13 +173,19 @@ class ShowQuota(show.ShowOne): return parser def get_compute_volume_quota(self, client, parsed_args): + identity_client = self.app.client_manager.identity + project = utils.find_resource( + identity_client.projects, + parsed_args.project, + ).id + try: if parsed_args.quota_class: - quota = client.quota_classes.get(parsed_args.project) + quota = client.quota_classes.get(project) elif parsed_args.default: - quota = client.quotas.defaults(parsed_args.project) + quota = client.quotas.defaults(project) else: - quota = client.quotas.get(parsed_args.project) + quota = client.quotas.get(project) except Exception as e: if type(e).__name__ == 'EndpointNotFound': return {} diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index 875b9a13..c35f1dd2 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -747,6 +747,14 @@ class ListServer(lister.Lister): default=False, help=_('List additional fields in output'), ) + parser.add_argument( + '--marker', + metavar='<marker>', + default=None, + help=('The last server (name or ID) of the previous page. Display' + ' list of servers after marker. Display all servers if not' + ' specified.') + ) return parser @utils.log_method(log) @@ -830,7 +838,14 @@ class ListServer(lister.Lister): 'Networks', ) mixed_case_fields = [] - data = compute_client.servers.list(search_opts=search_opts) + + marker_id = None + if parsed_args.marker: + marker_id = utils.find_resource(compute_client.servers, + parsed_args.marker).id + + data = compute_client.servers.list(search_opts=search_opts, + marker=marker_id) return (column_headers, (utils.get_item_properties( s, columns, @@ -1352,6 +1367,31 @@ class SetServer(command.Command): raise exceptions.CommandError(msg) +class ShelveServer(command.Command): + """Shelve server(s)""" + + log = logging.getLogger(__name__ + '.ShelveServer') + + def get_parser(self, prog_name): + parser = super(ShelveServer, self).get_parser(prog_name) + parser.add_argument( + 'server', + metavar='<server>', + nargs='+', + help=_('Server(s) to shelve (name or ID)'), + ) + return parser + + @utils.log_method(log) + def take_action(self, parsed_args): + compute_client = self.app.client_manager.compute + for server in parsed_args.server: + utils.find_resource( + compute_client.servers, + server, + ).shelve() + + class ShowServer(show.ShowOne): """Show server details""" @@ -1389,31 +1429,6 @@ class ShowServer(show.ShowOne): return zip(*sorted(six.iteritems(data))) -class ShelveServer(command.Command): - """Shelve server(s)""" - - log = logging.getLogger(__name__ + '.ShelveServer') - - def get_parser(self, prog_name): - parser = super(ShelveServer, self).get_parser(prog_name) - parser.add_argument( - 'server', - metavar='<server>', - nargs='+', - help=_('Server(s) to shelve (name or ID)'), - ) - return parser - - @utils.log_method(log) - def take_action(self, parsed_args): - compute_client = self.app.client_manager.compute - for server in parsed_args.server: - utils.find_resource( - compute_client.servers, - server, - ).shelve() - - class SshServer(command.Command): """Ssh to server""" @@ -1748,3 +1763,28 @@ class UnsetServer(command.Command): server, parsed_args.property, ) + + +class UnshelveServer(command.Command): + """Unshelve server(s)""" + + log = logging.getLogger(__name__ + '.UnshelveServer') + + def get_parser(self, prog_name): + parser = super(UnshelveServer, self).get_parser(prog_name) + parser.add_argument( + 'server', + metavar='<server>', + nargs='+', + help=_('Server(s) to unshelve (name or ID)'), + ) + return parser + + @utils.log_method(log) + def take_action(self, parsed_args): + compute_client = self.app.client_manager.compute + for server in parsed_args.server: + utils.find_resource( + compute_client.servers, + server, + ).unshelve() diff --git a/openstackclient/image/v1/image.py b/openstackclient/image/v1/image.py index 35e9ef43..4ebc8f93 100644 --- a/openstackclient/image/v1/image.py +++ b/openstackclient/image/v1/image.py @@ -354,7 +354,12 @@ class ListImage(lister.Lister): kwargs['public'] = True if parsed_args.private: kwargs['private'] = True - kwargs['detailed'] = bool(parsed_args.property or parsed_args.long) + # Note: We specifically need to do that below to get the 'status' + # column. + # + # Always set kwargs['detailed'] to True, and then filter the columns + # according to whether the --long option is specified or not. + kwargs['detailed'] = True if parsed_args.long: columns = ( @@ -382,7 +387,7 @@ class ListImage(lister.Lister): 'Properties', ) else: - columns = ("ID", "Name") + columns = ("ID", "Name", "Status") column_headers = columns # List of image data received diff --git a/openstackclient/image/v2/image.py b/openstackclient/image/v2/image.py index 5552f033..c0fb5b58 100644 --- a/openstackclient/image/v2/image.py +++ b/openstackclient/image/v2/image.py @@ -417,7 +417,7 @@ class ListImage(lister.Lister): 'Tags', ) else: - columns = ("ID", "Name") + columns = ("ID", "Name", "Status") column_headers = columns # List of image data received diff --git a/openstackclient/tests/common/test_quota.py b/openstackclient/tests/common/test_quota.py index ff711a75..485b8a8b 100644 --- a/openstackclient/tests/common/test_quota.py +++ b/openstackclient/tests/common/test_quota.py @@ -18,6 +18,7 @@ from openstackclient.common import quota from openstackclient.tests.compute.v2 import fakes as compute_fakes from openstackclient.tests import fakes from openstackclient.tests.identity.v2_0 import fakes as identity_fakes +from openstackclient.tests.network.v2 import fakes as network_fakes class FakeQuotaResource(fakes.FakeResource): @@ -41,13 +42,23 @@ class TestQuota(compute_fakes.TestComputev2): super(TestQuota, self).setUp() self.quotas_mock = self.app.client_manager.compute.quotas self.quotas_mock.reset_mock() + self.quotas_class_mock = self.app.client_manager.compute.quota_classes + self.quotas_class_mock.reset_mock() volume_mock = mock.Mock() volume_mock.quotas = mock.Mock() self.app.client_manager.volume = volume_mock self.volume_quotas_mock = volume_mock.quotas self.volume_quotas_mock.reset_mock() + self.volume_quotas_class_mock = \ + self.app.client_manager.volume.quota_classes + self.volume_quotas_class_mock.reset_mock() self.projects_mock = self.app.client_manager.identity.projects self.projects_mock.reset_mock() + self.app.client_manager.auth_ref = mock.Mock() + self.app.client_manager.auth_ref.service_catalog = mock.Mock() + self.service_catalog_mock = \ + self.app.client_manager.auth_ref.service_catalog + self.service_catalog_mock.reset_mock() class TestQuotaSet(TestQuota): @@ -172,3 +183,113 @@ class TestQuotaSet(TestQuota): identity_fakes.project_id, **kwargs ) + + +class TestQuotaShow(TestQuota): + + def setUp(self): + super(TestQuotaShow, self).setUp() + + self.quotas_mock.get.return_value = FakeQuotaResource( + None, + copy.deepcopy(compute_fakes.QUOTA), + loaded=True, + ) + + self.quotas_mock.defaults.return_value = FakeQuotaResource( + None, + copy.deepcopy(compute_fakes.QUOTA), + loaded=True, + ) + + self.volume_quotas_mock.get.return_value = FakeQuotaResource( + None, + copy.deepcopy(compute_fakes.QUOTA), + loaded=True, + ) + + self.volume_quotas_mock.defaults.return_value = FakeQuotaResource( + None, + copy.deepcopy(compute_fakes.QUOTA), + loaded=True, + ) + + self.service_catalog_mock.get_endpoints.return_value = [ + fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.ENDPOINT), + loaded=True, + ) + ] + + self.quotas_class_mock.get.return_value = FakeQuotaResource( + None, + copy.deepcopy(compute_fakes.QUOTA), + loaded=True, + ) + + self.volume_quotas_class_mock.get.return_value = FakeQuotaResource( + None, + copy.deepcopy(compute_fakes.QUOTA), + loaded=True, + ) + + self.projects_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.PROJECT), + loaded=True, + ) + + self.app.client_manager.network = network_fakes.FakeNetworkV2Client( + endpoint=fakes.AUTH_URL, + token=fakes.AUTH_TOKEN, + ) + + self.cmd = quota.ShowQuota(self.app, None) + + def test_quota_show(self): + arglist = [ + identity_fakes.project_name, + ] + verifylist = [ + ('project', identity_fakes.project_name), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + + self.quotas_mock.get.assert_called_with(identity_fakes.project_id) + + def test_quota_show_with_default(self): + arglist = [ + '--default', + identity_fakes.project_name, + ] + verifylist = [ + ('default', True), + ('project', identity_fakes.project_name), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + + self.quotas_mock.defaults.assert_called_with(identity_fakes.project_id) + + def test_quota_show_with_class(self): + arglist = [ + '--class', + identity_fakes.project_name, + ] + verifylist = [ + ('quota_class', True), + ('project', identity_fakes.project_name), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + + self.quotas_class_mock.get.assert_called_with( + identity_fakes.project_id) diff --git a/openstackclient/tests/compute/v2/fakes.py b/openstackclient/tests/compute/v2/fakes.py index 0d6cd430..91cc2bd2 100644 --- a/openstackclient/tests/compute/v2/fakes.py +++ b/openstackclient/tests/compute/v2/fakes.py @@ -25,8 +25,6 @@ from openstackclient.tests import utils from openstackclient.tests.volume.v2 import fakes as volume_fakes -service_id = '1' - extension_name = 'Multinic' extension_namespace = 'http://docs.openstack.org/compute/ext/'\ 'multinic/api/v1.1' @@ -80,6 +78,15 @@ QUOTA_data = tuple(QUOTA[x] for x in sorted(QUOTA)) block_device_mapping = 'vda=' + volume_fakes.volume_name + ':::0' +service_host = 'host_test' +service_binary = 'compute_test' +service_status = 'enabled' +SERVICE = { + 'host': service_host, + 'binary': service_binary, + 'status': service_status, +} + class FakeComputev2Client(object): def __init__(self, **kwargs): @@ -95,6 +102,8 @@ class FakeComputev2Client(object): self.flavors.resource_class = fakes.FakeResource(None, {}) self.quotas = mock.Mock() self.quotas.resource_class = fakes.FakeResource(None, {}) + self.quota_classes = mock.Mock() + self.quota_classes.resource_class = fakes.FakeResource(None, {}) self.volumes = mock.Mock() self.volumes.resource_class = fakes.FakeResource(None, {}) self.auth_token = kwargs['token'] diff --git a/openstackclient/tests/compute/v2/test_server.py b/openstackclient/tests/compute/v2/test_server.py index feb60547..a750ed5d 100644 --- a/openstackclient/tests/compute/v2/test_server.py +++ b/openstackclient/tests/compute/v2/test_server.py @@ -792,6 +792,26 @@ class TestServerResume(TestServer): self.run_method_with_servers('resume', 3) +class TestServerShelve(TestServer): + + def setUp(self): + super(TestServerShelve, self).setUp() + + # Get the command object to test + self.cmd = server.ShelveServer(self.app, None) + + # Set shelve method to be tested. + self.methods = { + 'shelve': None, + } + + def test_shelve_one_server(self): + self.run_method_with_servers('shelve', 1) + + def test_shelve_multi_servers(self): + self.run_method_with_servers('shelve', 3) + + class TestServerStart(TestServer): def setUp(self): @@ -892,6 +912,26 @@ class TestServerUnpause(TestServer): self.run_method_with_servers('unpause', 3) +class TestServerUnshelve(TestServer): + + def setUp(self): + super(TestServerUnshelve, self).setUp() + + # Get the command object to test + self.cmd = server.UnshelveServer(self.app, None) + + # Set unshelve method to be tested. + self.methods = { + 'unshelve': None, + } + + def test_unshelve_one_server(self): + self.run_method_with_servers('unshelve', 1) + + def test_unshelve_multi_servers(self): + self.run_method_with_servers('unshelve', 3) + + class TestServerGeneral(testtools.TestCase): OLD = { 'private': [ @@ -942,23 +982,3 @@ class TestServerGeneral(testtools.TestCase): server._get_ip_address, self.OLD, 'public', [4, 6]) self.assertRaises(exceptions.CommandError, server._get_ip_address, self.OLD, 'private', [6]) - - -class TestShelveServer(TestServer): - - def setUp(self): - super(TestShelveServer, self).setUp() - - # Get the command object to test - self.cmd = server.ShelveServer(self.app, None) - - # Set shelve method to be tested. - self.methods = { - 'shelve': None, - } - - def test_shelve_one_server(self): - self.run_method_with_servers('shelve', 1) - - def test_shelve_multi_servers(self): - self.run_method_with_servers('shelve', 3) diff --git a/openstackclient/tests/compute/v2/test_service.py b/openstackclient/tests/compute/v2/test_service.py index c6db30ac..380fbc4f 100644 --- a/openstackclient/tests/compute/v2/test_service.py +++ b/openstackclient/tests/compute/v2/test_service.py @@ -13,8 +13,11 @@ # under the License. # +import copy + from openstackclient.compute.v2 import service from openstackclient.tests.compute.v2 import fakes as compute_fakes +from openstackclient.tests import fakes class TestService(compute_fakes.TestComputev2): @@ -39,10 +42,10 @@ class TestServiceDelete(TestService): def test_service_delete_no_options(self): arglist = [ - compute_fakes.service_id, + compute_fakes.service_binary, ] verifylist = [ - ('service', compute_fakes.service_id), + ('service', compute_fakes.service_binary), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -50,5 +53,99 @@ class TestServiceDelete(TestService): self.cmd.take_action(parsed_args) self.service_mock.delete.assert_called_with( - compute_fakes.service_id, + compute_fakes.service_binary, + ) + + +class TestServiceList(TestService): + + def setUp(self): + super(TestServiceList, self).setUp() + + self.service_mock.list.return_value = [fakes.FakeResource( + None, + copy.deepcopy(compute_fakes.SERVICE), + loaded=True, + )] + + # Get the command object to test + self.cmd = service.ListService(self.app, None) + + def test_service_list(self): + arglist = [ + '--host', compute_fakes.service_host, + '--service', compute_fakes.service_binary, + ] + verifylist = [ + ('host', compute_fakes.service_host), + ('service', compute_fakes.service_binary), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + self.cmd.take_action(parsed_args) + + self.service_mock.list.assert_called_with( + compute_fakes.service_host, + compute_fakes.service_binary, + ) + + +class TestServiceSet(TestService): + + def setUp(self): + super(TestServiceSet, self).setUp() + + self.service_mock.enable.return_value = [fakes.FakeResource( + None, + copy.deepcopy(compute_fakes.SERVICE), + loaded=True, + )] + + self.service_mock.disable.return_value = [fakes.FakeResource( + None, + copy.deepcopy(compute_fakes.SERVICE), + loaded=True, + )] + + self.cmd = service.SetService(self.app, None) + + def test_service_set_enable(self): + arglist = [ + compute_fakes.service_host, + compute_fakes.service_binary, + '--enable', + ] + verifylist = [ + ('host', compute_fakes.service_host), + ('service', compute_fakes.service_binary), + ('enabled', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + + self.service_mock.enable.assert_called_with( + compute_fakes.service_host, + compute_fakes.service_binary, + ) + + def test_service_set_disable(self): + arglist = [ + compute_fakes.service_host, + compute_fakes.service_binary, + '--disable', + ] + verifylist = [ + ('host', compute_fakes.service_host), + ('service', compute_fakes.service_binary), + ('enabled', False), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + + self.service_mock.disable.assert_called_with( + compute_fakes.service_host, + compute_fakes.service_binary, ) diff --git a/openstackclient/tests/image/v1/test_image.py b/openstackclient/tests/image/v1/test_image.py index d10d3b15..4d964bdb 100644 --- a/openstackclient/tests/image/v1/test_image.py +++ b/openstackclient/tests/image/v1/test_image.py @@ -261,16 +261,17 @@ class TestImageList(TestImage): # DisplayCommandBase.take_action() returns two tuples columns, data = self.cmd.take_action(parsed_args) self.api_mock.image_list.assert_called_with( - detailed=False, + detailed=True, marker=image_fakes.image_id, ) - collist = ('ID', 'Name') + collist = ('ID', 'Name', 'Status') self.assertEqual(collist, columns) datalist = (( image_fakes.image_id, image_fakes.image_name, + '', ), ) self.assertEqual(datalist, tuple(data)) @@ -288,17 +289,18 @@ class TestImageList(TestImage): # DisplayCommandBase.take_action() returns two tuples columns, data = self.cmd.take_action(parsed_args) self.api_mock.image_list.assert_called_with( - detailed=False, + detailed=True, public=True, marker=image_fakes.image_id, ) - collist = ('ID', 'Name') + collist = ('ID', 'Name', 'Status') self.assertEqual(collist, columns) datalist = (( image_fakes.image_id, image_fakes.image_name, + '', ), ) self.assertEqual(datalist, tuple(data)) @@ -316,17 +318,18 @@ class TestImageList(TestImage): # DisplayCommandBase.take_action() returns two tuples columns, data = self.cmd.take_action(parsed_args) self.api_mock.image_list.assert_called_with( - detailed=False, + detailed=True, private=True, marker=image_fakes.image_id, ) - collist = ('ID', 'Name') + collist = ('ID', 'Name', 'Status') self.assertEqual(collist, columns) datalist = (( image_fakes.image_id, image_fakes.image_name, + '', ), ) self.assertEqual(datalist, tuple(data)) @@ -401,12 +404,13 @@ class TestImageList(TestImage): property_field='properties', ) - collist = ('ID', 'Name') + collist = ('ID', 'Name', 'Status') self.assertEqual(columns, collist) datalist = (( image_fakes.image_id, image_fakes.image_name, + '', ), ) self.assertEqual(datalist, tuple(data)) @@ -423,7 +427,7 @@ class TestImageList(TestImage): # DisplayCommandBase.take_action() returns two tuples columns, data = self.cmd.take_action(parsed_args) self.api_mock.image_list.assert_called_with( - detailed=False, + detailed=True, marker=image_fakes.image_id, ) si_mock.assert_called_with( @@ -431,12 +435,13 @@ class TestImageList(TestImage): 'name:asc' ) - collist = ('ID', 'Name') + collist = ('ID', 'Name', 'Status') self.assertEqual(collist, columns) datalist = (( image_fakes.image_id, - image_fakes.image_name + image_fakes.image_name, + '', ), ) self.assertEqual(datalist, tuple(data)) diff --git a/openstackclient/tests/image/v2/test_image.py b/openstackclient/tests/image/v2/test_image.py index f71407a6..be73c4ca 100644 --- a/openstackclient/tests/image/v2/test_image.py +++ b/openstackclient/tests/image/v2/test_image.py @@ -374,12 +374,13 @@ class TestImageList(TestImage): marker=image_fakes.image_id, ) - collist = ('ID', 'Name') + collist = ('ID', 'Name', 'Status') self.assertEqual(collist, columns) datalist = (( image_fakes.image_id, image_fakes.image_name, + '', ), ) self.assertEqual(datalist, tuple(data)) @@ -402,12 +403,13 @@ class TestImageList(TestImage): marker=image_fakes.image_id, ) - collist = ('ID', 'Name') + collist = ('ID', 'Name', 'Status') self.assertEqual(collist, columns) datalist = (( image_fakes.image_id, image_fakes.image_name, + '', ), ) self.assertEqual(datalist, tuple(data)) @@ -430,12 +432,13 @@ class TestImageList(TestImage): marker=image_fakes.image_id, ) - collist = ('ID', 'Name') + collist = ('ID', 'Name', 'Status') self.assertEqual(collist, columns) datalist = (( image_fakes.image_id, image_fakes.image_name, + '', ), ) self.assertEqual(datalist, tuple(data)) @@ -458,12 +461,13 @@ class TestImageList(TestImage): marker=image_fakes.image_id, ) - collist = ('ID', 'Name') + collist = ('ID', 'Name', 'Status') self.assertEqual(columns, collist) datalist = (( image_fakes.image_id, image_fakes.image_name, + '', ), ) self.assertEqual(datalist, tuple(data)) @@ -536,12 +540,13 @@ class TestImageList(TestImage): property_field='properties', ) - collist = ('ID', 'Name') + collist = ('ID', 'Name', 'Status') self.assertEqual(columns, collist) datalist = (( image_fakes.image_id, image_fakes.image_name, + '', ), ) self.assertEqual(datalist, tuple(data)) @@ -565,12 +570,13 @@ class TestImageList(TestImage): 'name:asc' ) - collist = ('ID', 'Name') + collist = ('ID', 'Name', 'Status') self.assertEqual(collist, columns) datalist = (( image_fakes.image_id, - image_fakes.image_name + image_fakes.image_name, + '', ), ) self.assertEqual(datalist, tuple(data)) diff --git a/openstackclient/tests/volume/v2/test_snapshot.py b/openstackclient/tests/volume/v2/test_snapshot.py index 3ceb57fa..3b30d4ef 100644 --- a/openstackclient/tests/volume/v2/test_snapshot.py +++ b/openstackclient/tests/volume/v2/test_snapshot.py @@ -225,6 +225,7 @@ class TestSnapshotList(TestSnapshot): def test_snapshot_list_without_options(self): arglist = [] verifylist = [ + ('all_projects', False), ("long", False) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -243,7 +244,7 @@ class TestSnapshotList(TestSnapshot): def test_snapshot_list_with_options(self): arglist = ["--long"] - verifylist = [("long", True)] + verifylist = [("long", True), ('all_projects', False)] parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) @@ -263,3 +264,33 @@ class TestSnapshotList(TestSnapshot): volume_fakes.EXPECTED_SNAPSHOT.get("properties") ),) self.assertEqual(datalist, tuple(data)) + + def test_snapshot_list_all_projects(self): + arglist = [ + '--all-projects', + ] + verifylist = [ + ('long', False), + ('all_projects', True) + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + collist = [ + "ID", + "Name", + "Description", + "Status", + "Size" + ] + self.assertEqual(collist, columns) + + datalist = (( + volume_fakes.snapshot_id, + volume_fakes.snapshot_name, + volume_fakes.snapshot_description, + "available", + volume_fakes.snapshot_size + ), ) + self.assertEqual(datalist, tuple(data)) diff --git a/openstackclient/tests/volume/v2/test_type.py b/openstackclient/tests/volume/v2/test_type.py index 9a07263b..c63cd1fa 100644 --- a/openstackclient/tests/volume/v2/test_type.py +++ b/openstackclient/tests/volume/v2/test_type.py @@ -73,7 +73,7 @@ class TestTypeCreate(TestType): self.types_mock.create.assert_called_with( volume_fakes.type_name, description=volume_fakes.type_description, - public=True, + is_public=True, ) collist = ( @@ -93,7 +93,7 @@ class TestTypeCreate(TestType): arglist = [ volume_fakes.type_name, "--description", volume_fakes.type_description, - "--private" + "--private", ] verifylist = [ ("name", volume_fakes.type_name), @@ -107,7 +107,7 @@ class TestTypeCreate(TestType): self.types_mock.create.assert_called_with( volume_fakes.type_name, description=volume_fakes.type_description, - private=True, + is_public=False, ) collist = ( diff --git a/openstackclient/volume/v1/snapshot.py b/openstackclient/volume/v1/snapshot.py index de7bb5b9..93e17eb8 100644 --- a/openstackclient/volume/v1/snapshot.py +++ b/openstackclient/volume/v1/snapshot.py @@ -111,6 +111,12 @@ class ListSnapshot(lister.Lister): def get_parser(self, prog_name): parser = super(ListSnapshot, self).get_parser(prog_name) parser.add_argument( + '--all-projects', + action='store_true', + default=False, + help='Include all projects (admin only)', + ) + parser.add_argument( '--long', action='store_true', default=False, @@ -157,7 +163,12 @@ class ListSnapshot(lister.Lister): # Just forget it if there's any trouble pass - data = self.app.client_manager.volume.volume_snapshots.list() + search_opts = { + 'all_tenants': parsed_args.all_projects, + } + + data = self.app.client_manager.volume.volume_snapshots.list( + search_opts=search_opts) return (column_headers, (utils.get_item_properties( s, columns, diff --git a/openstackclient/volume/v2/snapshot.py b/openstackclient/volume/v2/snapshot.py index bbc92c48..aa7630ae 100644 --- a/openstackclient/volume/v2/snapshot.py +++ b/openstackclient/volume/v2/snapshot.py @@ -108,6 +108,12 @@ class ListSnapshot(lister.Lister): def get_parser(self, prog_name): parser = super(ListSnapshot, self).get_parser(prog_name) parser.add_argument( + '--all-projects', + action='store_true', + default=False, + help='Include all projects (admin only)', + ) + parser.add_argument( '--long', action='store_true', default=False, @@ -149,7 +155,12 @@ class ListSnapshot(lister.Lister): # Just forget it if there's any trouble pass - data = self.app.client_manager.volume.volume_snapshots.list() + search_opts = { + 'all_tenants': parsed_args.all_projects, + } + + data = self.app.client_manager.volume.volume_snapshots.list( + search_opts=search_opts) return (column_headers, (utils.get_item_properties( s, columns, diff --git a/openstackclient/volume/v2/volume_type.py b/openstackclient/volume/v2/volume_type.py index 8cca86f9..583e6ed9 100644 --- a/openstackclient/volume/v2/volume_type.py +++ b/openstackclient/volume/v2/volume_type.py @@ -73,9 +73,9 @@ class CreateVolumeType(show.ShowOne): kwargs = {} if parsed_args.public: - kwargs['public'] = True + kwargs['is_public'] = True if parsed_args.private: - kwargs['private'] = True + kwargs['is_public'] = False volume_type = volume_client.volume_types.create( parsed_args.name, @@ -15,7 +15,6 @@ classifier = Programming Language :: Python Programming Language :: Python :: 2 Programming Language :: Python :: 2.7 - Programming Language :: Python :: 2.6 Programming Language :: Python :: 3 Programming Language :: Python :: 3.4 @@ -140,6 +139,7 @@ openstack.compute.v2 = server_unpause = openstackclient.compute.v2.server:UnpauseServer server_unrescue = openstackclient.compute.v2.server:UnrescueServer server_unset = openstackclient.compute.v2.server:UnsetServer + server_unshelve = openstackclient.compute.v2.server:UnshelveServer usage_list = openstackclient.compute.v2.usage:ListUsage usage_show = openstackclient.compute.v2.usage:ShowUsage @@ -1,6 +1,6 @@ [tox] minversion = 1.6 -envlist = py34,py26,py27,pep8 +envlist = py34,py27,pep8 skipdist = True [testenv] |
