def create_export(self, context, volume, connector): """Driver entry point to get the export info for a new volume.""" target_name = self._get_target_name(volume) updates = {} if not self._tgt_utils.iscsi_target_exists(target_name): self._tgt_utils.create_iscsi_target(target_name) updates['provider_location'] = target_name if self.configuration.use_chap_auth: chap_username = (self.configuration.chap_username or volume_utils.generate_username()) chap_password = (self.configuration.chap_password or volume_utils.generate_password()) self._tgt_utils.set_chap_credentials(target_name, chap_username, chap_password) updates['provider_auth'] = ' '.join( ('CHAP', chap_username, chap_password)) # This operation is idempotent self._tgt_utils.add_disk_to_target(volume.name, target_name) return updates
def create_export(self, context, volume, volume_path): """Creates an export for a logical volume.""" # 'iscsi_name': 'iqn.2010-10.org.openstack:volume-00000001' iscsi_name = "%s%s" % (self.configuration.target_prefix, volume['name']) iscsi_target, lun = self._get_target_and_lun(context, volume) # Verify we haven't setup a CHAP creds file already # if DNE no big deal, we'll just create it chap_auth = self._get_target_chap_auth(context, volume) if not chap_auth: chap_auth = (volume_utils.generate_username(), volume_utils.generate_password()) # Get portals ips and port portals_config = self._get_portals_config() # NOTE(jdg): For TgtAdm case iscsi_name is the ONLY param we need # should clean this all up at some point in the future tid = self.create_iscsi_target(iscsi_name, iscsi_target, lun, volume_path, chap_auth, **portals_config) data = {} data['location'] = self._iscsi_location( self.configuration.target_ip_address, tid, iscsi_name, lun, self.configuration.iscsi_secondary_ip_addresses) LOG.debug('Set provider_location to: %s', data['location']) data['auth'] = self._iscsi_authentication( 'CHAP', *chap_auth) return data
def _get_provider_auth(self): """Get provider authentication for the volume. :return: string of auth method and credentials """ chap_user = volume_utils.generate_password( length=8, symbolgroups=(string.ascii_lowercase + string.ascii_uppercase)) chap_password = volume_utils.generate_password( length=self.jovian_chap_pass_len, symbolgroups=(string.ascii_lowercase + string.ascii_uppercase + string.digits)) return 'CHAP {user} {passwd}'.format(user=chap_user, passwd=chap_password)
def _configure_chap(self, initiator_name): password = volume_utils.generate_password(na_utils.CHAP_SECRET_LENGTH) username = na_utils.DEFAULT_CHAP_USER_NAME self.zapi_client.set_iscsi_chap_authentication(initiator_name, username, password) LOG.debug("Set iSCSI CHAP authentication.") return username, password
def get_chap_credentials(): """Generate CHAP credentials. :return: CHAP username and secret """ return { "chap_single_username": CHAP_DEFAULT_USERNAME, "chap_single_password": volume_utils.generate_password( CHAP_DEFAULT_SECRET_LENGTH ) }
def initialize_connection(self, volume, connector): """Export a volume to a host.""" # create client initiator_iqn = connector['initiator'] self.create_client(initiator_iqn) auth = self._get_auth_for_client(initiator_iqn) username = initiator_iqn if not auth['password']: password = volume_utils.generate_password(length=self.CHAP_LENGTH) self._set_chap_for_client(initiator_iqn, username, password) else: LOG.debug("using existing CHAP password") password = auth['password'] # add disk for export iscsi_config = self._get_config() # First have to ensure that the disk is registered with # the gateways. self.create_disk(volume.name) self.register_disk(self.target_iqn, volume.name) iscsi_config = self._get_config() # Now export the disk to the initiator lun = self.export_disk(initiator_iqn, volume.name, iscsi_config) # fetch the updated config so we can get the lun id iscsi_config = self._get_config() target_info = iscsi_config['targets'][self.target_iqn] ips = target_info['ip_list'] target_portal = ips[0] if netutils.is_valid_ipv6(target_portal): target_portal = "[%s]:3260" % target_portal else: target_portal = "%s:3260" % target_portal data = { 'driver_volume_type': 'iscsi', 'data': { 'target_iqn': self.target_iqn, 'target_portal': target_portal, 'target_lun': lun['id'], 'auth_method': 'CHAP', 'auth_username': username, 'auth_password': password, } } return data
def create_nvmeof_target(self, volume_id, subsystem_name, target_ip, target_port, transport_type, nvmet_port_id, ns_id, volume_path): LOG.debug('SPDK create target') nqn = self._get_nqn_with_volume_name(volume_id) if nqn is None: node = self._get_first_free_node() nqn = '%s:cnode%s' % (subsystem_name, node) choice = string.ascii_uppercase + string.digits serial = ''.join( volume_utils.generate_password(length=12, symbolgroups=choice)) params = { 'nqn': nqn, 'allow_any_host': True, 'serial_number': serial, } self._rpc_call('nvmf_create_subsystem', params) listen_address = { 'trtype': transport_type, 'traddr': target_ip, 'trsvcid': str(target_port), } params = { 'nqn': nqn, 'listen_address': listen_address, } self._rpc_call('nvmf_subsystem_add_listener', params) ns = { 'bdev_name': self._get_spdk_volume_name(volume_id), 'nsid': ns_id, } params = { 'nqn': nqn, 'namespace': ns, } self._rpc_call('nvmf_subsystem_add_ns', params) location = self.get_nvmeof_location(nqn, target_ip, target_port, transport_type, ns_id) return {'location': location, 'auth': '', 'provider_id': nqn}
def _target_create(self, identifier): if not identifier: err = _('Param [identifier] is invalid.') raise exception.InvalidParameterValue(err=err) # 0 for no auth, 1 for single chap, 2 for mutual chap auth_type = 0 chap_username = '' chap_password = '' provider_auth = '' if self.config.safe_get('use_chap_auth') and self.config.use_chap_auth: auth_type = 1 chap_username = (self.config.safe_get('chap_username') or volume_utils.generate_username(12)) chap_password = (self.config.safe_get('chap_password') or volume_utils.generate_password()) provider_auth = ' '.join(('CHAP', chap_username, chap_password)) trg_prefix = self.config.safe_get('target_prefix') trg_name = (self.TARGET_NAME_PREFIX + '%s') % identifier iqn = trg_prefix + trg_name try: out = self.exec_webapi('SYNO.Core.ISCSI.Target', 'create', 1, name=trg_name, iqn=iqn, auth_type=auth_type, user=chap_username, password=chap_password, max_sessions=0) self.check_response(out) except Exception: with excutils.save_and_reraise_exception(): LOG.exception('Failed to _target_create. [%s]', identifier) if not self.check_value_valid(out, ['data', 'target_id']): msg = _('Failed to get target_id of target [%s]') % trg_name raise exception.VolumeDriverException(message=msg) trg_id = out['data']['target_id'] return iqn, trg_id, provider_auth
def create_export(self, context, volume, volume_path): """Creates an export for a logical volume.""" iscsi_target, lun = self._get_target_and_lun(context, volume) iscsi_name = self._get_iscsi_name(volume) if self.chap_username and self.chap_password: chap_auth = (self.chap_username, self.chap_password) else: chap_auth = self._get_target_chap_auth(context, volume) if not chap_auth: chap_auth = (volume_utils.generate_username(), volume_utils.generate_password()) tid = self.create_iscsi_target(iscsi_name, volume['id'], iscsi_target, lun, volume_path, chap_auth) data = {} data['location'] = self._iscsi_location( self.configuration.target_ip_address, tid, iscsi_name, lun) LOG.debug('Set provider_location to: %s', data['location']) data['auth'] = self._iscsi_authentication('CHAP', *chap_auth) return data
def _initialize_connection_iscsi(self, volume, connector): volume_name = self._make_volume_name(volume) infinidat_volume = self._get_infinidat_volume_by_name(volume_name) port = iqn.IQN(connector['initiator']) infinidat_host = self._get_or_create_host(port) if self.configuration.use_chap_auth: chap_username = (self.configuration.chap_username or volume_utils.generate_username()) chap_password = (self.configuration.chap_password or volume_utils.generate_password()) infinidat_host.update_fields( security_method='CHAP', security_chap_inbound_username=chap_username, security_chap_inbound_secret=chap_password) mapping = self._get_or_create_mapping(infinidat_host, infinidat_volume) lun = mapping.get_lun() netspace_names = self.configuration.infinidat_iscsi_netspaces target_portals = [] target_iqns = [] target_luns = [] for netspace_name in netspace_names: netspace = self._get_iscsi_network_space(netspace_name) target_portals.append(self._get_iscsi_portal(netspace)) target_iqns.append(netspace.get_properties().iscsi_iqn) target_luns.append(lun) result_data = dict(target_discovered=True, target_portal=target_portals[0], target_iqn=target_iqns[0], target_lun=target_luns[0], target_portals=target_portals, target_iqns=target_iqns, target_luns=target_luns) if self.configuration.use_chap_auth: result_data.update( dict(auth_method='CHAP', auth_username=chap_username, auth_password=chap_password)) return dict(driver_volume_type='iscsi', data=result_data)
def _setup_iscsi_chap_authentication(self, targets, initiator): iscsi_chap_enabled = self.configuration.datacore_iscsi_chap_enabled self._check_iscsi_chap_configuration(iscsi_chap_enabled, targets) server_group = self._get_our_server_group() update_access_token = False access_token = None chap_secret = None if iscsi_chap_enabled: authentication = 'CHAP' chap_secret = self._password_storage.get_password( server_group.Id, initiator.PortName) update_access_token = False if not chap_secret: chap_secret = volume_utils.generate_password(length=15) self._password_storage.set_password(server_group.Id, initiator.PortName, chap_secret) update_access_token = True access_token = self._api.build_access_token( initiator.PortName, None, None, False, initiator.PortName, chap_secret) else: authentication = 'None' if self._password_storage: self._password_storage.delete_password(server_group.Id, initiator.PortName) changed_targets = {} try: for target in targets: if iscsi_chap_enabled: target_iscsi_nodes = getattr(target.iSCSINodes, 'Node', []) iscsi_node = datacore_utils.get_first_or_default( lambda node: node.Name == initiator.PortName, target_iscsi_nodes, None) if (not iscsi_node or not iscsi_node.AccessToken.TargetUsername or update_access_token): self._api.set_access_token(target.Id, access_token) properties = target.ServerPortProperties if properties.Authentication != authentication: changed_targets[target] = properties.Authentication properties.Authentication = authentication self._api.set_server_port_properties(target.Id, properties) except Exception: with excutils.save_and_reraise_exception(): LOG.exception( "Configuring of iSCSI CHAP authentication for " "initiator %(initiator)s failed.", {'initiator': initiator.PortName}) try: for target in changed_targets: properties = target.ServerPortProperties properties.Authentication = changed_targets[target] self._api.set_server_port_properties( target.Id, properties) except datacore_exception.DataCoreException as e: LOG.warning( "An error occurred on a cleanup after failed " "configuration of iSCSI CHAP authentication " "on initiator %(initiator)s: %(error)s.", { 'initiator': initiator.PortName, 'error': e }) if iscsi_chap_enabled: return initiator.PortName, chap_secret
def _do_export(self, common, volume, connector): """Gets the associated account, generates CHAP info and updates.""" model_update = {} if not common._client_conf['hpe3par_iscsi_chap_enabled']: model_update['provider_auth'] = None return model_update # CHAP username will be the hostname chap_username = connector['host'] chap_password = None try: # Get all active VLUNs for the host vluns = common.client.getHostVLUNs(chap_username) # Host has active VLUNs... is CHAP enabled on host? host_info = common.client.getHost(chap_username) if not host_info['initiatorChapEnabled']: LOG.warning("Host has no CHAP key, but CHAP is enabled.") except hpeexceptions.HTTPNotFound: chap_password = volume_utils.generate_password(16) LOG.warning("No host or VLUNs exist. Generating new " "CHAP key.") else: # Get a list of all iSCSI VLUNs and see if there is already a CHAP # key assigned to one of them. Use that CHAP key if present, # otherwise create a new one. Skip any VLUNs that are missing # CHAP credentials in metadata. chap_exists = False active_vluns = 0 for vlun in vluns: if not vlun['active']: continue active_vluns += 1 # iSCSI connections start with 'iqn'. if ('remoteName' in vlun and re.match('iqn.*', vlun['remoteName'])): try: chap_password = common.client.getVolumeMetaData( vlun['volumeName'], CHAP_PASS_KEY)['value'] chap_exists = True break except hpeexceptions.HTTPNotFound: LOG.debug( "The VLUN %s is missing CHAP credentials " "but CHAP is enabled. Skipping.", vlun['remoteName']) else: LOG.warning("Non-iSCSI VLUN detected.") if not chap_exists: chap_password = volume_utils.generate_password(16) LOG.warning("No VLUN contained CHAP credentials. " "Generating new CHAP key.") # Add CHAP credentials to the volume metadata vol_name = common._get_3par_vol_name(volume) common.client.setVolumeMetaData(vol_name, CHAP_USER_KEY, chap_username) common.client.setVolumeMetaData(vol_name, CHAP_PASS_KEY, chap_password) model_update['provider_auth'] = ('CHAP %s %s' % (chap_username, chap_password)) return model_update