def _get_encryption_key_id(self, key_manager, context, volume_type_id, snapshot, source_volume): encryption_key_id = None if volume_types.is_encrypted(context, volume_type_id): if snapshot is not None: # creating from snapshot encryption_key_id = snapshot['encryption_key_id'] elif source_volume is not None: # cloning volume encryption_key_id = source_volume['encryption_key_id'] # NOTE(joel-coffman): References to the encryption key should *not* # be copied because the key is deleted when the volume is deleted. # Clone the existing key and associate a separate -- but # identical -- key with each volume. if encryption_key_id is not None: encryption_key_id = key_manager.store( context, key_manager.get(context, encryption_key_id)) else: volume_type_encryption = ( volume_types.get_volume_type_encryption( context, volume_type_id)) cipher = volume_type_encryption.cipher length = volume_type_encryption.key_size # NOTE(kaitlin-farr): dm-crypt expects the cipher in a # hyphenated format (aes-xts-plain64). The algorithm needs # to be parsed out to pass to the key manager (aes). algorithm = cipher.split('-')[0] if cipher else None encryption_key_id = key_manager.create_key(context, algorithm=algorithm, length=length) return encryption_key_id
def _get_encryption_key_id(self, key_manager, context, volume_type_id, snapshot, source_volume): encryption_key_id = None if volume_types.is_encrypted(context, volume_type_id): if snapshot is not None: # creating from snapshot encryption_key_id = snapshot['encryption_key_id'] elif source_volume is not None: # cloning volume encryption_key_id = source_volume['encryption_key_id'] # NOTE(joel-coffman): References to the encryption key should *not* # be copied because the key is deleted when the volume is deleted. # Clone the existing key and associate a separate -- but # identical -- key with each volume. if encryption_key_id is not None: encryption_key_id = key_manager.store( context, key_manager.get(context, encryption_key_id)) else: volume_type_encryption = ( volume_types.get_volume_type_encryption(context, volume_type_id)) cipher = volume_type_encryption.cipher length = volume_type_encryption.key_size # NOTE(kaitlin-farr): dm-crypt expects the cipher in a # hyphenated format (aes-xts-plain64). The algorithm needs # to be parsed out to pass to the key manager (aes). algorithm = cipher.split('-')[0] if cipher else None encryption_key_id = key_manager.create_key(context, algorithm=algorithm, length=length) return encryption_key_id
def test_get_volume_type_encryption(self): volume_type = volume_types.create(self.ctxt, "type1") volume_type_id = volume_type.get("id") encryption = {"control_location": "front-end", "provider": "fake_provider"} db.volume_type_encryption_create(self.ctxt, volume_type_id, encryption) ret = volume_types.get_volume_type_encryption(self.ctxt, volume_type_id) self.assertIsNotNone(ret)
def test_volume_type_destroy_with_encryption(self): volume_type = volume_types.create(self.ctxt, "type1") volume_type_id = volume_type.get('id') encryption = { 'control_location': 'front-end', 'provider': 'fake_provider', } db_api.volume_type_encryption_create(self.ctxt, volume_type_id, encryption) ret = volume_types.get_volume_type_encryption(self.ctxt, volume_type_id) self.assertIsNotNone(ret) volume_types.destroy(self.ctxt, volume_type_id) ret = volume_types.get_volume_type_encryption(self.ctxt, volume_type_id) self.assertIsNone(ret)
def create_encryption_key(context, key_manager, volume_type_id): encryption_key_id = None if volume_types.is_encrypted(context, volume_type_id): volume_type_encryption = (volume_types.get_volume_type_encryption( context, volume_type_id)) cipher = volume_type_encryption.cipher length = volume_type_encryption.key_size algorithm = cipher.split('-')[0] if cipher else None encryption_key_id = key_manager.create_key(context, algorithm=algorithm, length=length) return encryption_key_id
def create_encryption_key(context, key_manager, volume_type_id): encryption_key_id = None if volume_types.is_encrypted(context, volume_type_id): volume_type_encryption = ( volume_types.get_volume_type_encryption(context, volume_type_id)) cipher = volume_type_encryption.cipher length = volume_type_encryption.key_size algorithm = cipher.split('-')[0] if cipher else None encryption_key_id = key_manager.create_key( context, algorithm=algorithm, length=length) return encryption_key_id
def _get_encryption_key_id(self, key_manager, context, volume_type_id, snapshot, source_volume, image_metadata): encryption_key_id = None if volume_types.is_encrypted(context, volume_type_id): if snapshot is not None: # creating from snapshot encryption_key_id = snapshot['encryption_key_id'] elif source_volume is not None: # cloning volume encryption_key_id = source_volume['encryption_key_id'] elif image_metadata is not None: # creating from image encryption_key_id = image_metadata.get( 'cinder_encryption_key_id') # NOTE(joel-coffman): References to the encryption key should *not* # be copied because the key is deleted when the volume is deleted. # Clone the existing key and associate a separate -- but # identical -- key with each volume. if encryption_key_id is not None: encryption_key_id = key_manager.store( context, key_manager.get(context, encryption_key_id)) else: volume_type_encryption = ( volume_types.get_volume_type_encryption(context, volume_type_id)) cipher = volume_type_encryption.cipher length = volume_type_encryption.key_size # NOTE(kaitlin-farr): dm-crypt expects the cipher in a # hyphenated format (aes-xts-plain64). The algorithm needs # to be parsed out to pass to the key manager (aes). algorithm = cipher.split('-')[0] if cipher else None try: encryption_key_id = key_manager.create_key( context, algorithm=algorithm, length=length) except castellan_exc.KeyManagerError: # The messaging back to the client here is # purposefully terse, so we don't leak any sensitive # details. LOG.exception("Key manager error") raise exception.Invalid(message="Key manager error") return encryption_key_id
def create_encryption_key(context, key_manager, volume_type_id): encryption_key_id = None if volume_types.is_encrypted(context, volume_type_id): volume_type_encryption = (volume_types.get_volume_type_encryption( context, volume_type_id)) cipher = volume_type_encryption.cipher length = volume_type_encryption.key_size algorithm = cipher.split('-')[0] if cipher else None try: encryption_key_id = key_manager.create_key(context, algorithm=algorithm, length=length) except castellan_exception.KeyManagerError: # The messaging back to the client here is # purposefully terse, so we don't leak any sensitive # details. LOG.exception("Key manager error") raise exception.Invalid(message="Key manager error") return encryption_key_id
def create_encryption_key(context, key_manager, volume_type_id): encryption_key_id = None if volume_types.is_encrypted(context, volume_type_id): volume_type_encryption = ( volume_types.get_volume_type_encryption(context, volume_type_id)) cipher = volume_type_encryption.cipher length = volume_type_encryption.key_size algorithm = cipher.split('-')[0] if cipher else None try: encryption_key_id = key_manager.create_key( context, algorithm=algorithm, length=length) except castellan_exception.KeyManagerError: # The messaging back to the client here is # purposefully terse, so we don't leak any sensitive # details. LOG.exception("Key manager error") raise exception.Invalid(message="Key manager error") return encryption_key_id
def retype(self, context, volume, new_type, migration_policy=None): """Attempt to modify the type associated with an existing volume.""" if volume['status'] not in ['available', 'in-use']: msg = _('Unable to update type due to incorrect status ' 'on volume: %s') % volume['id'] LOG.error(msg) raise exception.InvalidVolume(reason=msg) if volume['migration_status'] is not None: msg = (_("Volume %s is already part of an active migration.") % volume['id']) LOG.error(msg) raise exception.InvalidVolume(reason=msg) if migration_policy and migration_policy not in ['on-demand', 'never']: msg = _('migration_policy must be \'on-demand\' or \'never\', ' 'passed: %s') % new_type LOG.error(msg) raise exception.InvalidInput(reason=msg) # Support specifying volume type by ID or name try: if uuidutils.is_uuid_like(new_type): vol_type = volume_types.get_volume_type(context, new_type) else: vol_type = volume_types.get_volume_type_by_name(context, new_type) except exception.InvalidVolumeType: msg = _('Invalid volume_type passed: %s') % new_type LOG.error(msg) raise exception.InvalidInput(reason=msg) vol_type_id = vol_type['id'] vol_type_qos_id = vol_type['qos_specs_id'] old_vol_type = None old_vol_type_id = volume['volume_type_id'] old_vol_type_qos_id = None # Error if the original and new type are the same if volume['volume_type_id'] == vol_type_id: msg = (_('New volume_type same as original: %s') % new_type) LOG.error(msg) raise exception.InvalidInput(reason=msg) if volume['volume_type_id']: old_vol_type = volume_types.get_volume_type( context, old_vol_type_id) old_vol_type_qos_id = old_vol_type['qos_specs_id'] # We don't support changing encryption requirements yet old_enc = volume_types.get_volume_type_encryption(context, old_vol_type_id) new_enc = volume_types.get_volume_type_encryption(context, vol_type_id) if old_enc != new_enc: msg = _('Retype cannot change encryption requirements') raise exception.InvalidInput(reason=msg) # We don't support changing QoS at the front-end yet for in-use volumes # TODO(avishay): Call Nova to change QoS setting (libvirt has support # - virDomainSetBlockIoTune() - Nova does not have support yet). if (volume['status'] != 'available' and old_vol_type_qos_id != vol_type_qos_id): for qos_id in [old_vol_type_qos_id, vol_type_qos_id]: if qos_id: specs = qos_specs.get_qos_specs(context.elevated(), qos_id) if specs['qos_specs']['consumer'] != 'back-end': msg = _('Retype cannot change front-end qos specs for ' 'in-use volumes') raise exception.InvalidInput(reason=msg) # We're checking here in so that we can report any quota issues as # early as possible, but won't commit until we change the type. We # pass the reservations onward in case we need to roll back. reservations = quota_utils.get_volume_type_reservation(context, volume, vol_type_id) self.update(context, volume, {'status': 'retyping'}) request_spec = {'volume_properties': volume, 'volume_id': volume['id'], 'volume_type': vol_type, 'migration_policy': migration_policy, 'quota_reservations': reservations} self.scheduler_rpcapi.retype(context, CONF.volume_topic, volume['id'], request_spec=request_spec, filter_properties={})
def retype(self, context, volume, new_type, migration_policy=None): """Attempt to modify the type associated with an existing volume.""" if volume['status'] not in ['available', 'in-use']: msg = _('Unable to update type due to incorrect status ' 'on volume: %s') % volume['id'] LOG.error(msg) raise exception.InvalidVolume(reason=msg) if volume['migration_status'] is not None: msg = (_("Volume %s is already part of an active migration.") % volume['id']) LOG.error(msg) raise exception.InvalidVolume(reason=msg) if migration_policy and migration_policy not in ['on-demand', 'never']: msg = _('migration_policy must be \'on-demand\' or \'never\', ' 'passed: %s') % new_type LOG.error(msg) raise exception.InvalidInput(reason=msg) # Support specifying volume type by ID or name try: if uuidutils.is_uuid_like(new_type): vol_type = volume_types.get_volume_type(context, new_type) else: vol_type = volume_types.get_volume_type_by_name( context, new_type) except exception.InvalidVolumeType: msg = _('Invalid volume_type passed: %s') % new_type LOG.error(msg) raise exception.InvalidInput(reason=msg) vol_type_id = vol_type['id'] vol_type_qos_id = vol_type['qos_specs_id'] old_vol_type = None old_vol_type_id = volume['volume_type_id'] old_vol_type_qos_id = None # Error if the original and new type are the same if volume['volume_type_id'] == vol_type_id: msg = (_('New volume_type same as original: %s') % new_type) LOG.error(msg) raise exception.InvalidInput(reason=msg) if volume['volume_type_id']: old_vol_type = volume_types.get_volume_type( context, old_vol_type_id) old_vol_type_qos_id = old_vol_type['qos_specs_id'] # We don't support changing encryption requirements yet old_enc = volume_types.get_volume_type_encryption( context, old_vol_type_id) new_enc = volume_types.get_volume_type_encryption(context, vol_type_id) if old_enc != new_enc: msg = _('Retype cannot change encryption requirements') raise exception.InvalidInput(reason=msg) # We don't support changing QoS at the front-end yet for in-use volumes # TODO(avishay): Call Nova to change QoS setting (libvirt has support # - virDomainSetBlockIoTune() - Nova does not have support yet). if (volume['status'] != 'available' and old_vol_type_qos_id != vol_type_qos_id): for qos_id in [old_vol_type_qos_id, vol_type_qos_id]: if qos_id: specs = qos_specs.get_qos_specs(context.elevated(), qos_id) if specs['qos_specs']['consumer'] != 'back-end': msg = _('Retype cannot change front-end qos specs for ' 'in-use volumes') raise exception.InvalidInput(reason=msg) # We're checking here in so that we can report any quota issues as # early as possible, but won't commit until we change the type. We # pass the reservations onward in case we need to roll back. reservations = quota_utils.get_volume_type_reservation( context, volume, vol_type_id) self.update(context, volume, {'status': 'retyping'}) request_spec = { 'volume_properties': volume, 'volume_id': volume['id'], 'volume_type': vol_type, 'migration_policy': migration_policy, 'quota_reservations': reservations } self.scheduler_rpcapi.retype(context, CONF.volume_topic, volume['id'], request_spec=request_spec, filter_properties={})
def test_get_volume_type_encryption_without_volume_type_id(self): ret = volume_types.get_volume_type_encryption(self.ctxt, None) self.assertIsNone(ret)
def retype(self, context, volume, new_type, migration_policy=None): """Attempt to modify the type associated with an existing volume.""" if volume["status"] not in ["available", "in-use"]: msg = _("Unable to update type due to incorrect status " "on volume: %s") % volume["id"] LOG.error(msg) raise exception.InvalidVolume(reason=msg) if volume["migration_status"] is not None: msg = _("Volume %s is already part of an active migration.") % volume["id"] LOG.error(msg) raise exception.InvalidVolume(reason=msg) if migration_policy and migration_policy not in ["on-demand", "never"]: msg = _("migration_policy must be 'on-demand' or 'never', " "passed: %s") % new_type LOG.error(msg) raise exception.InvalidInput(reason=msg) cg_id = volume.get("consistencygroup_id", None) if cg_id: msg = _("Volume must not be part of a consistency group.") LOG.error(msg) raise exception.InvalidVolume(reason=msg) # Support specifying volume type by ID or name try: if uuidutils.is_uuid_like(new_type): vol_type = volume_types.get_volume_type(context, new_type) else: vol_type = volume_types.get_volume_type_by_name(context, new_type) except exception.InvalidVolumeType: msg = _("Invalid volume_type passed: %s") % new_type LOG.error(msg) raise exception.InvalidInput(reason=msg) vol_type_id = vol_type["id"] vol_type_qos_id = vol_type["qos_specs_id"] old_vol_type = None old_vol_type_id = volume["volume_type_id"] old_vol_type_qos_id = None # Error if the original and new type are the same if volume["volume_type_id"] == vol_type_id: msg = _("New volume_type same as original: %s") % new_type LOG.error(msg) raise exception.InvalidInput(reason=msg) if volume["volume_type_id"]: old_vol_type = volume_types.get_volume_type(context, old_vol_type_id) old_vol_type_qos_id = old_vol_type["qos_specs_id"] # We don't support changing encryption requirements yet old_enc = volume_types.get_volume_type_encryption(context, old_vol_type_id) new_enc = volume_types.get_volume_type_encryption(context, vol_type_id) if old_enc != new_enc: msg = _("Retype cannot change encryption requirements") raise exception.InvalidInput(reason=msg) # We don't support changing QoS at the front-end yet for in-use volumes # TODO(avishay): Call Nova to change QoS setting (libvirt has support # - virDomainSetBlockIoTune() - Nova does not have support yet). if volume["status"] != "available" and old_vol_type_qos_id != vol_type_qos_id: for qos_id in [old_vol_type_qos_id, vol_type_qos_id]: if qos_id: specs = qos_specs.get_qos_specs(context.elevated(), qos_id) if specs["qos_specs"]["consumer"] != "back-end": msg = _("Retype cannot change front-end qos specs for " "in-use volumes") raise exception.InvalidInput(reason=msg) # We're checking here in so that we can report any quota issues as # early as possible, but won't commit until we change the type. We # pass the reservations onward in case we need to roll back. reservations = quota_utils.get_volume_type_reservation(context, volume, vol_type_id) self.update(context, volume, {"status": "retyping"}) request_spec = { "volume_properties": volume, "volume_id": volume["id"], "volume_type": vol_type, "migration_policy": migration_policy, "quota_reservations": reservations, } self.scheduler_rpcapi.retype( context, CONF.volume_topic, volume["id"], request_spec=request_spec, filter_properties={} )