def __init__(self, config, driver_type): if not config.safe_get('iscsi_ip_address'): raise exception.InvalidConfigurationValue( option='iscsi_ip_address', value='') if not config.safe_get('synology_pool_name'): raise exception.InvalidConfigurationValue( option='synology_pool_name', value='') self.config = config self.vendor_name = 'Synology' self.driver_type = driver_type self.volume_backend_name = self._get_backend_name() self.iscsi_port = self.config.safe_get('iscsi_port') api = APIRequest( self.config.iscsi_ip_address, self.config.synology_admin_port, self.config.synology_username, self.config.synology_password, self.config.safe_get('driver_use_ssl'), self.config.safe_get('synology_ssl_verify'), self.config.safe_get('synology_one_time_pass'), self.config.safe_get('synology_device_id'), ) self.synoexec = api.request self.host_uuid = self._get_node_uuid()
def validate_ports(self, ports_whitelist): all_ports = self.get_all_ports() # After normalize_config, `ports_whitelist` could be only None or valid # list in which the items are stripped. if ports_whitelist is None: return all_ports.id # For iSCSI port, the format is 'spa_eth0', and 'spa_iom_0_fc0' for FC. # Unix style glob like 'spa_*' is supported. whitelist = set(ports_whitelist) matched, _ignored, unmatched_whitelist = utils.match_any( all_ports.id, whitelist) if not matched: LOG.error('No matched ports filtered by all patterns: %s', whitelist) raise exception.InvalidConfigurationValue( option='%s.unity_io_ports' % self.config.config_group, value=self.config.unity_io_ports) if unmatched_whitelist: LOG.error('No matched ports filtered by below patterns: %s', unmatched_whitelist) raise exception.InvalidConfigurationValue( option='%s.unity_io_ports' % self.config.config_group, value=self.config.unity_io_ports) LOG.info( 'These ports %(matched)s will be used based on ' 'the option unity_io_ports: %(config)s', { 'matched': matched, 'config': self.config.unity_io_ports }) return matched
def __init__(self, conf_dict, driver): """Constructs a replication device from driver configuration. :param conf_dict: the conf of one replication device entry. It's a dict with content like `{backend_id: vendor-id-1, key-1: val-1, ...}` :param driver: the backend driver. """ driver_conf = driver.configuration self.backend_id = conf_dict.get('backend_id') self.san_ip = conf_dict.get('san_ip', None) if (self.backend_id is None or not self.backend_id.strip() or self.san_ip is None or not self.san_ip.strip()): LOG.error( 'No backend_id or san_ip in %(conf)s of ' '%(group)s.replication_device', conf=conf_dict, group=driver_conf.config_group) raise exception.InvalidConfigurationValue( option='%s.replication_device' % driver_conf.config_group, value=driver_conf.replication_device) # Use the driver settings if not configured in replication_device. self.san_login = conf_dict.get('san_login', driver_conf.san_login) self.san_password = conf_dict.get('san_password', driver_conf.san_password) # Max time (in minute) out of sync is a setting for replication. # It means maximum time to wait before syncing the source and # destination. `0` means it is a sync replication. Default is `60`. try: self.max_time_out_of_sync = int( conf_dict.get('max_time_out_of_sync', 60)) except ValueError: LOG.error( 'max_time_out_of_sync is not a number, %(conf)s of ' '%(group)s.replication_device', conf=conf_dict, group=driver_conf.config_group) raise exception.InvalidConfigurationValue( option='%s.replication_device' % driver_conf.config_group, value=driver_conf.replication_device) if self.max_time_out_of_sync < 0: LOG.error( 'max_time_out_of_sync should be greater than 0, ' '%(conf)s of %(group)s.replication_device', conf=conf_dict, group=driver_conf.config_group) raise exception.InvalidConfigurationValue( option='%s.replication_device' % driver_conf.config_group, value=driver_conf.replication_device) self.driver = driver self._adapter = init_adapter(driver.get_version(), driver.protocol) self._dst_pool = None self._serial_number = None
def get_qos_parameters(self, specs, reset): qos_params = {} if 'upperlimit' in specs and specs['upperlimit'] is not None: if self.validates_number(specs['upperlimit']) is True: upper_limit = int(specs['upperlimit'], 10) if ((upper_limit != 0) and ((upper_limit < 10) or (upper_limit > 1000000))): raise exception.InvalidConfigurationValue( value=upper_limit, option='upperlimit') qos_params['upperlimit'] = upper_limit else: raise exception.InvalidConfigurationValue( value=specs['upperlimit'], option='upperlimit') else: # 0: Set to no limit.(default) # On the QoS function in NEC Storage, 0 means there is no # limit. # None: Keep current value. qos_params['upperlimit'] = 0 if reset else None if 'lowerlimit' in specs and specs['lowerlimit'] is not None: if self.validates_number(specs['lowerlimit']) is True: lower_limit = int(specs['lowerlimit'], 10) if (lower_limit != 0 and (lower_limit < 10 or lower_limit > 1000000)): raise exception.InvalidConfigurationValue( value=lower_limit, option='lowerlimit') qos_params['lowerlimit'] = lower_limit else: raise exception.InvalidConfigurationValue( value=specs['lowerlimit'], option='lowerlimit') else: # 0: Set to no limit.(default) # On the QoS function in NEC Storage, 0 means there is no # limit. # None: Keep current value. qos_params['lowerlimit'] = 0 if reset else None if 'upperreport' in specs: if specs['upperreport'] not in ['on', 'off']: LOG.debug( 'Illegal arguments. ' 'upperreport is not on or off.' 'upperreport=%s', specs['upperreport']) qos_params['upperreport'] = 'off' if reset else None else: qos_params['upperreport'] = specs['upperreport'] else: # off: Set to no report.(default) # None: Keep current value. qos_params['upperreport'] = 'off' if reset else None return qos_params
def do_setup(self, driver): self.default_conf = driver.configuration self.replication_devices = self.parse_rep_device(driver) if DEFAULT_ADAPTER_NAME in self.replication_devices: LOG.error('backend_id cannot be `default`') raise exception.InvalidConfigurationValue( option=('%s.replication_device' % self.default_conf.config_group), value=self.default_conf.replication_device) # Only support one replication device currently. if len(self.replication_devices) > 1: LOG.error('At most one replication_device is supported') raise exception.InvalidConfigurationValue( option=('%s.replication_device' % self.default_conf.config_group), value=self.default_conf.replication_device) self.is_replication_configured = len(self.replication_devices) >= 1 self.active_backend_id = driver.active_backend_id if self.active_backend_id: if self.active_backend_id not in self.replication_devices: LOG.error( 'Service starts under failed-over status, ' 'active_backend_id: %s is not empty, but not in ' 'replication_device.', self.active_backend_id) raise exception.InvalidConfigurationValue( option=('%s.replication_device' % self.default_conf.config_group), value=self.default_conf.replication_device) else: self.active_backend_id = DEFAULT_ADAPTER_NAME default_device_conf = { 'backend_id': DEFAULT_ADAPTER_NAME, 'san_ip': driver.configuration.san_ip } self.default_device = ReplicationDevice(default_device_conf, driver) if not self.is_service_failed_over: # If service doesn't fail over, setup the adapter. # Otherwise, the primary backend could be down, adapter setup could # fail. self.default_device.setup_adapter() if self.is_replication_configured: # If replication_device is configured, consider the replication is # enabled and check the same configuration is valid for secondary # backend or not. self.setup_rep_adapters()
def check_for_setup_error(self): required_flags = ['backup_share'] for flag in required_flags: val = getattr(CONF, flag, None) if not val: raise exception.InvalidConfigurationValue(option=flag, value=val)
def get_pool_name_filter_regex(configuration): """Build the regex for filtering pools by name :param configuration: The volume driver configuration :raise InvalidConfigurationValue: if configured regex pattern is invalid :returns: A compiled regex for filtering pool names """ # If the configuration parameter is specified as an empty string # (interpreted as matching all pools), we replace it here with # (.+) to be explicit with CSV compatibility support implemented below. pool_patterns = configuration.netapp_pool_name_search_pattern or r'(.+)' # Strip whitespace from start/end and then 'or' all regex patterns pool_patterns = '|'.join([ '^' + pool_pattern.strip('^$ \t') + '$' for pool_pattern in pool_patterns.split(',') ]) try: return re.compile(pool_patterns) except re.error: raise exception.InvalidConfigurationValue( option='netapp_pool_name_search_pattern', value=configuration.netapp_pool_name_search_pattern)
def check_for_setup_error(self): if self.proxy.session_id is None: msg = _('FSS cinder volume driver not ready: Unable to determine ' 'session id.') raise exception.VolumeBackendAPIException(data=msg) if self.configuration.fss_pool: self.configuration.fss_pools = { 'A': six.text_type(self.configuration.fss_pool) } # The fss_pool is deprecated. LOG.warning("'fss_pool=<pool-id>' is deprecated. Using the " "fss_pools=A:<pool-id> for single pool or " "fss_pools=P:<pool-id>,O:<other-pool-id> instead " "as old format will be removed once Queens development" " opens up.") if not self.configuration.fss_pools: msg = _('Pool is not available in the cinder configuration ' 'fields.') raise exception.InvalidHost(reason=msg) self._pool_checking(self.configuration.fss_pools) if self.configuration.san_thin_provision: if not self.configuration.max_over_subscription_ratio: msg = _('The max_over_subscription_ratio have to set ' 'when thin provisioning enabled.') raise exception.InvalidConfigurationValue(reason=msg)
def clear_volume(volume_size, volume_path, volume_clear=None, volume_clear_size=None, volume_clear_ionice=None, throttle=None): """Unprovision old volumes to prevent data leaking between users.""" if volume_clear is None: volume_clear = CONF.volume_clear if volume_clear_size is None: volume_clear_size = CONF.volume_clear_size if volume_clear_size == 0: volume_clear_size = volume_size if volume_clear_ionice is None: volume_clear_ionice = CONF.volume_clear_ionice LOG.info("Performing secure delete on volume: %s", volume_path) # We pass sparse=False explicitly here so that zero blocks are not # skipped in order to clear the volume. if volume_clear == 'zero': return copy_volume('/dev/zero', volume_path, volume_clear_size, CONF.volume_dd_blocksize, sync=True, execute=utils.execute, ionice=volume_clear_ionice, throttle=throttle, sparse=False) else: raise exception.InvalidConfigurationValue( option='volume_clear', value=volume_clear)
def clear_volume(volume_size, volume_path, volume_clear=None, volume_clear_size=None, volume_clear_ionice=None, throttle=None): """Unprovision old volumes to prevent data leaking between users.""" if volume_clear is None: volume_clear = CONF.volume_clear if volume_clear_size is None: volume_clear_size = CONF.volume_clear_size if volume_clear_size == 0: volume_clear_size = volume_size if volume_clear_ionice is None: volume_clear_ionice = CONF.volume_clear_ionice LOG.info(_LI("Performing secure delete on volume: %s"), volume_path) if volume_clear == 'shred': LOG.warning(_LW("volume_clear=shred has been deprecated and will " "be removed in the next release. Clearing with dd.")) volume_clear = 'zero' # We pass sparse=False explicitly here so that zero blocks are not # skipped in order to clear the volume. if volume_clear == 'zero': return copy_volume('/dev/zero', volume_path, volume_clear_size, CONF.volume_dd_blocksize, sync=True, execute=utils.execute, ionice=volume_clear_ionice, throttle=throttle, sparse=False) else: raise exception.InvalidConfigurationValue( option='volume_clear', value=volume_clear)
def _check_ops(self, required_ops, configuration): """Ensures that the options we care about are set.""" for op in required_ops: if not getattr(configuration, op): LOG.error('Configuration value %s is not set.', op) raise exception.InvalidConfigurationValue(option=op, value=None)
def __init__(self, config): """:param config: list of config values.""" self.proto = 'http' if config.get('driver_use_ssl', True): self.proto = 'https' self.hosts = config.get('san_hosts', []) self.port = str(config.get('san_api_port', 82)) for host in self.hosts: if o_netutils.is_valid_ip(host) is False: err_msg = ('Invalid value of jovian_host property: ' '%(addr)s, IP address expected.' % { 'addr': host }) LOG.debug(err_msg) raise exception.InvalidConfigurationValue(err_msg) self.active_host = 0 self.delay = config.get('jovian_recovery_delay', 40) self.pool = config.get('jovian_pool', 'Pool-0') self.user = config.get('san_login', 'admin') self.password = config.get('san_password', 'admin') self.verify = config.get('driver_ssl_cert_verify', True) self.cert = config.get('driver_ssl_cert_path') urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) self.session = self._get_session()
def __init__(self, context, chunk_size_bytes, sha_block_size_bytes, backup_default_container, enable_progress_timer, db=None): super(ChunkedBackupDriver, self).__init__(context, db) self.chunk_size_bytes = chunk_size_bytes self.sha_block_size_bytes = sha_block_size_bytes self.backup_default_container = backup_default_container self.enable_progress_timer = enable_progress_timer self.backup_timer_interval = CONF.backup_timer_interval self.data_block_num = CONF.backup_object_number_per_notification self.az = CONF.storage_availability_zone self.backup_compression_algorithm = CONF.backup_compression_algorithm self.compressor = \ self._get_compressor(CONF.backup_compression_algorithm) self.support_force_delete = True if sys.platform == 'win32' and self.chunk_size_bytes % 4096: # The chunk size must be a multiple of the sector size. In order # to fail out early and avoid attaching the disks, we'll just # enforce the chunk size to be a multiple of 4096. err = _("Invalid chunk size. It must be a multiple of 4096.") raise exception.InvalidConfigurationValue(message=err)
def __init__(self, name, loader=None): """Initialize, but do not start the WSGI server. :param name: The name of the WSGI server given to the loader. :param loader: Loads the WSGI application using the given name. :returns: None """ self.name = name self.manager = self._get_manager() self.loader = loader or wsgi.Loader(CONF) self.app = self.loader.load_app(name) self.host = getattr(CONF, '%s_listen' % name, "0.0.0.0") self.port = getattr(CONF, '%s_listen_port' % name, 0) self.use_ssl = getattr(CONF, '%s_use_ssl' % name, False) self.workers = (getattr(CONF, '%s_workers' % name, None) or processutils.get_worker_count()) if self.workers and self.workers < 1: worker_name = '%s_workers' % name msg = (_("%(worker_name)s value of %(workers)d is invalid, " "must be greater than 0.") % { 'worker_name': worker_name, 'workers': self.workers }) raise exception.InvalidConfigurationValue(msg) setup_profiler(name, self.host) self.server = wsgi.Server(CONF, name, self.app, host=self.host, port=self.port, use_ssl=self.use_ssl)
def _get_pool_lun_provisioned_size(self): pool_name = self.config.synology_pool_name if not pool_name: raise exception.InvalidConfigurationValue(option='pool_name', value=pool_name) try: out = self.exec_webapi('SYNO.Core.ISCSI.LUN', 'list', 1, location='/' + pool_name) self.check_response(out) except Exception: with excutils.save_and_reraise_exception(): LOG.exception('Failed to _get_pool_lun_provisioned_size.') if not self.check_value_valid(out, ['data', 'luns'], list): raise exception.MalformedResponse( cmd='_get_pool_lun_provisioned_size', reason=_('no data found')) size = 0 for lun in out['data']['luns']: size += lun['size'] return int(math.ceil(float(size) / units.Gi))
def remove_empty(option, value_list): if value_list is not None: value_list = list(filter(None, map(str.strip, value_list))) if not value_list: raise exception.InvalidConfigurationValue(option=option, value=value_list) return value_list
def check_for_setup_error(self): required_options = ('backup_gcs_bucket', 'backup_gcs_credential_file', 'backup_gcs_project_id') for opt in required_options: val = getattr(CONF, opt, None) if not val: raise exception.InvalidConfigurationValue(option=opt, value=val)
def do_setup(self, context): """Any initialization the volume driver does while starting.""" super(NfsDriver, self).do_setup(context) config = self.configuration.nfs_shares_config if not config: msg = (_("There's no NFS config file configured (%s)") % 'nfs_shares_config') LOG.warning(msg) raise exception.NfsException(msg) if not os.path.exists(config): msg = (_("NFS config file at %(config)s doesn't exist") % {'config': config}) LOG.warning(msg) raise exception.NfsException(msg) if not self.configuration.nfs_oversub_ratio > 0: msg = _("NFS config 'nfs_oversub_ratio' invalid. Must be > 0: " "%s") % self.configuration.nfs_oversub_ratio LOG.error(msg) raise exception.InvalidConfigurationValue(msg) if not ((self.configuration.nfs_used_ratio > 0) and (self.configuration.nfs_used_ratio <= 1)): msg = _("NFS config 'nfs_used_ratio' invalid. Must be > 0 " "and <= 1.0: %s") % self.configuration.nfs_used_ratio LOG.error(msg) raise exception.InvalidConfigurationValue(msg) self.shares = {} # address : options # Check if mount.nfs is installed on this system; note that we don't # need to be root to see if the package is installed. package = 'mount.nfs' try: self._execute(package, check_exit_code=False, run_as_root=False) except OSError as exc: if exc.errno == errno.ENOENT: msg = _('%s is not installed') % package raise exception.NfsException(msg) else: raise # Now that all configuration data has been loaded (shares), # we can "set" our final NAS file security options. self.set_nas_security_options(self._is_voldb_empty_at_startup)
def check_for_setup_error(self): """Raises error if any required configuration flag is missing.""" required_flags = ['glusterfs_backup_share'] for flag in required_flags: val = getattr(CONF, flag, None) if not val: raise exception.InvalidConfigurationValue(option=flag, value=val)
def setup_api_trace_pattern(api_trace_pattern): global API_TRACE_PATTERN try: re.compile(api_trace_pattern) except (re.error, TypeError): msg = _('Cannot parse the API trace pattern. %s is not a ' 'valid python regular expression.') % api_trace_pattern raise exception.InvalidConfigurationValue(msg) API_TRACE_PATTERN = api_trace_pattern
def _get_iscsi_properties(self, volume, connector): """Return dict according to cinder/driver.py implementation. :param volume: :return: """ vname = volume["id"] zvol_info = self.ra.get_zvol_info(self.pool, vname) if zvol_info is None: LOG.debug('JovianDSS: Unable to get zvol lun for' ' volume %s.', vname) raise exception.VolumeBackendAPIException( 'JovianDSS: Unable to get' ' zvolume lun for volume %s.', vname) iface_info = [] multipath = connector.get('multipath', False) if multipath is True: iface_info = self._get_active_ifaces() if not iface_info: raise exception.InvalidConfigurationValue( 'JovianDSS: No available interfaces ' 'or config excludes them') iscsi_properties = dict() if multipath: iscsi_properties['target_iqns'] = [] iscsi_properties['target_portals'] = [] iscsi_properties['target_luns'] = [] LOG.debug('JovianDSS: tpaths %s.', str(iface_info)) for iface in iface_info: iscsi_properties['target_iqns'].append( self.jovian_target_prefix + vname) iscsi_properties['target_portals'].append( iface + ":" + self.jovian_iscsi_target_portal_port) iscsi_properties['target_luns'].append(int(zvol_info["lun"])) else: iscsi_properties['target_iqn'] = self.jovian_target_prefix + vname iscsi_properties['target_portal'] = \ self.jovian_host + ":" + self.jovian_iscsi_target_portal_port iscsi_properties['target_discovered'] = False auth = volume['provider_auth'] if auth: (auth_method, auth_username, auth_secret) = auth.split() iscsi_properties['auth_method'] = auth_method iscsi_properties['auth_username'] = auth_username iscsi_properties['auth_password'] = auth_secret iscsi_properties['target_lun'] = int(zvol_info["lun"]) return iscsi_properties
def check_io_parameter(self, specs): if ('upperlimit' not in specs and 'lowerlimit' not in specs and 'upperreport' not in specs): specs['upperlimit'] = None specs['lowerlimit'] = None specs['upperreport'] = None LOG.debug('qos parameter not found.') else: if 'upperlimit' in specs and specs['upperlimit'] is not None: if self.validates_number(specs['upperlimit']) is True: upper_limit = int(specs['upperlimit'], 10) if ((upper_limit != 0) and ((upper_limit < 10) or (upper_limit > 1000000))): raise exception.InvalidConfigurationValue( value=upper_limit, option='upperlimit') else: raise exception.InvalidConfigurationValue( value=specs['upperlimit'], option='upperlimit') else: specs['upperlimit'] = None if 'lowerlimit' in specs and specs['lowerlimit'] is not None: if self.validates_number(specs['lowerlimit']) is True: lower_limit = int(specs['lowerlimit'], 10) if (lower_limit != 0 and (lower_limit < 10 or lower_limit > 1000000)): raise exception.InvalidConfigurationValue( value=lower_limit, option='lowerlimit') else: raise exception.InvalidConfigurationValue( value=specs['lowerlimit'], option='lowerlimit') else: specs['lowerlimit'] = None if 'upperreport' in specs: if specs['upperreport'] not in ['on', 'off']: LOG.debug( 'Illegal arguments. ' 'upperreport is not on or off.' 'upperreport=%s', specs['upperreport']) specs['upperreport'] = None else: specs['upperreport'] = None
def correct_qos_parameter(self, specs, reset): if 'upperlimit' in specs and specs['upperlimit'] is not None: if self.validates_number(specs['upperlimit']) is True: upper_limit = int(specs['upperlimit'], 10) if ((upper_limit != 0) and ((upper_limit < 10) or (upper_limit > 1000000))): raise exception.InvalidConfigurationValue( value=upper_limit, option='upperlimit') else: raise exception.InvalidConfigurationValue( value=specs['upperlimit'], option='upperlimit') else: # 0: Set to no limit.(default) # None: Keep current value. specs['upperlimit'] = '0' if reset else None if 'lowerlimit' in specs and specs['lowerlimit'] is not None: if self.validates_number(specs['lowerlimit']) is True: lower_limit = int(specs['lowerlimit'], 10) if (lower_limit != 0 and (lower_limit < 10 or lower_limit > 1000000)): raise exception.InvalidConfigurationValue( value=lower_limit, option='lowerlimit') else: raise exception.InvalidConfigurationValue( value=specs['lowerlimit'], option='lowerlimit') else: # 0: Set to no limit.(default) # None: Keep current value. specs['lowerlimit'] = '0' if reset else None if 'upperreport' in specs: if specs['upperreport'] not in ['on', 'off']: LOG.debug( 'Illegal arguments. ' 'upperreport is not on or off.' 'upperreport=%s', specs['upperreport']) specs['upperreport'] = 'off' if reset else None else: # off: Set to no report.(default) # None: Keep current value. specs['upperreport'] = 'off' if reset else None
def check_for_setup_error(self): versionutils.report_deprecated_feature( LOG, "Cinder TSM Backup Driver is deprecated and will be removed " "in Wallaby release. Please, migrate you backups to a supported " "backend.") required_flags = ['backup_share'] for flag in required_flags: val = getattr(CONF, flag, None) if not val: raise exception.InvalidConfigurationValue(option=flag, value=val)
def clear_volume(self, volume, is_snapshot=False): """unprovision old volumes to prevent data leaking between users.""" # NOTE(jdg): Don't write the blocks of thin provisioned # volumes if self.configuration.volume_clear == 'none' or \ self.configuration.lvm_type == 'thin': return if is_snapshot: # if the volume to be cleared is a snapshot of another volume # we need to clear out the volume using the -cow instead of the # directly volume path. We need to skip this if we are using # thin provisioned LVs. # bug# lp1191812 dev_path = self.local_path(volume) + "-cow" else: dev_path = self.local_path(volume) if not os.path.exists(dev_path): msg = (_('Volume device file path %s does not exist.') % dev_path) LOG.error(msg) raise exception.VolumeBackendAPIException(data=msg) size_in_g = volume.get('size', volume.get('volume_size', None)) if size_in_g is None: msg = (_("Size for volume: %s not found, " "cannot secure delete.") % volume['id']) LOG.error(msg) raise exception.InvalidParameterValue(msg) size_in_m = self.configuration.volume_clear_size LOG.info(_("Performing secure delete on volume: %s") % volume['id']) if self.configuration.volume_clear == 'zero': if size_in_m == 0: return volutils.copy_volume('/dev/zero', dev_path, size_in_g * 1024, sync=True, execute=self._execute) else: clear_cmd = ['shred', '-n0', '-z', '-s%dMiB' % size_in_m] elif self.configuration.volume_clear == 'shred': clear_cmd = ['shred', '-n3'] if size_in_m: clear_cmd.append('-s%dMiB' % size_in_m) else: raise exception.InvalidConfigurationValue( option='volume_clear', value=self.configuration.volume_clear) clear_cmd.append(dev_path) self._execute(*clear_cmd, run_as_root=True)
def _get_iscsi_properties(self, volume, connector): """Return dict according to cinder/driver.py implementation. :param volume: :return: """ tname = self.jovian_target_prefix + volume.id iface_info = [] multipath = connector.get('multipath', False) if multipath: iface_info = self._get_active_ifaces() if not iface_info: raise exception.InvalidConfigurationValue( _('No available interfaces ' 'or config excludes them')) iscsi_properties = dict() if multipath: iscsi_properties['target_iqns'] = [] iscsi_properties['target_portals'] = [] iscsi_properties['target_luns'] = [] LOG.debug('tpaths %s.', iface_info) for iface in iface_info: iscsi_properties['target_iqns'].append( self.jovian_target_prefix + volume.id) iscsi_properties['target_portals'].append( iface + ":" + str(self.jovian_iscsi_target_portal_port)) iscsi_properties['target_luns'].append(0) else: iscsi_properties['target_iqn'] = tname iscsi_properties['target_portal'] = ( self.ra.get_active_host() + ":" + str(self.jovian_iscsi_target_portal_port)) iscsi_properties['target_discovered'] = False auth = volume.provider_auth if auth: (auth_method, auth_username, auth_secret) = auth.split() iscsi_properties['auth_method'] = auth_method iscsi_properties['auth_username'] = auth_username iscsi_properties['auth_password'] = auth_secret iscsi_properties['target_lun'] = 0 return iscsi_properties
def clear_volume(volume_size, volume_path, volume_clear=None, volume_clear_size=None, volume_clear_ionice=None, throttle=None): """Unprovision old volumes to prevent data leaking between users.""" if volume_clear is None: volume_clear = CONF.volume_clear if volume_clear_size is None: volume_clear_size = CONF.volume_clear_size if volume_clear_size == 0: volume_clear_size = volume_size if volume_clear_ionice is None: volume_clear_ionice = CONF.volume_clear_ionice LOG.info(_LI("Performing secure delete on volume: %s"), volume_path) # We pass sparse=False explicitly here so that zero blocks are not # skipped in order to clear the volume. if volume_clear == 'zero': return copy_volume('/dev/zero', volume_path, volume_clear_size, CONF.volume_dd_blocksize, sync=True, execute=utils.execute, ionice=volume_clear_ionice, throttle=throttle, sparse=False) elif volume_clear == 'shred': clear_cmd = ['shred', '-n3'] if volume_clear_size: clear_cmd.append('-s%dMiB' % volume_clear_size) else: raise exception.InvalidConfigurationValue(option='volume_clear', value=volume_clear) clear_cmd.append(volume_path) start_time = timeutils.utcnow() utils.execute(*clear_cmd, run_as_root=True) duration = timeutils.delta_seconds(start_time, timeutils.utcnow()) # NOTE(jdg): use a default of 1, mostly for unit test, but in # some incredible event this is 0 (cirros image?) don't barf if duration < 1: duration = 1 LOG.info(_LI('Elapsed time for clear volume: %.2f sec'), duration)
def test_init_host_retry(self, mock_sleep): kwargs = {'service_id': 2} self.volume = importutils.import_object(CONF.volume_manager) self.volume.driver.do_setup = mock.MagicMock() self.volume.driver.do_setup.side_effect = [ exception.CinderException("Test driver error."), exception.InvalidConfigurationValue('Test config error.'), ImportError ] self.volume.init_host(added_to_cluster=False, **kwargs) self.assertEqual(4, self.volume.driver.do_setup.call_count) self.assertFalse(self.volume.is_working())
def check_for_setup_error(self): """Return an error if prerequisites aren't met.""" super(RBDISCSIDriver, self).check_for_setup_error() required_options = [ 'rbd_iscsi_api_user', 'rbd_iscsi_api_password', 'rbd_iscsi_api_url', 'rbd_iscsi_target_iqn' ] for attr in required_options: val = getattr(self.configuration, attr) if not val: raise exception.InvalidConfigurationValue(option=attr, value=val)
def check_for_setup_error(self): """Check for setup error.""" if len(self.jovian_hosts) == 0: msg = _("No hosts provided in configuration") raise exception.VolumeDriverException(msg) if not self.ra.is_pool_exists(): msg = (_("Unable to identify pool %s") % self._pool) raise exception.VolumeDriverException(msg) valid_bsize = ['16K', '32K', '64K', '128K', '256K', '512K', '1M'] if self.block_size not in valid_bsize: raise exception.InvalidConfigurationValue( value=self.block_size, option='jovian_block_size')