def _wait_for_power_off(self, instance_name, time_limit): """Waiting for a VM to be in a disabled state. :return: True if the instance is shutdown within time_limit, False otherwise. """ desired_vm_states = [constants.HYPERV_VM_STATE_DISABLED] def _check_vm_status(instance_name): if self._get_vm_state(instance_name) in desired_vm_states: raise loopingcall.LoopingCallDone() periodic_call = loopingcall.FixedIntervalLoopingCall( _check_vm_status, instance_name) try: # add a timeout to the periodic call. periodic_call.start(interval=SHUTDOWN_TIME_INCREMENT) etimeout.with_timeout(time_limit, periodic_call.wait) except etimeout.Timeout: # VM did not shutdown in the expected time_limit. return False finally: # stop the periodic call, in case of exceptions or Timeout. periodic_call.stop() return True
def _async_build_and_run_instance(): # check dest compute service is alive utils.spawn_n(async_check_live) timer = loopingcall.FixedIntervalLoopingCall(_loop_check) timer.start(interval=1).wait() if not alive_dict['alive']: LOG.warn( '%s compute service seems down, revert instance ' 'task state', host_state, instance=instance) instance.task_state = None instance.save() return LOG.info('build instance on host %s', host_state, instance=instance) self.compute_rpcapi.sync_build_and_run_instance( context, instance=instance, host=host_state, image=image, request_spec=request_spec, filter_properties=filter_properties, admin_password=None, injected_files=jsonutils.loads(injected_files), requested_networks=request_networks, security_groups=security_groups, block_device_mapping=bdms, node=host_state, limits=hosts[0]['limits'])
def reboot(self, context, instance, network_info, reboot_type, block_device_info=None, bad_volumes_callback=None): """Reboot the specified instance. NOTE: Ironic does not support soft-off, so this method always performs a hard-reboot. NOTE: Unlike the libvirt driver, this method does not delete and recreate the instance; it preserves local state. :param context: The security context. :param instance: The instance object. :param network_info: Instance network information. Ignored by this driver. :param reboot_type: Either a HARD or SOFT reboot. Ignored by this driver. :param block_device_info: Info pertaining to attached volumes. Ignored by this driver. :param bad_volumes_callback: Function to handle any bad volumes encountered. Ignored by this driver. """ node = _validate_instance_and_node(self.ironicclient, instance) self.ironicclient.call("node.set_power_state", node.uuid, 'reboot') timer = loopingcall.FixedIntervalLoopingCall( self._wait_for_power_state, self.ironicclient, instance, 'reboot') timer.start(interval=CONF.ironic.api_retry_interval).wait()
def __init__(self, get_connection): super(VRouterVIFDriver, self).__init__(get_connection) self._vrouter_semaphore = eventlet.semaphore.Semaphore() self._vrouter_client = ContrailVRouterApi( doconnect=True, semaphore=self._vrouter_semaphore) timer = loopingcall.FixedIntervalLoopingCall(self._keep_alive) timer.start(interval=2)
def _wait_for_node_reboot(self, nodename): """Wait for xCAT node boot to complete.""" locals = {'errstr':''} def _wait_for_reboot(): out,err = self._exec_xcat_command("nodestat %s" % nodename) if err: locals['errstr'] = _("Error returned when quering node status" " for node %s:%s") % (nodename, err) LOG.warning(locals['errstr']) raise loopingcall.LoopingCallDone() if out: node,status = out.split(": ") status = status.strip() if status == "sshd": LOG.info(_("Rebooting node %s completed.") % nodename) raise loopingcall.LoopingCallDone() if (CONF.xcat.reboot_timeout and timeutils.utcnow() > expiration): locals['errstr'] = _("Timeout while waiting for" " rebooting node %s.") % nodename LOG.warning(locals['errstr']) raise loopingcall.LoopingCallDone() expiration = timeutils.utcnow() + datetime.timedelta( seconds=CONF.xcat.reboot_timeout) timer = loopingcall.FixedIntervalLoopingCall(_wait_for_reboot) # default check every 5 seconds timer.start(interval=CONF.xcat.reboot_checking_interval).wait() if locals['errstr']: raise exception.xCATRebootFailure(locals['errstr'])
def start(self): """ This method retrieves all services from PowerVC and for each service it creates a local nova-compute service. """ try: remote_services = self._get_filtered_remote_services() for remote_service in remote_services: eventlet.greenthread.sleep(0) self.new_compute_service(remote_service) if self.auto_refresh: refresher = loopingcall.FixedIntervalLoopingCall(self.refresh) refresher.start( interval=CONF.powervc.hypervisor_refresh_interval) LOG.info(_('The PowerVC compute service manager is running.')) self.running = True except Exception: LOG.exception("exception during startup. Stopping compute" "driver") traceback.print_exc() sys.exit(1)
def wait_task_done(self, task_uri, interval=3): """ :param task_uri: :param interval: :return: """ ret = {'success': False, 'reason': None} def _wait_done(): """ wait task result """ task = self.get_task(task_uri) if task['status'] == "success": LOG.info(_("Task [%s] is successfully." % task_uri)) ret['success'] = True raise loopingcall.LoopingCallDone() elif task['status'] == "failed": LOG.info(_("Task [%s] is failed, the reason is %s."), task_uri, task['reasonDes']) ret['reason'] = task['reasonDes'] raise loopingcall.LoopingCallDone() else: LOG.info(_("Task [%s] is running, the progress is %s."), task_uri, task['progress']) timer = loopingcall.FixedIntervalLoopingCall(_wait_done) timer.start(interval=interval).wait() return ret['success'], ret['reason']
def cleanup_volumes(self, instance): def _cleanup_vol(ioctx, volume, retryctx): try: rbd.RBD().remove(client.ioctx, volume) raise loopingcall.LoopingCallDone(retvalue=False) except (rbd.ImageBusy, rbd.ImageHasSnapshots): LOG.warn( _LW('rbd remove %(volume)s in pool %(pool)s ' 'failed'), { 'volume': volume, 'pool': self.pool }) retryctx['retries'] -= 1 if retryctx['retries'] <= 0: raise loopingcall.LoopingCallDone() with RADOSClient(self, self.pool) as client: def belongs_to_instance(disk): return disk.startswith(instance.uuid) volumes = rbd.RBD().list(client.ioctx) for volume in filter(belongs_to_instance, volumes): # NOTE(danms): We let it go for ten seconds retryctx = {'retries': 10} timer = loopingcall.FixedIntervalLoopingCall( _cleanup_vol, client.ioctx, volume, retryctx) timed_out = timer.start(interval=1).wait() if timed_out: # NOTE(danms): Run this again to propagate the error, but # if it succeeds, don't raise the loopingcall exception try: _cleanup_vol(client.ioctx, volume, retryctx) except loopingcall.LoopingCallDone: pass
def wait_for_power_state(instance, power_state, time_limit): """Waiting for a virtual machine to be in required power state. :param instance: nova.objects.instance.Instance :param power_state: nova.compute.power_state :param time_limit: (int) time limit for this task :return: True if the instance is in required power state within time_limit, False otherwise. """ def _check_power_state(instance): current_state = get_power_state(instance) LOG.debug("Wait for soft shutdown: (%s, %s)", current_state, power_state) if current_state == power_state: raise loopingcall.LoopingCallDone() response = True periodic_call = loopingcall.FixedIntervalLoopingCall(_check_power_state, instance) try: # add a timeout to the periodic call. periodic_call.start(interval=constants.SHUTDOWN_RETRY_INTERVAL) etimeout.with_timeout(time_limit, periodic_call.wait) except etimeout.Timeout: # Virtual machine did not shutdown in the expected time_limit. response = False finally: # Stop the periodic call, in case of exceptions or Timeout. periodic_call.stop() return response
def _poll_for_lpar_status(self, instance_name, status, operation, timeout=constants.POWERVM_LPAR_OPERATION_TIMEOUT): """Polls until the LPAR with the given name reaches the given status. :param instance_name: LPAR instance name :param status: Poll until the given LPAR status is reached :param operation: The operation being performed, e.g. 'stop_lpar' :param timeout: The number of seconds to wait. :raises: PowerVMLPARInstanceNotFound :raises: PowerVMLPAROperationTimeout :raises: InvalidParameterValue """ # make sure it's a valid status if (status == constants.POWERVM_NOSTATE or not status in constants.POWERVM_POWER_STATE): msg = _("Invalid LPAR state: %s") % status raise n_exc.InvalidParameterValue(err=msg) # raise the given timeout exception if the loop call doesn't complete # in the specified timeout timeout_exception = exception.PowerVMLPAROperationTimeout( operation=operation, instance_name=instance_name) with eventlet_timeout.Timeout(timeout, timeout_exception): def _wait_for_lpar_status(instance_name, status): """Called at an interval until the status is reached.""" lpar_obj = self.get_lpar(instance_name) if lpar_obj['state'] == status: raise loopingcall.LoopingCallDone() timer = loopingcall.FixedIntervalLoopingCall(_wait_for_lpar_status, instance_name, status) timer.start(interval=1).wait()
def power_on(self, context, instance, network_info, block_device_info=None): """Power on the specified instance. NOTE: Unlike the libvirt driver, this method does not delete and recreate the instance; it preserves local state. :param context: The security context. :param instance: The instance object. :param network_info: Instance network information. Ignored by this driver. :param block_device_info: Instance block device information. Ignored by this driver. """ node = _validate_instance_and_node(self.ironicclient, instance) self.ironicclient.call("node.set_power_state", node.uuid, 'on') timer = loopingcall.FixedIntervalLoopingCall( self._wait_for_power_state, self.ironicclient, instance, 'power on') timer.start(interval=CONF.ironic.api_retry_interval).wait()
def _power_off(self): """Turn the power to this node OFF.""" def _wait_for_power_off(): """Called at an interval until the node's power is off.""" if self.is_power_on() is False: self.state = baremetal_states.DELETED raise loopingcall.LoopingCallDone() if self.retries > CONF.baremetal.ipmi_power_retry: LOG.error( _("IPMI power off failed after %d tries") % (CONF.baremetal.ipmi_power_retry)) self.state = baremetal_states.ERROR raise loopingcall.LoopingCallDone() try: self.retries += 1 if not self.power_off_called: self._exec_ipmitool("power off") self.power_off_called = True except Exception: LOG.exception(_("IPMI power off failed")) self.retries = 0 self.power_off_called = False timer = loopingcall.FixedIntervalLoopingCall(_wait_for_power_off) timer.start(interval=1.0).wait()
def __init__(self): super(ContrailVIFDriver, self).__init__() self._agent_alive = False self._agent_connected = False self._port_dict = {} self._protocol = None timer = loopingcall.FixedIntervalLoopingCall(self._keep_alive) timer.start(interval=2)
def add_timer(self, interval, callback, initial_delay=None, *args, **kwargs): pulse = loopingcall.FixedIntervalLoopingCall(callback, *args, **kwargs) pulse.start(interval=interval, initial_delay=initial_delay) self.timers.append(pulse)
def _handoff_recv(self, base_vm_paths, base_hashvalue, handoff_recv_datafile, launch_diskpath, launch_memorypath): # data structure for handoff receiving handoff_ds_recv = handoff.HandoffDataRecv() handoff_ds_recv.save_data(base_vm_paths, base_hashvalue, launch_diskpath, launch_memorypath) handoff_ds_recv.to_file(handoff_recv_datafile) LOG.debug("start handoff recv process") cmd = [ "/usr/local/bin/handoff-server-proc", "-d", "%s" % handoff_recv_datafile ] LOG.debug("subprocess: %s" % cmd) proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, close_fds=True) stdout_buf = StringIO.StringIO() def _wait_for_handoff_recv(print_log=True): """Called at an interval until VM synthesis finishes.""" returncode = proc.poll() if returncode is None: # keep record stdout LOG.debug("waiting for finishing handoff recv") in_ready, _, _ = select.select([proc.stdout], [], []) try: buf = os.read(proc.stdout.fileno(), 1024 * 100) if print_log: LOG.debug(buf) stdout_buf.write(buf) except OSError as e: if e.errno == errno.EAGAIN or e.errno == errno.EWOULDBLOCK: return else: # handoff finishes. Read reamining stdout in_ready, _, _ = select.select([proc.stdout], [], [], 0.1) buf = proc.stdout.read() stdout_buf.write(buf) raise loopingcall.LoopingCallDone() timer = loopingcall.FixedIntervalLoopingCall(_wait_for_handoff_recv) timer.start(interval=0.5).wait() LOG.info("Handoff recv finishes") returncode = proc.poll() if returncode is not 0: msg = "Failed to receive handoff data" raise handoff.HandoffError(msg) # parse output: this will be fixed at cloudlet deamon keyword, disksize, memorysize, disk_overlay_map, memory_overlay_map =\ stdout_buf.getvalue().split("\n")[-1].split("\t") if keyword.lower() != "openstack": raise handoff.HandoffError("Failed to parse returned data") return disksize, memorysize, disk_overlay_map, memory_overlay_map
def _wait_for_task(self, instance_uuid, task_ref): """ Return a Deferred that will give the result of the given task. The task is polled until it completes. """ done = event.Event() loop = loopingcall.FixedIntervalLoopingCall(self._poll_task, instance_uuid, task_ref, done) loop.start(CONF.vmware.task_poll_interval) ret_val = done.wait() loop.stop() return ret_val
def connect_volume(self, connection_info, mount_device): shelf = connection_info['data']['target_shelf'] lun = connection_info['data']['target_lun'] aoedev = 'e%s.%s' % (shelf, lun) aoedevpath = '/dev/etherd/%s' % (aoedev) if os.path.exists(aoedevpath): # NOTE(jbr_): If aoedevpath already exists, revalidate the LUN. self._aoe_revalidate(aoedev) else: # NOTE(jbr_): If aoedevpath does not exist, do a discover. self._aoe_discover() #NOTE(jbr_): Device path is not always present immediately def _wait_for_device_discovery(aoedevpath, mount_device): tries = self.tries if os.path.exists(aoedevpath): raise loopingcall.LoopingCallDone() if self.tries >= CONF.num_aoe_discover_tries: raise exception.NovaException( _("AoE device not found at %s") % (aoedevpath)) LOG.warn( _("AoE volume not yet found at: %(aoedevpath)s. " "Try number: %(tries)s"), { 'aoedevpath': aoedevpath, 'tries': tries }) self._aoe_discover() self.tries = self.tries + 1 self.tries = 0 timer = loopingcall.FixedIntervalLoopingCall( _wait_for_device_discovery, aoedevpath, mount_device) timer.start(interval=2).wait() tries = self.tries if tries != 0: LOG.debug( _("Found AoE device %(aoedevpath)s " "(after %(tries)s rediscover)"), { 'aoedevpath': aoedevpath, 'tries': tries }) conf = super(LibvirtAOEVolumeDriver, self).connect_volume(connection_info, mount_device) conf.source_type = "block" conf.source_path = aoedevpath return conf
def _unprovision(self, ironicclient, instance, node): """This method is called from destroy() to unprovision already provisioned node after required checks. """ try: ironicclient.call("node.set_provision_state", node.uuid, "deleted") except Exception as e: # if the node is already in a deprovisioned state, continue # This should be fixed in Ironic. # TODO(deva): This exception should be added to # python-ironicclient and matched directly, # rather than via __name__. if getattr(e, '__name__', None) != 'InstanceDeployFailure': raise # using a dict because this is modified in the local method data = {'tries': 0} def _wait_for_provision_state(): node = _validate_instance_and_node(ironicclient, instance) if node.provision_state in (ironic_states.NOSTATE, ironic_states.CLEANING, ironic_states.CLEANFAIL, ironic_states.AVAILABLE): # From a user standpoint, the node is unprovisioned. If a node # gets into CLEANFAIL state, it must be fixed in Ironic, but we # can consider the instance unprovisioned. LOG.debug( "Ironic node %(node)s is in state %(state)s, " "instance is now unprovisioned.", dict(node=node.uuid, state=node.provision_state), instance=instance) raise loopingcall.LoopingCallDone() if data['tries'] >= CONF.ironic.api_max_retries: msg = (_("Error destroying the instance on node %(node)s. " "Provision state still '%(state)s'.") % { 'state': node.provision_state, 'node': node.uuid }) LOG.error(msg) raise exception.NovaException(msg) else: data['tries'] += 1 _log_ironic_polling('unprovision', node, instance) # wait for the state transition to finish timer = loopingcall.FixedIntervalLoopingCall(_wait_for_provision_state) timer.start(interval=CONF.ironic.api_retry_interval).wait()
def _wait_for_task(self, task_ref): """Return a Deferred that will give the result of the given task. The task is polled until it completes. """ done = event.Event() loop = loopingcall.FixedIntervalLoopingCall(self._poll_task, task_ref, done) loop.start(CONF.vmware.task_poll_interval) try: ret_val = done.wait() except Exception: raise finally: self._stop_loop(loop) return ret_val
def activate_node(self, context, node, instance): """Wait for PXE deployment to complete.""" locals = {'error': '', 'started': False} def _wait_for_deploy(): """Called at an interval until the deployment completes.""" try: row = db.bm_node_get(context, node['id']) if instance['uuid'] != row.get('instance_uuid'): locals['error'] = _("Node associated with another instance" " while waiting for deploy of %s") raise loopingcall.LoopingCallDone() status = row.get('task_state') if (status == baremetal_states.DEPLOYING and locals['started'] == False): LOG.info( _("PXE deploy started for instance %s") % instance['uuid']) locals['started'] = True elif status in (baremetal_states.DEPLOYDONE, baremetal_states.ACTIVE): LOG.info( _("PXE deploy completed for instance %s") % instance['uuid']) raise loopingcall.LoopingCallDone() elif status == baremetal_states.DEPLOYFAIL: locals['error'] = _("PXE deploy failed for instance %s") except exception.NodeNotFound: locals['error'] = _("Baremetal node deleted while waiting " "for deployment of instance %s") if (CONF.baremetal.pxe_deploy_timeout and timeutils.utcnow() > expiration): locals['error'] = _("Timeout reached while waiting for " "PXE deploy of instance %s") if locals['error']: raise loopingcall.LoopingCallDone() expiration = timeutils.utcnow() + datetime.timedelta( seconds=CONF.baremetal.pxe_deploy_timeout) timer = loopingcall.FixedIntervalLoopingCall(_wait_for_deploy) timer.start(interval=1).wait() if locals['error']: raise exception.InstanceDeployFailure(locals['error'] % instance['uuid'])
def join(self, member_id, group_id, service=None): """Join the given service with it's group.""" msg = _('DB_Driver: join new ServiceGroup member %(member_id)s to ' 'the %(group_id)s group, service = %(service)s') LOG.debug(msg, locals()) if service is None: raise RuntimeError(_('service is a mandatory argument for DB based' ' ServiceGroup driver')) report_interval = service.report_interval if report_interval: pulse = loopingcall.FixedIntervalLoopingCall(self._report_state, service) pulse.start(interval=report_interval, initial_delay=report_interval) return pulse
def _unprovision(self, icli, instance, node): """This method is called from destroy() to unprovision already provisioned node after required checks. """ try: self._retry_if_service_is_unavailable( icli.node.set_provision_state, node.uuid, 'deleted') except MaximumRetriesReached: msg = (_("Error triggering the unprovisioning of the node %s") % node.uuid) LOG.error(msg) raise exception.NovaException(msg) except Exception as e: # if the node is already in a deprovisioned state, continue # This should be fixed in Ironic. # TODO(deva): This exception should be added to # python-ironicclient and matched directly, # rather than via __name__. if getattr(e, '__name__', None) == 'InstanceDeployFailure': pass else: raise def _wait_for_provision_state(): try: node = icli.node.get_by_instance_uuid(instance['uuid']) except ironic_exception.HTTPNotFound: raise exception.InstanceNotFound(instance_id=instance['uuid']) if not node.provision_state: raise loopingcall.LoopingCallDone() if self.tries >= CONF.ironic.api_max_retries: msg = (_("Error destroying the instance on node %(node)s. " "Provision state still '%(state)s'.") % { 'state': node.provision_state, 'node': node.uuid }) LOG.error(msg) raise exception.NovaException(msg) else: self.tries += 1 # wait for the state transition to finish self.tries = 0 timer = loopingcall.FixedIntervalLoopingCall(_wait_for_provision_state) timer.start(interval=CONF.ironic.api_retry_interval).wait()
def _retry_if_service_is_unavailable(self, func, *args): """Rety the request if the API returns 409 (Conflict).""" def _request_api(): try: func(*args) raise loopingcall.LoopingCallDone() except ironic_exception.HTTPServiceUnavailable: pass if self.tries >= CONF.ironic.api_max_retries: raise MaximumRetriesReached() else: self.tries += 1 self.tries = 0 timer = loopingcall.FixedIntervalLoopingCall(_request_api) timer.start(interval=CONF.ironic.api_retry_interval).wait()
def periodic_flavor_sync(ctx, driver, scg_id_list): """ Periodically update the flavors from PowerVC. A default time of 300 seconds is specified for the refresh interval. if the refresh interval is set to 0, then flavors are not refreshed. """ sync_interval = CONF.powervc.flavor_sync_interval if sync_interval is None or sync_interval == 0: return def flavors_sync(driver, scg_id_list): FlavorSync(driver, scg_id_list).synchronize_flavors(ctx) LOG.debug('Flavors synchronization completed') sync_flavors = loopingcall.FixedIntervalLoopingCall( flavors_sync, driver, scg_id_list) sync_flavors.start(interval=sync_interval, initial_delay=sync_interval)
def _unprovision(self, icli, instance, node): """This method is called from destroy() to unprovision already provisioned node after required checks. """ try: icli.call("node.set_provision_state", node.uuid, "deleted") except Exception as e: # if the node is already in a deprovisioned state, continue # This should be fixed in Ironic. # TODO(deva): This exception should be added to # python-ironicclient and matched directly, # rather than via __name__. if getattr(e, '__name__', None) == 'InstanceDeployFailure': pass else: raise # using a dict because this is modified in the local method data = {'tries': 0} def _wait_for_provision_state(): try: node = icli.call("node.get_by_instance_uuid", instance['uuid']) except ironic_exception.NotFound: raise exception.InstanceNotFound(instance_id=instance['uuid']) if not node.provision_state: raise loopingcall.LoopingCallDone() if data['tries'] >= CONF.ironic.api_max_retries: msg = (_("Error destroying the instance on node %(node)s. " "Provision state still '%(state)s'.") % { 'state': node.provision_state, 'node': node.uuid }) LOG.error(msg) raise exception.NovaException(msg) else: data['tries'] += 1 # wait for the state transition to finish timer = loopingcall.FixedIntervalLoopingCall(_wait_for_provision_state) timer.start(interval=CONF.ironic.api_retry_interval).wait()
def _wait_for_image_state(self, ami_id, desired_state): """Timer to wait for the image/snapshot to reach a desired state :params:ami_id: correspoding image id in Amazon :params:desired_state: the desired new state of the image to be in. """ def _wait_for_state(): """Called at an interval until the AMI image is available.""" try: images = self.ec2_conn.get_all_images(image_ids=[ami_id], owners=None, executable_by=None, filters=None, dry_run=None) state = images[0].state # LOG.info("\n\n\nImage id = %s" % ami_id + ", state = %s\n\n\n" % state) if state == desired_state: LOG.info("Image has changed state to %s." % desired_state) raise loopingcall.LoopingCallDone() except boto_exc.EC2ResponseError: pass timer = loopingcall.FixedIntervalLoopingCall(_wait_for_state) timer.start(interval=0.5).wait()
def _power_on(self): """Turn the power to this node ON.""" def _wait_for_power_on(): """Called at an interval until the node's power is on.""" if self.is_power_on(): self.state = baremetal_states.ACTIVE raise loopingcall.LoopingCallDone() if self.retries > CONF.baremetal.ipmi_power_retry: self.state = baremetal_states.ERROR raise loopingcall.LoopingCallDone() try: self.retries += 1 self._exec_ipmitool("power on") except Exception: LOG.exception(_("IPMI power on failed")) self.retries = 0 timer = loopingcall.FixedIntervalLoopingCall(_wait_for_power_on) timer.start(interval=0.5).wait()
def power_off(self, instance, timeout=0, retry_interval=0): """Power off the specified instance. NOTE: Ironic does not support soft-off, so this method ignores timeout and retry_interval parameters. NOTE: Unlike the libvirt driver, this method does not delete and recreate the instance; it preserves local state. :param instance: The instance object. :param timeout: time to wait for node to shutdown. Ignored by this driver. :param retry_interval: How often to signal node while waiting for it to shutdown. Ignored by this driver. """ icli = client_wrapper.IronicClientWrapper() node = _validate_instance_and_node(icli, instance) icli.call("node.set_power_state", node.uuid, 'off') timer = loopingcall.FixedIntervalLoopingCall( self._wait_for_power_state, icli, instance, 'power off') timer.start(interval=CONF.ironic.api_retry_interval).wait()
def _async_reschedule(): # check dest compute service is alive utils.spawn_n(async_check_live) timer = loopingcall.FixedIntervalLoopingCall(_loop_check) timer.start(interval=1).wait() if not alive_dict['alive']: LOG.warn( '%s compute service seems down, revert instance ' 'task state', host_state, instance=instance) instance.task_state = None instance.save() return LOG.info('reschedule instance to host %s', host_state, instance=instance) try: self.compute_rpcapi.sync_reschedule_instance( context, instance=instance, new_pass=None, injected_files=jsonutils.loads(injected_files), image_ref=image_ref, orig_image_ref=orig_image_ref, orig_sys_metadata=None, bdms=bdms, host=host_state, filter_properties=filter_properties) except Exception as e: LOG.error(_LE('reschedule call failed: %s'), e) self.db.instance_update(context, instance.uuid, task_state=None)
def connect_volume(self, connection_info, disk_info): """Attach the volume to instance_name.""" fc_properties = connection_info['data'] mount_device = disk_info["dev"] ports = fc_properties['target_wwn'] wwns = [] # we support a list of wwns or a single wwn if isinstance(ports, list): for wwn in ports: wwns.append(wwn) elif isinstance(ports, str): wwns.append(ports) # We need to look for wwns on every hba # because we don't know ahead of time # where they will show up. hbas = virtutils.get_fc_hbas_info() host_devices = [] for hba in hbas: pci_num = self._get_pci_num(hba) if pci_num is not None: for wwn in wwns: target_wwn = "0x%s" % wwn.lower() host_device = ("/dev/disk/by-path/pci-%s-fc-%s-lun-%s" % (pci_num, target_wwn, fc_properties.get('target_lun', 0))) host_devices.append(host_device) if len(host_devices) == 0: # this is empty because we don't have any FC HBAs msg = _("We are unable to locate any Fibre Channel devices") raise exception.NovaException(msg) # 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, mount_device): 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 >= CONF.num_iscsi_scan_tries: msg = _("Fibre Channel device not found.") raise exception.NovaException(msg) LOG.warn( _("Fibre volume not yet found at: %(mount_device)s. " "Will rescan & retry. Try number: %(tries)s"), { 'mount_device': mount_device, 'tries': tries }) linuxscsi.rescan_hosts(hbas) 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, mount_device) 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 %(mount_device)s " "(after %(tries)s rescans)"), { 'mount_device': mount_device, 'tries': tries }) # see if the new drive is part of a multipath # device. If so, we'll use the multipath device. mdev_info = linuxscsi.find_multipath_device(self.device_name) if mdev_info is not None: LOG.debug( _("Multipath device discovered %(device)s") % {'device': mdev_info['device']}) device_path = mdev_info['device'] connection_info['data']['devices'] = mdev_info['devices'] connection_info['data']['multipath_id'] = mdev_info['id'] else: # we didn't find a multipath device. # so we assume the kernel only sees 1 device device_path = self.host_device device_info = linuxscsi.get_device_info(self.device_name) connection_info['data']['devices'] = [device_info] conf = super(LibvirtFibreChannelVolumeDriver, self).connect_volume(connection_info, disk_info) conf.source_type = "block" conf.source_path = device_path return conf