def connect_volume(self, connection_properties): """Attach the volume to instance_name. :param connection_properties: The dictionary that describes all of the target volume attributes. :type connection_properties: dict :returns: dict connection_properties for Fibre Channel must include: target_wwn - World Wide Name target_lun - LUN id of the volume """ LOG.debug("execute = %s", self._execute) device_info = {'type': 'block'} hbas = self._linuxfc.get_fc_hbas_info() host_devices = self._get_possible_volume_paths(connection_properties, hbas) if len(host_devices) == 0: # this is empty because we don't have any FC HBAs LOG.warning("We are unable to locate any Fibre Channel devices") raise exception.NoFibreChannelHostsFound() # The /dev/disk/by-path/... node is not always present immediately # We only need to find the first device. Once we see the first device # multipath will have any others. def _wait_for_device_discovery(host_devices): tries = self.tries for device in host_devices: LOG.debug("Looking for Fibre Channel dev %(device)s", {'device': device}) if os.path.exists(device): self.host_device = device # get the /dev/sdX device. This is used # to find the multipath device. self.device_name = os.path.realpath(device) raise loopingcall.LoopingCallDone() if self.tries >= self.device_scan_attempts: LOG.error("Fibre Channel volume device not found.") raise exception.NoFibreChannelVolumeDeviceFound() LOG.info( "Fibre Channel volume device not yet found. " "Will rescan & retry. Try number: %(tries)s.", {'tries': tries}) self._linuxfc.rescan_hosts(hbas, connection_properties['target_lun']) self.tries = self.tries + 1 self.host_device = None self.device_name = None self.tries = 0 timer = loopingcall.FixedIntervalLoopingCall( _wait_for_device_discovery, host_devices) timer.start(interval=2).wait() tries = self.tries if self.host_device is not None and self.device_name is not None: LOG.debug( "Found Fibre Channel volume %(name)s " "(after %(tries)s rescans)", { 'name': self.device_name, 'tries': tries }) # find out the WWN of the device device_wwn = self._linuxscsi.get_scsi_wwn(self.host_device) LOG.debug("Device WWN = '%(wwn)s'", {'wwn': device_wwn}) device_info['scsi_wwn'] = device_wwn # see if the new drive is part of a multipath # device. If so, we'll use the multipath device. if self.use_multipath: (device_path, multipath_id) = (super(FibreChannelConnector, self)._discover_mpath_device( device_wwn, connection_properties, self.device_name)) if multipath_id: # only set the multipath_id if we found one device_info['multipath_id'] = multipath_id else: device_path = self.host_device device_info['path'] = device_path LOG.debug("connect_volume returning %s", device_info) return device_info
def connect_volume(self, connection_properties): """Attach the volume to instance_name. :param connection_properties: The dictionary that describes all of the target volume attributes. :type connection_properties: dict :returns: dict connection_properties for Fibre Channel must include: target_wwn - World Wide Name target_lun - LUN id of the volume """ device_info = {'type': 'block'} connection_properties = self._add_targets_to_connection_properties( connection_properties) hbas = self._linuxfc.get_fc_hbas_info() if not hbas: LOG.warning("We are unable to locate any Fibre Channel devices.") raise exception.NoFibreChannelHostsFound() host_devices = self._get_possible_volume_paths( connection_properties, hbas) # The /dev/disk/by-path/... node is not always present immediately # We only need to find the first device. Once we see the first device # multipath will have any others. def _wait_for_device_discovery(host_devices): for device in host_devices: LOG.debug("Looking for Fibre Channel dev %(device)s", {'device': device}) if os.path.exists(device) and self.check_valid_device(device): self.host_device = device # get the /dev/sdX device. This variable is maintained to # keep the same log output. self.device_name = os.path.realpath(device) raise loopingcall.LoopingCallDone() if self.tries >= self.device_scan_attempts: LOG.error("Fibre Channel volume device not found.") raise exception.NoFibreChannelVolumeDeviceFound() LOG.info("Fibre Channel volume device not yet found. " "Will rescan & retry. Try number: %(tries)s.", {'tries': self.tries}) self._linuxfc.rescan_hosts(hbas, connection_properties) self.tries = self.tries + 1 self.host_device = None self.device_name = None self.tries = 0 timer = loopingcall.FixedIntervalLoopingCall( _wait_for_device_discovery, host_devices) timer.start(interval=2).wait() LOG.debug("Found Fibre Channel volume %(name)s " "(after %(tries)s rescans.)", {'name': self.device_name, 'tries': self.tries}) # find out the WWN of the device device_wwn = self._linuxscsi.get_scsi_wwn(self.host_device) LOG.debug("Device WWN = '%(wwn)s'", {'wwn': device_wwn}) device_info['scsi_wwn'] = device_wwn # see if the new drive is part of a multipath # device. If so, we'll use the multipath device. if self.use_multipath: # Pass a symlink, not a real path, otherwise we'll get a real path # back if we don't find a multipath and we'll return that to the # caller, breaking Nova's encryption which requires a symlink. (device_path, multipath_id) = self._discover_mpath_device( device_wwn, connection_properties, self.host_device) if multipath_id: # only set the multipath_id if we found one device_info['multipath_id'] = multipath_id else: device_path = self.host_device device_info['path'] = device_path return device_info