diff options
| author | Jenkins <jenkins@review.openstack.org> | 2017-02-18 03:36:06 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2017-02-18 03:36:06 +0000 |
| commit | c88975136d675c947167533191b75c849cd0a1b5 (patch) | |
| tree | e592862adb330eb0184b452e3355a0ffb7eb2405 /openstackclient/volume | |
| parent | ef1a86a802149e0a62c68fb93edf66b802bc72d1 (diff) | |
| parent | b2fd8ba869cd4b8e927118f7712d0ed7fb60309f (diff) | |
| download | python-openstackclient-c88975136d675c947167533191b75c849cd0a1b5.tar.gz | |
Merge "Add "encryption-*" options in volume type commands"
Diffstat (limited to 'openstackclient/volume')
| -rw-r--r-- | openstackclient/volume/v1/volume_type.py | 221 | ||||
| -rw-r--r-- | openstackclient/volume/v2/volume_type.py | 210 |
2 files changed, 419 insertions, 12 deletions
diff --git a/openstackclient/volume/v1/volume_type.py b/openstackclient/volume/v1/volume_type.py index 8adce322..f9baa5be 100644 --- a/openstackclient/volume/v1/volume_type.py +++ b/openstackclient/volume/v1/volume_type.py @@ -29,6 +29,26 @@ from openstackclient.i18n import _ LOG = logging.getLogger(__name__) +def _create_encryption_type(volume_client, volume_type, parsed_args): + if not parsed_args.encryption_provider: + msg = _("'--encryption-provider' should be specified while " + "creating a new encryption type") + raise exceptions.CommandError(msg) + # set the default of control location while creating + control_location = 'front-end' + if parsed_args.encryption_control_location: + control_location = parsed_args.encryption_control_location + body = { + 'provider': parsed_args.encryption_provider, + 'cipher': parsed_args.encryption_cipher, + 'key_size': parsed_args.encryption_key_size, + 'control_location': control_location + } + encryption = volume_client.volume_encryption_types.create( + volume_type, body) + return encryption + + class CreateVolumeType(command.ShowOne): _description = _("Create new volume type") @@ -46,6 +66,42 @@ class CreateVolumeType(command.ShowOne): help=_('Set a property on this volume type ' '(repeat option to set multiple properties)'), ) + # TODO(Huanxuan Ao): Add choices for each "--encryption-*" option. + parser.add_argument( + '--encryption-provider', + metavar='<provider>', + help=_('Set the class that provides encryption support for ' + 'this volume type (e.g "LuksEncryptor") (admin only) ' + '(This option is required when setting encryption type ' + 'of a volume. Consider using other encryption options ' + 'such as: "--encryption-cipher", "--encryption-key-size" ' + 'and "--encryption-control-location")'), + ) + parser.add_argument( + '--encryption-cipher', + metavar='<cipher>', + help=_('Set the encryption algorithm or mode for this ' + 'volume type (e.g "aes-xts-plain64") (admin only)'), + ) + parser.add_argument( + '--encryption-key-size', + metavar='<key-size>', + type=int, + help=_('Set the size of the encryption key of this ' + 'volume type (e.g "128" or "256") (admin only)'), + ) + parser.add_argument( + '--encryption-control-location', + metavar='<control-location>', + choices=['front-end', 'back-end'], + help=_('Set the notional service where the encryption is ' + 'performed ("front-end" or "back-end") (admin only) ' + '(The default value for this option is "front-end" ' + 'when setting encryption type of a volume. Consider ' + 'using other encryption options such as: ' + '"--encryption-cipher", "--encryption-key-size" and ' + '"--encryption-provider")'), + ) return parser def take_action(self, parsed_args): @@ -55,6 +111,21 @@ class CreateVolumeType(command.ShowOne): if parsed_args.property: result = volume_type.set_keys(parsed_args.property) volume_type._info.update({'properties': utils.format_dict(result)}) + if (parsed_args.encryption_provider or + parsed_args.encryption_cipher or + parsed_args.encryption_key_size or + parsed_args.encryption_control_location): + try: + # create new encryption + encryption = _create_encryption_type( + volume_client, volume_type, parsed_args) + except Exception as e: + LOG.error(_("Failed to set encryption information for this " + "volume type: %s"), e) + # add encryption info in result + encryption._info.pop("volume_type_id", None) + volume_type._info.update( + {'encryption': utils.format_dict(encryption._info)}) volume_type._info.pop("os-volume-type-access:is_public", None) return zip(*sorted(six.iteritems(volume_type._info))) @@ -107,20 +178,58 @@ class ListVolumeType(command.Lister): default=False, help=_('List additional fields in output') ) + parser.add_argument( + "--encryption-type", + action="store_true", + help=_("Display encryption information for each volume type " + "(admin only)"), + ) return parser def take_action(self, parsed_args): + volume_client = self.app.client_manager.volume if parsed_args.long: - columns = ('ID', 'Name', 'Is Public', 'Extra Specs') - column_headers = ('ID', 'Name', 'Is Public', 'Properties') + columns = ['ID', 'Name', 'Is Public', 'Extra Specs'] + column_headers = ['ID', 'Name', 'Is Public', 'Properties'] else: - columns = ('ID', 'Name', 'Is Public') - column_headers = columns - data = self.app.client_manager.volume.volume_types.list() + columns = ['ID', 'Name', 'Is Public'] + column_headers = ['ID', 'Name', 'Is Public'] + data = volume_client.volume_types.list() + + def _format_encryption_info(type_id, encryption_data=None): + encryption_data = encryption + encryption_info = '-' + if type_id in encryption_data.keys(): + encryption_info = encryption_data[type_id] + return encryption_info + + if parsed_args.encryption_type: + encryption = {} + for d in volume_client.volume_encryption_types.list(): + volume_type_id = d._info['volume_type_id'] + # remove some redundant information + del_key = [ + 'deleted', + 'created_at', + 'updated_at', + 'deleted_at', + 'volume_type_id' + ] + for key in del_key: + d._info.pop(key, None) + # save the encryption information with their volume type ID + encryption[volume_type_id] = utils.format_dict(d._info) + # We need to get volume type ID, then show encryption + # information according to the ID, so use "id" to keep + # difference to the real "ID" column. + columns += ['id'] + column_headers += ['Encryption'] + return (column_headers, (utils.get_item_properties( s, columns, - formatters={'Extra Specs': utils.format_dict}, + formatters={'Extra Specs': utils.format_dict, + 'id': _format_encryption_info}, ) for s in data)) @@ -141,6 +250,42 @@ class SetVolumeType(command.Command): help=_('Set a property on this volume type ' '(repeat option to set multiple properties)'), ) + # TODO(Huanxuan Ao): Add choices for each "--encryption-*" option. + parser.add_argument( + '--encryption-provider', + metavar='<provider>', + help=_('Set the class that provides encryption support for ' + 'this volume type (e.g "LuksEncryptor") (admin only) ' + '(This option is required when setting encryption type ' + 'of a volume. Consider using other encryption options ' + 'such as: "--encryption-cipher", "--encryption-key-size" ' + 'and "--encryption-control-location")'), + ) + parser.add_argument( + '--encryption-cipher', + metavar='<cipher>', + help=_('Set the encryption algorithm or mode for this ' + 'volume type (e.g "aes-xts-plain64") (admin only)'), + ) + parser.add_argument( + '--encryption-key-size', + metavar='<key-size>', + type=int, + help=_('Set the size of the encryption key of this ' + 'volume type (e.g "128" or "256") (admin only)'), + ) + parser.add_argument( + '--encryption-control-location', + metavar='<control-location>', + choices=['front-end', 'back-end'], + help=_('Set the notional service where the encryption is ' + 'performed ("front-end" or "back-end") (admin only) ' + '(The default value for this option is "front-end" ' + 'when setting encryption type of a volume. Consider ' + 'using other encryption options such as: ' + '"--encryption-cipher", "--encryption-key-size" and ' + '"--encryption-provider")'), + ) return parser def take_action(self, parsed_args): @@ -148,8 +293,29 @@ class SetVolumeType(command.Command): volume_type = utils.find_resource( volume_client.volume_types, parsed_args.volume_type) + result = 0 if parsed_args.property: - volume_type.set_keys(parsed_args.property) + try: + volume_type.set_keys(parsed_args.property) + except Exception as e: + LOG.error(_("Failed to set volume type property: %s"), e) + result += 1 + + if (parsed_args.encryption_provider or + parsed_args.encryption_cipher or + parsed_args.encryption_key_size or + parsed_args.encryption_control_location): + try: + _create_encryption_type( + volume_client, volume_type, parsed_args) + except Exception as e: + LOG.error(_("Failed to set encryption information for this " + "volume type: %s"), e) + result += 1 + + if result > 0: + raise exceptions.CommandError(_("Command Failed: One or more of" + " the operations failed")) class ShowVolumeType(command.ShowOne): @@ -162,6 +328,12 @@ class ShowVolumeType(command.ShowOne): metavar="<volume-type>", help=_("Volume type to display (name or ID)") ) + parser.add_argument( + "--encryption-type", + action="store_true", + help=_("Display encryption information of this volume type " + "(admin only)"), + ) return parser def take_action(self, parsed_args): @@ -170,6 +342,17 @@ class ShowVolumeType(command.ShowOne): volume_client.volume_types, parsed_args.volume_type) properties = utils.format_dict(volume_type._info.pop('extra_specs')) volume_type._info.update({'properties': properties}) + if parsed_args.encryption_type: + # show encryption type information for this volume type + try: + encryption = volume_client.volume_encryption_types.get( + volume_type.id) + encryption._info.pop("volume_type_id", None) + volume_type._info.update( + {'encryption': utils.format_dict(encryption._info)}) + except Exception as e: + LOG.error(_("Failed to display the encryption information " + "of this volume type: %s"), e) volume_type._info.pop("os-volume-type-access:is_public", None) return zip(*sorted(six.iteritems(volume_type._info))) @@ -191,6 +374,12 @@ class UnsetVolumeType(command.Command): help=_('Remove a property from this volume type ' '(repeat option to remove multiple properties)'), ) + parser.add_argument( + "--encryption-type", + action="store_true", + help=_("Remove the encryption type for this volume type " + "(admin oly)"), + ) return parser def take_action(self, parsed_args): @@ -200,5 +389,21 @@ class UnsetVolumeType(command.Command): parsed_args.volume_type, ) + result = 0 if parsed_args.property: - volume_type.unset_keys(parsed_args.property) + try: + volume_type.unset_keys(parsed_args.property) + except Exception as e: + LOG.error(_("Failed to unset volume type property: %s"), e) + result += 1 + if parsed_args.encryption_type: + try: + volume_client.volume_encryption_types.delete(volume_type) + except Exception as e: + LOG.error(_("Failed to remove the encryption type for this " + "volume type: %s"), e) + result += 1 + + if result > 0: + raise exceptions.CommandError(_("Command Failed: One or more of" + " the operations failed")) diff --git a/openstackclient/volume/v2/volume_type.py b/openstackclient/volume/v2/volume_type.py index 46466783..8d2901f2 100644 --- a/openstackclient/volume/v2/volume_type.py +++ b/openstackclient/volume/v2/volume_type.py @@ -29,6 +29,44 @@ from openstackclient.identity import common as identity_common LOG = logging.getLogger(__name__) +def _create_encryption_type(volume_client, volume_type, parsed_args): + if not parsed_args.encryption_provider: + msg = _("'--encryption-provider' should be specified while " + "creating a new encryption type") + raise exceptions.CommandError(msg) + # set the default of control location while creating + control_location = 'front-end' + if parsed_args.encryption_control_location: + control_location = parsed_args.encryption_control_location + body = { + 'provider': parsed_args.encryption_provider, + 'cipher': parsed_args.encryption_cipher, + 'key_size': parsed_args.encryption_key_size, + 'control_location': control_location + } + encryption = volume_client.volume_encryption_types.create( + volume_type, body) + return encryption + + +def _set_encryption_type(volume_client, volume_type, parsed_args): + # update the existing encryption type + body = {} + for attr in ['provider', 'cipher', 'key_size', 'control_location']: + info = getattr(parsed_args, 'encryption_' + attr, None) + if info is not None: + body[attr] = info + try: + volume_client.volume_encryption_types.update(volume_type, body) + except Exception as e: + if type(e).__name__ == 'NotFound': + # create new encryption type + LOG.warning(_("No existing encryption type found, creating " + "new encryption type for this volume type ...")) + _create_encryption_type( + volume_client, volume_type, parsed_args) + + class CreateVolumeType(command.ShowOne): _description = _("Create new volume type") @@ -70,6 +108,42 @@ class CreateVolumeType(command.ShowOne): help=_("Allow <project> to access private type (name or ID) " "(Must be used with --private option)"), ) + # TODO(Huanxuan Ao): Add choices for each "--encryption-*" option. + parser.add_argument( + '--encryption-provider', + metavar='<provider>', + help=_('Set the class that provides encryption support for ' + 'this volume type (e.g "LuksEncryptor") (admin only) ' + '(This option is required when setting encryption type ' + 'of a volume. Consider using other encryption options ' + 'such as: "--encryption-cipher", "--encryption-key-size" ' + 'and "--encryption-control-location")'), + ) + parser.add_argument( + '--encryption-cipher', + metavar='<cipher>', + help=_('Set the encryption algorithm or mode for this ' + 'volume type (e.g "aes-xts-plain64") (admin only)'), + ) + parser.add_argument( + '--encryption-key-size', + metavar='<key-size>', + type=int, + help=_('Set the size of the encryption key of this ' + 'volume type (e.g "128" or "256") (admin only)'), + ) + parser.add_argument( + '--encryption-control-location', + metavar='<control-location>', + choices=['front-end', 'back-end'], + help=_('Set the notional service where the encryption is ' + 'performed ("front-end" or "back-end") (admin only) ' + '(The default value for this option is "front-end" ' + 'when setting encryption type of a volume. Consider ' + 'using other encryption options such as: ' + '"--encryption-cipher", "--encryption-key-size" and ' + '"--encryption-provider")'), + ) identity_common.add_project_domain_option_to_parser(parser) return parser @@ -110,6 +184,21 @@ class CreateVolumeType(command.ShowOne): if parsed_args.property: result = volume_type.set_keys(parsed_args.property) volume_type._info.update({'properties': utils.format_dict(result)}) + if (parsed_args.encryption_provider or + parsed_args.encryption_cipher or + parsed_args.encryption_key_size or + parsed_args.encryption_control_location): + try: + # create new encryption + encryption = _create_encryption_type( + volume_client, volume_type, parsed_args) + except Exception as e: + LOG.error(_("Failed to set encryption information for this " + "volume type: %s"), e) + # add encryption info in result + encryption._info.pop("volume_type_id", None) + volume_type._info.update( + {'encryption': utils.format_dict(encryption._info)}) volume_type._info.pop("os-volume-type-access:is_public", None) return zip(*sorted(six.iteritems(volume_type._info))) @@ -179,6 +268,12 @@ class ListVolumeType(command.Lister): action="store_true", help=_("List only private types (admin only)") ) + parser.add_argument( + "--encryption-type", + action="store_true", + help=_("Display encryption information for each volume type " + "(admin only)"), + ) return parser def take_action(self, parsed_args): @@ -189,7 +284,7 @@ class ListVolumeType(command.Lister): 'ID', 'Name', 'Is Public', 'Description', 'Properties'] else: columns = ['ID', 'Name', 'Is Public'] - column_headers = columns + column_headers = ['ID', 'Name', 'Is Public'] if parsed_args.default: data = [volume_client.volume_types.default()] else: @@ -200,10 +295,41 @@ class ListVolumeType(command.Lister): is_public = False data = volume_client.volume_types.list( is_public=is_public) + + def _format_encryption_info(type_id, encryption_data=None): + encryption_data = encryption + encryption_info = '-' + if type_id in encryption_data.keys(): + encryption_info = encryption_data[type_id] + return encryption_info + + if parsed_args.encryption_type: + encryption = {} + for d in volume_client.volume_encryption_types.list(): + volume_type_id = d._info['volume_type_id'] + # remove some redundant information + del_key = [ + 'deleted', + 'created_at', + 'updated_at', + 'deleted_at', + 'volume_type_id' + ] + for key in del_key: + d._info.pop(key, None) + # save the encryption information with their volume type ID + encryption[volume_type_id] = utils.format_dict(d._info) + # We need to get volume type ID, then show encryption + # information according to the ID, so use "id" to keep + # difference to the real "ID" column. + columns += ['id'] + column_headers += ['Encryption'] + return (column_headers, (utils.get_item_properties( s, columns, - formatters={'Extra Specs': utils.format_dict}, + formatters={'Extra Specs': utils.format_dict, + 'id': _format_encryption_info}, ) for s in data)) @@ -241,7 +367,43 @@ class SetVolumeType(command.Command): '(admin only)'), ) identity_common.add_project_domain_option_to_parser(parser) - + # TODO(Huanxuan Ao): Add choices for each "--encryption-*" option. + parser.add_argument( + '--encryption-provider', + metavar='<provider>', + help=_('Set the class that provides encryption support for ' + 'this volume type (e.g "LuksEncryptor") (admin only) ' + '(This option is required when setting encryption type ' + 'of a volume for the first time. Consider using other ' + 'encryption options such as: "--encryption-cipher", ' + '"--encryption-key-size" and ' + '"--encryption-control-location")'), + ) + parser.add_argument( + '--encryption-cipher', + metavar='<cipher>', + help=_('Set the encryption algorithm or mode for this ' + 'volume type (e.g "aes-xts-plain64") (admin only)'), + ) + parser.add_argument( + '--encryption-key-size', + metavar='<key-size>', + type=int, + help=_('Set the size of the encryption key of this ' + 'volume type (e.g "128" or "256") (admin only)'), + ) + parser.add_argument( + '--encryption-control-location', + metavar='<control-location>', + choices=['front-end', 'back-end'], + help=_('Set the notional service where the encryption is ' + 'performed ("front-end" or "back-end") (admin only) ' + '(The default value for this option is "front-end" ' + 'when setting encryption type of a volume for the ' + 'first time. Consider using other encryption options ' + 'such as: "--encryption-cipher", "--encryption-key-size" ' + 'and "--encryption-provider")'), + ) return parser def take_action(self, parsed_args): @@ -290,6 +452,17 @@ class SetVolumeType(command.Command): "project: %s"), e) result += 1 + if (parsed_args.encryption_provider or + parsed_args.encryption_cipher or + parsed_args.encryption_key_size or + parsed_args.encryption_control_location): + try: + _set_encryption_type(volume_client, volume_type, parsed_args) + except Exception as e: + LOG.error(_("Failed to set encryption information for this " + "volume type: %s"), e) + result += 1 + if result > 0: raise exceptions.CommandError(_("Command Failed: One or more of" " the operations failed")) @@ -305,6 +478,12 @@ class ShowVolumeType(command.ShowOne): metavar="<volume-type>", help=_("Volume type to display (name or ID)") ) + parser.add_argument( + "--encryption-type", + action="store_true", + help=_("Display encryption information of this volume type " + "(admin only)"), + ) return parser def take_action(self, parsed_args): @@ -329,6 +508,17 @@ class ShowVolumeType(command.ShowOne): '%(type)s: %(e)s') LOG.error(msg % {'type': volume_type.id, 'e': e}) volume_type._info.update({'access_project_ids': access_project_ids}) + if parsed_args.encryption_type: + # show encryption type information for this volume type + try: + encryption = volume_client.volume_encryption_types.get( + volume_type.id) + encryption._info.pop("volume_type_id", None) + volume_type._info.update( + {'encryption': utils.format_dict(encryption._info)}) + except Exception as e: + LOG.error(_("Failed to display the encryption information " + "of this volume type: %s"), e) volume_type._info.pop("os-volume-type-access:is_public", None) return zip(*sorted(six.iteritems(volume_type._info))) @@ -357,7 +547,12 @@ class UnsetVolumeType(command.Command): ' (admin only)'), ) identity_common.add_project_domain_option_to_parser(parser) - + parser.add_argument( + "--encryption-type", + action="store_true", + help=_("Remove the encryption type for this volume type " + "(admin only)"), + ) return parser def take_action(self, parsed_args): @@ -391,6 +586,13 @@ class UnsetVolumeType(command.Command): LOG.error(_("Failed to remove volume type access from " "project: %s"), e) result += 1 + if parsed_args.encryption_type: + try: + volume_client.volume_encryption_types.delete(volume_type) + except Exception as e: + LOG.error(_("Failed to remove the encryption type for this " + "volume type: %s"), e) + result += 1 if result > 0: raise exceptions.CommandError(_("Command Failed: One or more of" |
