Merge "Add create and list for volume type v2"
This commit is contained in:
		| @@ -2,7 +2,7 @@ | |||||||
| volume type | volume type | ||||||
| =========== | =========== | ||||||
|  |  | ||||||
| Volume v1 | Volume v1, v2 | ||||||
|  |  | ||||||
| volume type create | volume type create | ||||||
| ------------------ | ------------------ | ||||||
| @@ -13,9 +13,29 @@ Create new volume type | |||||||
| .. code:: bash | .. code:: bash | ||||||
|  |  | ||||||
|     os volume type create |     os volume type create | ||||||
|  |         [--description <description>] | ||||||
|  |         [--public | --private] | ||||||
|         [--property <key=value> [...] ] |         [--property <key=value> [...] ] | ||||||
|         <name> |         <name> | ||||||
|  |  | ||||||
|  | .. option:: --description <description> | ||||||
|  |  | ||||||
|  |     New volume type description | ||||||
|  |  | ||||||
|  |     .. versionadded:: 2 | ||||||
|  |  | ||||||
|  | .. option:: --public | ||||||
|  |  | ||||||
|  |     Volume type is accessible to the public | ||||||
|  |  | ||||||
|  |     .. versionadded:: 2 | ||||||
|  |  | ||||||
|  | .. option:: --private | ||||||
|  |  | ||||||
|  |     Volume type is not accessible to the public | ||||||
|  |  | ||||||
|  |     .. versionadded:: 2 | ||||||
|  |  | ||||||
| .. option:: --property <key=value> | .. option:: --property <key=value> | ||||||
|  |  | ||||||
|     Set a property on this volume type (repeat option to set multiple properties) |     Set a property on this volume type (repeat option to set multiple properties) | ||||||
| @@ -57,6 +77,8 @@ List volume types | |||||||
| volume type set | volume type set | ||||||
| --------------- | --------------- | ||||||
|  |  | ||||||
|  | *Only supported for Volume API v1* | ||||||
|  |  | ||||||
| Set volume type properties | Set volume type properties | ||||||
|  |  | ||||||
| .. program:: volume type set | .. program:: volume type set | ||||||
| @@ -77,6 +99,8 @@ Set volume type properties | |||||||
| volume type unset | volume type unset | ||||||
| ----------------- | ----------------- | ||||||
|  |  | ||||||
|  | *Only supported for Volume API v1* | ||||||
|  |  | ||||||
| Unset volume type properties | Unset volume type properties | ||||||
|  |  | ||||||
| .. program:: volume type unset | .. program:: volume type unset | ||||||
|   | |||||||
| @@ -28,6 +28,135 @@ class TestType(volume_fakes.TestVolume): | |||||||
|         self.types_mock.reset_mock() |         self.types_mock.reset_mock() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class TestTypeCreate(TestType): | ||||||
|  |  | ||||||
|  |     def setUp(self): | ||||||
|  |         super(TestTypeCreate, self).setUp() | ||||||
|  |  | ||||||
|  |         self.types_mock.create.return_value = fakes.FakeResource( | ||||||
|  |             None, | ||||||
|  |             copy.deepcopy(volume_fakes.TYPE), | ||||||
|  |             loaded=True, | ||||||
|  |         ) | ||||||
|  |         # Get the command object to test | ||||||
|  |         self.cmd = volume_type.CreateVolumeType(self.app, None) | ||||||
|  |  | ||||||
|  |     def test_type_create_public(self): | ||||||
|  |         arglist = [ | ||||||
|  |             volume_fakes.type_name, | ||||||
|  |             "--description", volume_fakes.type_description, | ||||||
|  |             "--public" | ||||||
|  |         ] | ||||||
|  |         verifylist = [ | ||||||
|  |             ("name", volume_fakes.type_name), | ||||||
|  |             ("description", volume_fakes.type_description), | ||||||
|  |             ("public", True), | ||||||
|  |             ("private", False), | ||||||
|  |         ] | ||||||
|  |         parsed_args = self.check_parser(self.cmd, arglist, verifylist) | ||||||
|  |  | ||||||
|  |         columns, data = self.cmd.take_action(parsed_args) | ||||||
|  |         self.types_mock.create.assert_called_with( | ||||||
|  |             volume_fakes.type_name, | ||||||
|  |             description=volume_fakes.type_description, | ||||||
|  |             public=True, | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         collist = ( | ||||||
|  |             'description', | ||||||
|  |             'id', | ||||||
|  |             'name', | ||||||
|  |         ) | ||||||
|  |         self.assertEqual(collist, columns) | ||||||
|  |         datalist = ( | ||||||
|  |             volume_fakes.type_description, | ||||||
|  |             volume_fakes.type_id, | ||||||
|  |             volume_fakes.type_name, | ||||||
|  |         ) | ||||||
|  |         self.assertEqual(datalist, data) | ||||||
|  |  | ||||||
|  |     def test_type_create_private(self): | ||||||
|  |         arglist = [ | ||||||
|  |             volume_fakes.type_name, | ||||||
|  |             "--description", volume_fakes.type_description, | ||||||
|  |             "--private" | ||||||
|  |         ] | ||||||
|  |         verifylist = [ | ||||||
|  |             ("name", volume_fakes.type_name), | ||||||
|  |             ("description", volume_fakes.type_description), | ||||||
|  |             ("public", False), | ||||||
|  |             ("private", True), | ||||||
|  |         ] | ||||||
|  |         parsed_args = self.check_parser(self.cmd, arglist, verifylist) | ||||||
|  |  | ||||||
|  |         columns, data = self.cmd.take_action(parsed_args) | ||||||
|  |         self.types_mock.create.assert_called_with( | ||||||
|  |             volume_fakes.type_name, | ||||||
|  |             description=volume_fakes.type_description, | ||||||
|  |             private=True, | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         collist = ( | ||||||
|  |             'description', | ||||||
|  |             'id', | ||||||
|  |             'name', | ||||||
|  |         ) | ||||||
|  |         self.assertEqual(collist, columns) | ||||||
|  |         datalist = ( | ||||||
|  |             volume_fakes.type_description, | ||||||
|  |             volume_fakes.type_id, | ||||||
|  |             volume_fakes.type_name, | ||||||
|  |         ) | ||||||
|  |         self.assertEqual(datalist, data) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class TestTypeList(TestType): | ||||||
|  |     def setUp(self): | ||||||
|  |         super(TestTypeList, self).setUp() | ||||||
|  |  | ||||||
|  |         self.types_mock.list.return_value = [ | ||||||
|  |             fakes.FakeResource( | ||||||
|  |                 None, | ||||||
|  |                 copy.deepcopy(volume_fakes.TYPE), | ||||||
|  |                 loaded=True | ||||||
|  |             ) | ||||||
|  |         ] | ||||||
|  |         # get the command to test | ||||||
|  |         self.cmd = volume_type.ListVolumeType(self.app, None) | ||||||
|  |  | ||||||
|  |     def test_type_list_without_options(self): | ||||||
|  |         arglist = [] | ||||||
|  |         verifylist = [ | ||||||
|  |             ("long", False) | ||||||
|  |         ] | ||||||
|  |         parsed_args = self.check_parser(self.cmd, arglist, verifylist) | ||||||
|  |  | ||||||
|  |         columns, data = self.cmd.take_action(parsed_args) | ||||||
|  |         collist = ["ID", "Name"] | ||||||
|  |         self.assertEqual(collist, columns) | ||||||
|  |         datalist = (( | ||||||
|  |             volume_fakes.type_id, | ||||||
|  |             volume_fakes.type_name, | ||||||
|  |             ),) | ||||||
|  |         self.assertEqual(datalist, tuple(data)) | ||||||
|  |  | ||||||
|  |     def test_type_list_with_options(self): | ||||||
|  |         arglist = ["--long"] | ||||||
|  |         verifylist = [("long", True)] | ||||||
|  |         parsed_args = self.check_parser(self.cmd, arglist, verifylist) | ||||||
|  |  | ||||||
|  |         columns, data = self.cmd.take_action(parsed_args) | ||||||
|  |         collist = ["ID", "Name", "Description", "Properties"] | ||||||
|  |         self.assertEqual(collist, columns) | ||||||
|  |         datalist = (( | ||||||
|  |             volume_fakes.type_id, | ||||||
|  |             volume_fakes.type_name, | ||||||
|  |             volume_fakes.type_description, | ||||||
|  |             "foo='bar'" | ||||||
|  |             ),) | ||||||
|  |         self.assertEqual(datalist, tuple(data)) | ||||||
|  |  | ||||||
|  |  | ||||||
| class TestTypeShow(TestType): | class TestTypeShow(TestType): | ||||||
|     def setUp(self): |     def setUp(self): | ||||||
|         super(TestTypeShow, self).setUp() |         super(TestTypeShow, self).setUp() | ||||||
|   | |||||||
| @@ -17,12 +17,79 @@ | |||||||
| import logging | import logging | ||||||
|  |  | ||||||
| from cliff import command | from cliff import command | ||||||
|  | from cliff import lister | ||||||
| from cliff import show | from cliff import show | ||||||
| import six | import six | ||||||
|  |  | ||||||
|  | from openstackclient.common import parseractions | ||||||
| from openstackclient.common import utils | from openstackclient.common import utils | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class CreateVolumeType(show.ShowOne): | ||||||
|  |     """Create new volume type""" | ||||||
|  |  | ||||||
|  |     log = logging.getLogger(__name__ + ".CreateVolumeType") | ||||||
|  |  | ||||||
|  |     def get_parser(self, prog_name): | ||||||
|  |         parser = super(CreateVolumeType, self).get_parser(prog_name) | ||||||
|  |         parser.add_argument( | ||||||
|  |             "name", | ||||||
|  |             metavar="<name>", | ||||||
|  |             help="New volume type name" | ||||||
|  |         ) | ||||||
|  |         parser.add_argument( | ||||||
|  |             "--description", | ||||||
|  |             metavar="<description>", | ||||||
|  |             help="New volume type description", | ||||||
|  |         ) | ||||||
|  |         public_group = parser.add_mutually_exclusive_group() | ||||||
|  |         public_group.add_argument( | ||||||
|  |             "--public", | ||||||
|  |             dest="public", | ||||||
|  |             action="store_true", | ||||||
|  |             default=False, | ||||||
|  |             help="Volume type is accessible to the public", | ||||||
|  |         ) | ||||||
|  |         public_group.add_argument( | ||||||
|  |             "--private", | ||||||
|  |             dest="private", | ||||||
|  |             action="store_true", | ||||||
|  |             default=False, | ||||||
|  |             help="Volume type is not accessible to the public", | ||||||
|  |         ) | ||||||
|  |         parser.add_argument( | ||||||
|  |             '--property', | ||||||
|  |             metavar='<key=value>', | ||||||
|  |             action=parseractions.KeyValueAction, | ||||||
|  |             help='Property to add for this volume type' | ||||||
|  |                  '(repeat option to set multiple properties)', | ||||||
|  |         ) | ||||||
|  |         return parser | ||||||
|  |  | ||||||
|  |     def take_action(self, parsed_args): | ||||||
|  |         self.log.debug('take_action(%s)', parsed_args) | ||||||
|  |  | ||||||
|  |         volume_client = self.app.client_manager.volume | ||||||
|  |  | ||||||
|  |         kwargs = {} | ||||||
|  |         if parsed_args.public: | ||||||
|  |             kwargs['public'] = True | ||||||
|  |         if parsed_args.private: | ||||||
|  |             kwargs['private'] = True | ||||||
|  |  | ||||||
|  |         volume_type = volume_client.volume_types.create( | ||||||
|  |             parsed_args.name, | ||||||
|  |             description=parsed_args.description, | ||||||
|  |             **kwargs | ||||||
|  |         ) | ||||||
|  |         volume_type._info.pop('extra_specs') | ||||||
|  |         if parsed_args.property: | ||||||
|  |             result = volume_type.set_keys(parsed_args.property) | ||||||
|  |             volume_type._info.update({'properties': utils.format_dict(result)}) | ||||||
|  |  | ||||||
|  |         return zip(*sorted(six.iteritems(volume_type._info))) | ||||||
|  |  | ||||||
|  |  | ||||||
| class DeleteVolumeType(command.Command): | class DeleteVolumeType(command.Command): | ||||||
|     """Delete volume type""" |     """Delete volume type""" | ||||||
|  |  | ||||||
| @@ -46,6 +113,36 @@ class DeleteVolumeType(command.Command): | |||||||
|         return |         return | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class ListVolumeType(lister.Lister): | ||||||
|  |     """List volume types""" | ||||||
|  |  | ||||||
|  |     log = logging.getLogger(__name__ + '.ListVolumeType') | ||||||
|  |  | ||||||
|  |     def get_parser(self, prog_name): | ||||||
|  |         parser = super(ListVolumeType, self).get_parser(prog_name) | ||||||
|  |         parser.add_argument( | ||||||
|  |             '--long', | ||||||
|  |             action='store_true', | ||||||
|  |             default=False, | ||||||
|  |             help='List additional fields in output') | ||||||
|  |         return parser | ||||||
|  |  | ||||||
|  |     def take_action(self, parsed_args): | ||||||
|  |         self.log.debug('take_action(%s)', parsed_args) | ||||||
|  |         if parsed_args.long: | ||||||
|  |             columns = ['ID', 'Name', 'Description', 'Extra Specs'] | ||||||
|  |             column_headers = ['ID', 'Name', 'Description', 'Properties'] | ||||||
|  |         else: | ||||||
|  |             columns = ['ID', 'Name'] | ||||||
|  |             column_headers = columns | ||||||
|  |         data = self.app.client_manager.volume.volume_types.list() | ||||||
|  |         return (column_headers, | ||||||
|  |                 (utils.get_item_properties( | ||||||
|  |                     s, columns, | ||||||
|  |                     formatters={'Extra Specs': utils.format_dict}, | ||||||
|  |                 ) for s in data)) | ||||||
|  |  | ||||||
|  |  | ||||||
| class ShowVolumeType(show.ShowOne): | class ShowVolumeType(show.ShowOne): | ||||||
|     """Display volume type details""" |     """Display volume type details""" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -395,7 +395,9 @@ openstack.volume.v2 = | |||||||
|     volume_delete = openstackclient.volume.v2.volume:DeleteVolume |     volume_delete = openstackclient.volume.v2.volume:DeleteVolume | ||||||
|     volume_show = openstackclient.volume.v2.volume:ShowVolume |     volume_show = openstackclient.volume.v2.volume:ShowVolume | ||||||
|  |  | ||||||
|  |     volume_type_create = openstackclient.volume.v2.volume_type:CreateVolumeType | ||||||
|     volume_type_delete = openstackclient.volume.v2.volume_type:DeleteVolumeType |     volume_type_delete = openstackclient.volume.v2.volume_type:DeleteVolumeType | ||||||
|  |     volume_type_list = openstackclient.volume.v2.volume_type:ListVolumeType | ||||||
|     volume_type_show = openstackclient.volume.v2.volume_type:ShowVolumeType |     volume_type_show = openstackclient.volume.v2.volume_type:ShowVolumeType | ||||||
|  |  | ||||||
|     volume_qos_associate = openstackclient.volume.v2.qos_specs:AssociateQos |     volume_qos_associate = openstackclient.volume.v2.qos_specs:AssociateQos | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Jenkins
					Jenkins