def _ata_erase(self, block_device): security_lines = self._get_ata_security_lines(block_device) # If secure erase isn't supported return False so erase_block_device # can try another mechanism. Below here, if secure erase is supported # but fails in some way, error out (operators of hardware that supports # secure erase presumably expect this to work). if 'supported' not in security_lines: return False if 'enabled' in security_lines: raise errors.BlockDeviceEraseError( ('Block device {0} already has ' 'a security password set').format(block_device.name)) if 'not frozen' not in security_lines: raise errors.BlockDeviceEraseError( ('Block device {0} is frozen ' 'and cannot be erased').format(block_device.name)) utils.execute('hdparm', '--user-master', 'u', '--security-set-pass', 'NULL', block_device.name) utils.execute('hdparm', '--user-master', 'u', '--security-erase', 'NULL', block_device.name) # Verify that security is now 'not enabled' security_lines = self._get_ata_security_lines(block_device) if 'not enabled' not in security_lines: raise errors.BlockDeviceEraseError( ('An unknown error occurred ' 'erasing block device {0}').format(block_device.name)) return True
def erase_devices_metadata(self, node, ports): """Attempt to erase the disk devices metadata. :param node: Ironic node object :param ports: list of Ironic port objects :raises BlockDeviceEraseError: when there's an error erasing the block device """ block_devices = self.list_block_devices() erase_errors = {} for dev in block_devices: if self._is_virtual_media_device(dev): LOG.info("Skipping the erase of virtual media device %s", dev.name) continue try: disk_utils.destroy_disk_metadata(dev.name, node['uuid']) except processutils.ProcessExecutionError as e: LOG.error( 'Failed to erase the metadata on device "%(dev)s". ' 'Error: %(error)s', { 'dev': dev.name, 'error': e }) erase_errors[dev.name] = e if erase_errors: excpt_msg = ( 'Failed to erase the metadata on the device(s): %s' % '; '.join( ['"%s": %s' % (k, v) for k, v in erase_errors.items()])) raise errors.BlockDeviceEraseError(excpt_msg)
def erase_block_device(self, block_device): if self._ata_erase(block_device): return # NOTE(russell_h): Support for additional generic erase methods should # be added above this raise, in order of precedence. raise errors.BlockDeviceEraseError( ('Unable to erase block device ' '{0}: device is unsupported.').format(block_device.name))
def _erase_lsi_warpdrive(self, block_device): if not self._is_warpdrive(block_device): return False # NOTE(JayF): Start timing here, so any devices short circuited # don't produce invalidly-short metrics. with metrics.instrument_context(__name__, 'erase_lsi_warpdrive'): device = self._get_warpdrive_card(block_device) result = utils.execute(DDOEMCLI, '-c', device['id'], '-format', '-op', '-level', 'nom', '-s') if 'WarpDrive format successfully completed.' not in result[0]: raise errors.BlockDeviceEraseError(('Erasing LSI card failed: ' '{0}').format(result[0])) return True
def test_error_classes(self): cases = [ (errors.InvalidContentError(DETAILS), SAME_DETAILS), (errors.NotFound(), SAME_CL_DETAILS), (errors.CommandExecutionError(DETAILS), SAME_DETAILS), (errors.InvalidCommandError(DETAILS), SAME_DETAILS), (errors.InvalidCommandParamsError(DETAILS), SAME_DETAILS), (errors.RequestedObjectNotFoundError('type_descr', 'obj_id'), DIFF_CL_DETAILS), (errors.IronicAPIError(DETAILS), SAME_DETAILS), (errors.HeartbeatError(DETAILS), SAME_DETAILS), (errors.LookupNodeError(DETAILS), SAME_DETAILS), (errors.LookupAgentIPError(DETAILS), SAME_DETAILS), (errors.LookupAgentInterfaceError(DETAILS), SAME_DETAILS), (errors.ImageDownloadError('image_id', DETAILS), DIFF_CL_DETAILS), (errors.ImageChecksumError('image_id', '/foo/image_id', 'incorrect', 'correct'), DIFF_CL_DETAILS), (errors.ImageWriteError('device', 'exit_code', 'stdout', 'stderr'), DIFF_CL_DETAILS), (errors.ConfigDriveTooLargeError('filename', 'filesize'), DIFF_CL_DETAILS), (errors.ConfigDriveWriteError('device', 'exit_code', 'stdout', 'stderr'), DIFF_CL_DETAILS), (errors.SystemRebootError('exit_code', 'stdout', 'stderr'), DIFF_CL_DETAILS), (errors.BlockDeviceEraseError(DETAILS), SAME_DETAILS), (errors.BlockDeviceError(DETAILS), SAME_DETAILS), (errors.VirtualMediaBootError(DETAILS), SAME_DETAILS), (errors.UnknownNodeError(), DEFAULT_DETAILS), (errors.UnknownNodeError(DETAILS), SAME_DETAILS), (errors.HardwareManagerNotFound(), DEFAULT_DETAILS), (errors.HardwareManagerNotFound(DETAILS), SAME_DETAILS), (errors.HardwareManagerMethodNotFound('method'), DIFF_CL_DETAILS), (errors.IncompatibleHardwareMethodError(), DEFAULT_DETAILS), (errors.IncompatibleHardwareMethodError(DETAILS), SAME_DETAILS), ] for (obj, check_details) in cases: self._test_class(obj, check_details)
def _ata_erase(self, block_device): security_lines = self._get_ata_security_lines(block_device) # If secure erase isn't supported return False so erase_block_device # can try another mechanism. Below here, if secure erase is supported # but fails in some way, error out (operators of hardware that supports # secure erase presumably expect this to work). if 'supported' not in security_lines: return False if 'enabled' in security_lines: # Attempt to unlock the drive in the event it has already been # locked by a previous failed attempt. try: utils.execute('hdparm', '--user-master', 'u', '--security-unlock', 'NULL', block_device.name) security_lines = self._get_ata_security_lines(block_device) except processutils.ProcessExecutionError as e: raise errors.BlockDeviceEraseError( 'Security password set ' 'failed for device ' '%(name)s: %(err)s' % { 'name': block_device.name, 'err': e }) if 'enabled' in security_lines: raise errors.BlockDeviceEraseError( ('Block device {} already has a security password set').format( block_device.name)) if 'not frozen' not in security_lines: raise errors.BlockDeviceEraseError( ('Block device {} is frozen and cannot be erased').format( block_device.name)) try: utils.execute('hdparm', '--user-master', 'u', '--security-set-pass', 'NULL', block_device.name) except processutils.ProcessExecutionError as e: raise errors.BlockDeviceEraseError('Security password set ' 'failed for device ' '%(name)s: %(err)s' % { 'name': block_device.name, 'err': e }) # Use the 'enhanced' security erase option if it's supported. erase_option = '--security-erase' if 'not supported: enhanced erase' not in security_lines: erase_option += '-enhanced' try: utils.execute('hdparm', '--user-master', 'u', erase_option, 'NULL', block_device.name) except processutils.ProcessExecutionError as e: raise errors.BlockDeviceEraseError('Erase failed for device ' '%(name)s: %(err)s' % { 'name': block_device.name, 'err': e }) # Verify that security is now 'not enabled' security_lines = self._get_ata_security_lines(block_device) if 'not enabled' not in security_lines: raise errors.BlockDeviceEraseError( ('An unknown error occurred erasing block device {}').format( block_device.name)) return True
def _ata_erase(self, block_device): security_lines = self._get_ata_security_lines(block_device) # If secure erase isn't supported return False so erase_block_device # can try another mechanism. Below here, if secure erase is supported # but fails in some way, error out (operators of hardware that supports # secure erase presumably expect this to work). if 'supported' not in security_lines: return False # At this point, we could be SEC1,2,4,5,6 if 'not frozen' not in security_lines: # In SEC2 or 6 raise errors.BlockDeviceEraseError( ('Block device {} is frozen and cannot be erased').format( block_device.name)) # At this point, we could be in SEC1,4,5 # Attempt to unlock the drive in the event it has already been # locked by a previous failed attempt. We try the empty string as # versions of hdparm < 9.51, interpreted NULL as the literal string, # "NULL", as opposed to the empty string. unlock_passwords = ['NULL', ''] for password in unlock_passwords: if 'not locked' in security_lines: break try: utils.execute('hdparm', '--user-master', 'u', '--security-unlock', password, block_device.name) except processutils.ProcessExecutionError as e: LOG.info( 'Security unlock failed for device ' '%(name)s using password "%(password)s": %(err)s', { 'name': block_device.name, 'password': password, 'err': e }) security_lines = self._get_ata_security_lines(block_device) # If the unlock failed we will still be in SEC4, otherwise, we will be # in SEC1 or SEC5 if 'not locked' not in security_lines: # In SEC4 raise errors.BlockDeviceEraseError( ('Block device {} already has a security password set').format( block_device.name)) # At this point, we could be in SEC1 or 5 if 'not enabled' in security_lines: # SEC1. Try to transition to SEC5 by setting empty user # password. try: utils.execute('hdparm', '--user-master', 'u', '--security-set-pass', 'NULL', block_device.name) except processutils.ProcessExecutionError as e: error_msg = ('Security password set failed for device ' '{name}: {err}').format(name=block_device.name, err=e) raise errors.BlockDeviceEraseError(error_msg) # Use the 'enhanced' security erase option if it's supported. erase_option = '--security-erase' if 'not supported: enhanced erase' not in security_lines: erase_option += '-enhanced' try: utils.execute('hdparm', '--user-master', 'u', erase_option, 'NULL', block_device.name) except processutils.ProcessExecutionError as e: raise errors.BlockDeviceEraseError('Erase failed for device ' '%(name)s: %(err)s' % { 'name': block_device.name, 'err': e }) # Verify that security is now 'not enabled' security_lines = self._get_ata_security_lines(block_device) if 'not enabled' not in security_lines: # Not SEC1 - fail raise errors.BlockDeviceEraseError( ('An unknown error occurred erasing block device {}').format( block_device.name)) # In SEC1 security state return True