Beispiel #1
0
 def __init__(self, count):
     self._executor = futurist.GreenThreadPoolExecutor(max_workers=1000)
     self.count = count
     if 'consoleserver_host' in os.environ:
         self.host = os.environ["consoleserver_host"]
     else:
         self.host = 'http://localhost:12429'
Beispiel #2
0
def executor():
    """Return the current futures executor."""
    global _EXECUTOR
    if _EXECUTOR is None:
        _EXECUTOR = futurist.GreenThreadPoolExecutor(
            max_workers=CONF.max_concurrency)
    return _EXECUTOR
Beispiel #3
0
    def init_host(self, admin_context=None):
        """Initialize the agent host.

        :param admin_context: the admin context to pass to periodic tasks.
        :raises: RuntimeError when agent is already running.
        """
        if self._started:
            raise RuntimeError(
                _('Attempt to start an already running '
                  'agent manager'))

        rejection_func = rejection.reject_when_reached(64)
        # CONF.conductor.workers_pool_size)
        self._executor = futurist.GreenThreadPoolExecutor(
            64, check_and_reject=rejection_func)
        # JK max_workers=CONF.conductor.workers_pool_size,
        """Executor for performing tasks async."""

        # Collect driver-specific periodic tasks.
        # Conductor periodic tasks accept context argument,
        LOG.info('Collecting periodic tasks')
        self._periodic_task_callables = []
        self._collect_periodic_tasks(self, (admin_context, ))

        self._periodic_tasks = periodics.PeriodicWorker(
            self._periodic_task_callables,
            executor_factory=periodics.ExistingExecutor(self._executor))

        # Start periodic tasks
        self._periodic_tasks_worker = self._executor.submit(
            self._periodic_tasks.start, allow_empty=True)
        self._periodic_tasks_worker.add_done_callback(
            self._on_periodic_tasks_stop)

        self._started = True
def _parallel_create(func, nodes, total, split_num):
    import eventlet
    eventlet.monkey_patch(os=False)
    import futurist
    from futurist import waiters
    data = []
    i = 0
    per_split = total / split_num
    while i < split_num - 1:
        data.append({'nodes': nodes[i * per_split:(i + 1) * per_split]})
        i += 1
    data.append({'nodes': nodes[i * per_split:]})
    _executor = futurist.GreenThreadPoolExecutor(max_workers=split_num)
    j = 0
    futures = []
    while j < split_num:
        future = _executor.submit(func, data[j])
        futures.append(future)
        j += 1

    done, not_done = waiters.wait_for_all(futures, 3600)
    result = {'nodes': {}}
    for r in done:
        result['nodes'].update(r.result()['nodes'])

    return result
def _parallel_update(func, names, patch, total, split_num):
    import eventlet
    eventlet.monkey_patch(os=False)
    import futurist
    from futurist import waiters
    patch_dicts = []
    patch_dict = {'nodes': [], "patches": patch}
    i = 0
    per_split = total / split_num
    while i < total:
        if i != 0 and i % per_split == 0 and i != split_num * per_split:
            patch_dicts.append(patch_dict)
            patch_dict = {'nodes': [], "patches": patch}

        patch_dict['nodes'].append({'name': names[i]})
        i += 1
    patch_dicts.append(patch_dict)

    _executor = futurist.GreenThreadPoolExecutor(max_workers=split_num)
    futures = []
    for patch_dict in patch_dicts:
        future = _executor.submit(func, patch_dict)
        futures.append(future)

    done, not_done = waiters.wait_for_all(futures, 3600)
    result = {'nodes': {}}
    for r in done:
        result['nodes'].update(r.result()['nodes'])

    return result
Beispiel #6
0
    def list_floatingips(self, context, region=None):
        """
        Get floating ips based on the current context from Neutron
        """
        endpoints = self._endpoints(
            service_catalog=context.service_catalog,
            service_type='network',
            endpoint_type=CONF['network_api:neutron'].endpoint_type,
            config_section='network_api:neutron',
            region=region
        )

        floating_ips = []
        with futurist.GreenThreadPoolExecutor(max_workers=5) as executor:
            executors = [
                executor.submit(
                    self._get_floating_ips,
                    context,
                    endpoint,
                    region,
                    project_id=context.project_id
                ) for endpoint, region in endpoints
            ]
            for future in concurrent.futures.as_completed(executors):
                try:
                    floating_ips.extend(future.result())
                except Exception as e:
                    raise exceptions.NeutronCommunicationFailure(e)

        return floating_ips
Beispiel #7
0
def get_pool(size):
    import futurist

    if eventletutils.is_monkey_patched('thread'):
        return futurist.GreenThreadPoolExecutor(size)

    return futurist.ThreadPoolExecutor(size)
 def test_submit_passes_through(self):
     self.useFixture(fixtures.SynchronousThreadPoolExecutorFixture())
     tester = mock.MagicMock()
     executor = futurist.GreenThreadPoolExecutor()
     future = executor.submit(tester.function, 'foo', bar='bar')
     tester.function.assert_called_once_with('foo', bar='bar')
     result = future.result()
     self.assertEqual(tester.function.return_value, result)
Beispiel #9
0
 def _executor(self):
     if CONF.taskflow_executor.engine_mode != 'parallel':
         yield None
     else:
         max_workers = CONF.taskflow_executor.max_workers
         try:
             yield futurist.GreenThreadPoolExecutor(max_workers=max_workers)
         except RuntimeError:
             yield futurist.ThreadPoolExecutor(max_workers=max_workers)
Beispiel #10
0
def default_executor():
    thread_count = 5
    try:
        thread_count = CONF['service:worker'].threads
    except Exception:
        pass

    # return futures.ThreadPoolExecutor(thread_count)
    return futurist.GreenThreadPoolExecutor(thread_count)
 def _make_engine(self, flow, flow_detail=None, executor=None):
     if executor is None:
         executor = futurist.GreenThreadPoolExecutor()
         self.addCleanup(executor.shutdown)
     return taskflow.engines.load(flow,
                                  flow_detail=flow_detail,
                                  backend=self.backend,
                                  engine='parallel',
                                  executor=executor)
Beispiel #12
0
def default_executor():
    thread_count = 5
    try:
        thread_count = CONF['service:worker'].threads
    except Exception:
        pass

    # TODO(mugsie): if (when) we move away from eventlet this may have to
    # revert back to ThreadPoolExecutor - this is changing due to
    # https://bugs.launchpad.net/bugs/1782647 (eventlet + py37 issues)
    return futurist.GreenThreadPoolExecutor(thread_count)
Beispiel #13
0
 def _fetch_an_executor():
     if CONF.taskflow_executor.engine_mode != 'parallel':
         return None
     else:
         max_workers = CONF.taskflow_executor.max_workers
         try:
             return futurist.GreenThreadPoolExecutor(
                 max_workers=max_workers)
         except RuntimeError:
             # NOTE(harlowja): I guess eventlet isn't being made
             # useable, well just use native threads then (or try to).
             return futurist.ThreadPoolExecutor(max_workers=max_workers)
Beispiel #14
0
    def execute(self, actions):
        try:
            flow = gf.Flow("watcher_flow")
            for a in actions:
                task = TaskFlowActionContainer(a, self)
                flow.add(task)
            executor = futurist.GreenThreadPoolExecutor(max_workers=100)
            e = engines.load(flow, engine='parallel', executor=executor)
            e.run()

        except Exception as e:
            raise exception.WorkflowExecutionException(error=e)
        finally:
            executor.shutdown()
def main():
    if len(sys.argv) == 2:
        tbl = []
        with open(sys.argv[1], 'rb') as fh:
            reader = csv.reader(fh)
            for row in reader:
                tbl.append([float(r) if r else 0.0 for r in row])
    else:
        # Make some random table out of thin air...
        tbl = []
        cols = random.randint(1, 100)
        rows = random.randint(1, 100)
        for _i in compat_range(0, rows):
            row = []
            for _j in compat_range(0, cols):
                row.append(random.random())
            tbl.append(row)

    # Generate the work to be done.
    f = make_flow(tbl)

    # Now run it (using the specified executor)...
    try:
        executor = futurist.GreenThreadPoolExecutor(max_workers=5)
    except RuntimeError:
        # No eventlet currently active, use real threads instead.
        executor = futurist.ThreadPoolExecutor(max_workers=5)
    try:
        e = engines.load(f, engine='parallel', executor=executor)
        for st in e.run_iter():
            print(st)
    finally:
        executor.shutdown()

    # Find the old rows and put them into place...
    #
    # TODO(harlowja): probably easier just to sort instead of search...
    computed_tbl = []
    for i in compat_range(0, len(tbl)):
        for t in f:
            if t.index == i:
                computed_tbl.append(e.storage.get(t.name))

    # Do some basic validation (which causes the return code of this process
    # to be different if things were not as expected...)
    if len(computed_tbl) != len(tbl):
        return 1
    else:
        return 0
Beispiel #16
0
 def get_engine(self, flow, **kwargs):
     if flow is None:
         LOG.error(_LE("Flow is None, build it first"))
         return
     executor = kwargs.get('executor', None)
     engine = kwargs.get('engine', None)
     store = kwargs.get('store', None)
     if not executor:
         executor = futurist.GreenThreadPoolExecutor()
     if not engine:
         engine = 'parallel'
     flow_engine = engines.load(flow,
                                executor=executor,
                                engine=engine,
                                store=store)
     return flow_engine
Beispiel #17
0
 def get_engine(self, flow, **kwargs):
     if flow is None:
         LOG.error("The flow is None, build it first")
         raise exception.InvalidTaskFlowObject(reason=_("The flow is None"))
     executor = kwargs.get('executor', None)
     engine = kwargs.get('engine', None)
     store = kwargs.get('store', None)
     if not executor:
         executor = futurist.GreenThreadPoolExecutor()
     if not engine:
         engine = 'parallel'
     flow_engine = engines.load(flow,
                                executor=executor,
                                engine=engine,
                                store=store)
     return flow_engine
Beispiel #18
0
    def __init__(self, operation_manager, thread_count=None):
        super(ThreadPoolExecutor, self).__init__(operation_manager)

        if thread_count is None:
            thread_count = CONF.thread_count

        self._pool = futurist.GreenThreadPoolExecutor(thread_count)
        self._operation_to_run = defaultdict(int)
        self._operation_to_cancel = set()
        self._lock = RLock()

        self._check_functions = {
            self._CHECK_ITEMS['is_waiting']:
            lambda op_id: (op_id in self._operation_to_run),
            self._CHECK_ITEMS['is_canceled']:
            lambda op_id: (op_id in self._operation_to_cancel),
        }
Beispiel #19
0
def main():
    # the behavior is specific to GreenThreadPoolExecutor
    threadpool = futurist.GreenThreadPoolExecutor(max_workers=4)
    rrwlock = ReentrantReadWriteLock()
    futures = []
    futures.append(threadpool.submit(get_write, rrwlock))
    futures.append(threadpool.submit(get_read, rrwlock))

    # Get the results and verify only one of the calls succeeded
    # assert that the other call is still pending
    # this call will block indefinitely, it should not block state of threads
    # in threadpool should not be able to cause wait_for_any to block
    # indefinitely.
    results = waiters.wait_for_any(futures)

    # these statements will never be reached
    print(results[0].pop().result == True)
    print(len(results[1]))
Beispiel #20
0
 def test_green_executor_creation(self):
     with futurist.GreenThreadPoolExecutor(1) as e:
         eng = self._create_engine(executor=e)
         self.assertIsInstance(eng._task_executor,
                               executor.ParallelThreadTaskExecutor)
Beispiel #21
0
with eu.get_backend() as backend:

    # Try to find a previously passed in tracking id...
    try:
        book_id, flow_id = sys.argv[2].split("+", 1)
        if not uuidutils.is_uuid_like(book_id):
            book_id = None
        if not uuidutils.is_uuid_like(flow_id):
            flow_id = None
    except (IndexError, ValueError):
        book_id = None
        flow_id = None

    # Set up how we want our engine to run, serial, parallel...
    try:
        executor = futurist.GreenThreadPoolExecutor(max_workers=5)
    except RuntimeError:
        # No eventlet installed, just let the default be used instead.
        executor = None

    # Create/fetch a logbook that will track the workflows work.
    book = None
    flow_detail = None
    if all([book_id, flow_id]):
        # Try to find in a prior logbook and flow detail...
        with contextlib.closing(backend.get_connection()) as conn:
            try:
                book = conn.get_logbook(book_id)
                flow_detail = book.find(flow_id)
            except exc.NotFound:
                pass
Beispiel #22
0
 def __init__(self, url, method, count):
     self._executor = futurist.GreenThreadPoolExecutor(max_workers=1000)
     self.url = url
     self.method = method
     self.count = count
Beispiel #23
0
 def __init__(self):
     self.amount_workers = CONF.watcher_decision_engine.max_general_workers
     self._threadpool = futurist.GreenThreadPoolExecutor(
         max_workers=self.amount_workers)
Beispiel #24
0
 def __init__(self, applier_manager):
     self.applier_manager = applier_manager
     workers = CONF.watcher_applier.workers
     self.executor = futurist.GreenThreadPoolExecutor(max_workers=workers)
    def init_host(self, admin_context=None):
        """Initialize the conductor host.

        :param admin_context: the admin context to pass to periodic tasks.
        :raises: RuntimeError when conductor is already running.
        :raises: NoDriversLoaded when no drivers are enabled on the conductor.
        :raises: DriverNotFound if a driver is enabled that does not exist.
        :raises: DriverLoadError if an enabled driver cannot be loaded.
        :raises: DriverNameConflict if a classic driver and a dynamic driver
                 are both enabled and have the same name.
        :raises: ConfigInvalid if required config options for connection with
                 radosgw are missing while storing config drive.
        """
        if self._started:
            raise RuntimeError(
                _('Attempt to start an already running '
                  'conductor manager'))
        self._shutdown = False

        self.dbapi = dbapi.get_instance()

        self._keepalive_evt = threading.Event()
        """Event for the keepalive thread."""

        # TODO(dtantsur): make the threshold configurable?
        rejection_func = rejection.reject_when_reached(
            CONF.conductor.workers_pool_size)
        self._executor = futurist.GreenThreadPoolExecutor(
            max_workers=CONF.conductor.workers_pool_size,
            check_and_reject=rejection_func)
        """Executor for performing tasks async."""

        self.ring_manager = hash_ring.HashRingManager()
        """Consistent hash ring which maps drivers to conductors."""

        _check_enabled_interfaces()

        # NOTE(deva): these calls may raise DriverLoadError or DriverNotFound
        # NOTE(vdrok): Instantiate network and storage interface factory on
        # startup so that all the interfaces are loaded at the very
        # beginning, and failures prevent the conductor from starting.
        drivers = driver_factory.drivers()
        hardware_types = driver_factory.hardware_types()
        driver_factory.NetworkInterfaceFactory()
        driver_factory.StorageInterfaceFactory()

        # NOTE(jroll) this is passed to the dbapi, which requires a list, not
        # a generator (which keys() returns in py3)
        driver_names = list(drivers)
        hardware_type_names = list(hardware_types)

        # check that at least one driver is loaded, whether classic or dynamic
        if not driver_names and not hardware_type_names:
            msg = ("Conductor %s cannot be started because no drivers "
                   "were loaded. This could be because no classic drivers "
                   "were specified in the 'enabled_drivers' config option "
                   "and no dynamic drivers were specified in the "
                   "'enabled_hardware_types' config option.")
            LOG.error(msg, self.host)
            raise exception.NoDriversLoaded(conductor=self.host)

        # check for name clashes between classic and dynamic drivers
        name_clashes = set(driver_names).intersection(hardware_type_names)
        if name_clashes:
            name_clashes = ', '.join(name_clashes)
            msg = ("Conductor %(host)s cannot be started because there is "
                   "one or more name conflicts between classic drivers and "
                   "dynamic drivers (%(names)s). Check any external driver "
                   "plugins and the 'enabled_drivers' and "
                   "'enabled_hardware_types' config options.")
            LOG.error(msg, {'host': self.host, 'names': name_clashes})
            raise exception.DriverNameConflict(names=name_clashes)

        # Collect driver-specific periodic tasks.
        # Conductor periodic tasks accept context argument, driver periodic
        # tasks accept this manager and context. We have to ensure that the
        # same driver interface class is not traversed twice, otherwise
        # we'll have several instances of the same task.
        LOG.debug('Collecting periodic tasks')
        self._periodic_task_callables = []
        periodic_task_classes = set()
        self._collect_periodic_tasks(self, (admin_context, ))
        for driver_obj in drivers.values():
            for iface_name in driver_obj.all_interfaces:
                iface = getattr(driver_obj, iface_name, None)
                if iface and iface.__class__ not in periodic_task_classes:
                    self._collect_periodic_tasks(iface, (self, admin_context))
                    periodic_task_classes.add(iface.__class__)

        if (len(self._periodic_task_callables) >
                CONF.conductor.workers_pool_size):
            LOG.warning(
                'This conductor has %(tasks)d periodic tasks '
                'enabled, but only %(workers)d task workers '
                'allowed by [conductor]workers_pool_size option', {
                    'tasks': len(self._periodic_task_callables),
                    'workers': CONF.conductor.workers_pool_size
                })

        self._periodic_tasks = periodics.PeriodicWorker(
            self._periodic_task_callables,
            executor_factory=periodics.ExistingExecutor(self._executor))

        # Check for required config options if object_store_endpoint_type is
        # radosgw
        if (CONF.deploy.configdrive_use_object_store
                and CONF.deploy.object_store_endpoint_type == "radosgw"):
            if (None in (CONF.swift.auth_url, CONF.swift.username,
                         CONF.swift.password)):
                msg = _("Parameters missing to make a connection with "
                        "radosgw. Ensure that [swift]/auth_url, "
                        "[swift]/username, and [swift]/password are all "
                        "configured.")
                raise exception.ConfigInvalid(msg)

        # clear all target_power_state with locks by this conductor
        self.dbapi.clear_node_target_power_state(self.host)
        # clear all locks held by this conductor before registering
        self.dbapi.clear_node_reservations_for_conductor(self.host)
        try:
            # Register this conductor with the cluster
            self.conductor = objects.Conductor.register(
                admin_context, self.host, driver_names)
        except exception.ConductorAlreadyRegistered:
            # This conductor was already registered and did not shut down
            # properly, so log a warning and update the record.
            LOG.warning(
                "A conductor with hostname %(hostname)s was "
                "previously registered. Updating registration",
                {'hostname': self.host})
            self.conductor = objects.Conductor.register(admin_context,
                                                        self.host,
                                                        driver_names,
                                                        update_existing=True)

        # register hardware types and interfaces supported by this conductor
        # and validate them against other conductors
        try:
            self._register_and_validate_hardware_interfaces(hardware_types)
        except (exception.DriverLoadError, exception.DriverNotFound,
                exception.ConductorHardwareInterfacesAlreadyRegistered,
                exception.InterfaceNotFoundInEntrypoint,
                exception.NoValidDefaultForInterface) as e:
            with excutils.save_and_reraise_exception():
                LOG.error('Failed to register hardware types. %s', e)
                self.del_host()

        # Start periodic tasks
        self._periodic_tasks_worker = self._executor.submit(
            self._periodic_tasks.start, allow_empty=True)
        self._periodic_tasks_worker.add_done_callback(
            self._on_periodic_tasks_stop)

        # NOTE(lucasagomes): If the conductor server dies abruptly
        # mid deployment (OMM Killer, power outage, etc...) we
        # can not resume the deployment even if the conductor
        # comes back online. Cleaning the reservation of the nodes
        # (dbapi.clear_node_reservations_for_conductor) is not enough to
        # unstick it, so let's gracefully fail the deployment so the node
        # can go through the steps (deleting & cleaning) to make itself
        # available again.
        filters = {'reserved': False, 'provision_state': states.DEPLOYING}
        last_error = (_("The deployment can't be resumed by conductor "
                        "%s. Moving to fail state.") % self.host)
        self._fail_if_in_state(ironic_context.get_admin_context(),
                               filters,
                               states.DEPLOYING,
                               'provision_updated_at',
                               last_error=last_error)

        # Start consoles if it set enabled in a greenthread.
        try:
            self._spawn_worker(self._start_consoles,
                               ironic_context.get_admin_context())
        except exception.NoFreeConductorWorker:
            LOG.warning('Failed to start worker for restarting consoles.')

        # Spawn a dedicated greenthread for the keepalive
        try:
            self._spawn_worker(self._conductor_service_record_keepalive)
            LOG.info(
                'Successfully started conductor with hostname '
                '%(hostname)s.', {'hostname': self.host})
        except exception.NoFreeConductorWorker:
            with excutils.save_and_reraise_exception():
                LOG.critical('Failed to start keepalive')
                self.del_host()

        self._started = True
Beispiel #26
0
 def _create_executor(self, max_workers=None):
     if max_workers is None:
         max_workers = self.DEFAULT_WORKERS
     return futurist.GreenThreadPoolExecutor(max_workers=max_workers)
    world_chorus.add(PrinterTask("%s@world" % name,
                                 inject={'output': world}))

# The composition starts with the conductor and then runs in sequence with
# the chorus running in parallel, but no matter what the 'hello' chorus must
# always run before the 'world' chorus (otherwise the world will fall apart).
song.add(PrinterTask("conductor@begin",
                     show_name=False, inject={'output': "*ding*"}),
         hi_chorus,
         world_chorus,
         PrinterTask("conductor@end",
                     show_name=False, inject={'output': "*dong*"}))

# Run in parallel using eventlet green threads...
try:
    executor = futurist.GreenThreadPoolExecutor()
except RuntimeError:
    # No eventlet currently active, skip running with it...
    pass
else:
    print("-- Running in parallel using eventlet --")
    with executor:
        e = engines.load(song, executor=executor, engine='parallel')
        e.run()


# Run in parallel using real threads...
with futurist.ThreadPoolExecutor(max_workers=1) as executor:
    print("-- Running in parallel using threads --")
    e = engines.load(song, executor=executor, engine='parallel')
    e.run()
Beispiel #28
0
def executor():
    global _executor
    if not _executor:
        _executor = futurist.GreenThreadPoolExecutor(max_workers=10)
    return _executor
Beispiel #29
0
    def init_host(self, admin_context=None):
        """Initialize the conductor host.

        :param admin_context: the admin context to pass to periodic tasks.
        :raises: RuntimeError when conductor is already running.
        :raises: NoDriversLoaded when no drivers are enabled on the conductor.
        :raises: DriverNotFound if a driver is enabled that does not exist.
        :raises: DriverLoadError if an enabled driver cannot be loaded.
        :raises: DriverNameConflict if a classic driver and a dynamic driver
                 are both enabled and have the same name.
        """
        if self._started:
            raise RuntimeError(
                _('Attempt to start an already running '
                  'conductor manager'))
        self._shutdown = False

        self.dbapi = dbapi.get_instance()

        self._keepalive_evt = threading.Event()
        """Event for the keepalive thread."""

        # TODO(dtantsur): make the threshold configurable?
        rejection_func = rejection.reject_when_reached(
            CONF.conductor.workers_pool_size)
        self._executor = futurist.GreenThreadPoolExecutor(
            max_workers=CONF.conductor.workers_pool_size,
            check_and_reject=rejection_func)
        """Executor for performing tasks async."""

        # TODO(jroll) delete the use_groups argument and use the default
        # in Stein.
        self.ring_manager = hash_ring.HashRingManager(
            use_groups=self._use_groups())
        """Consistent hash ring which maps drivers to conductors."""

        _check_enabled_interfaces()

        # NOTE(deva): these calls may raise DriverLoadError or DriverNotFound
        # NOTE(vdrok): Instantiate network and storage interface factory on
        # startup so that all the interfaces are loaded at the very
        # beginning, and failures prevent the conductor from starting.
        hardware_types = driver_factory.hardware_types()
        driver_factory.NetworkInterfaceFactory()
        driver_factory.StorageInterfaceFactory()

        # NOTE(jroll) this is passed to the dbapi, which requires a list, not
        # a generator (which keys() returns in py3)
        hardware_type_names = list(hardware_types)

        # check that at least one driver is loaded, whether classic or dynamic
        if not hardware_type_names:
            msg = ("Conductor %s cannot be started because no hardware types "
                   "were specified in the 'enabled_hardware_types' config "
                   "option.")
            LOG.error(msg, self.host)
            raise exception.NoDriversLoaded(conductor=self.host)

        self._collect_periodic_tasks(admin_context)

        # clear all target_power_state with locks by this conductor
        self.dbapi.clear_node_target_power_state(self.host)
        # clear all locks held by this conductor before registering
        self.dbapi.clear_node_reservations_for_conductor(self.host)
        try:
            # Register this conductor with the cluster
            self.conductor = objects.Conductor.register(
                admin_context, self.host, hardware_type_names,
                CONF.conductor.conductor_group)
        except exception.ConductorAlreadyRegistered:
            # This conductor was already registered and did not shut down
            # properly, so log a warning and update the record.
            LOG.warning(
                "A conductor with hostname %(hostname)s was "
                "previously registered. Updating registration",
                {'hostname': self.host})
            self.conductor = objects.Conductor.register(
                admin_context,
                self.host,
                hardware_type_names,
                CONF.conductor.conductor_group,
                update_existing=True)

        # register hardware types and interfaces supported by this conductor
        # and validate them against other conductors
        try:
            self._register_and_validate_hardware_interfaces(hardware_types)
        except (exception.DriverLoadError, exception.DriverNotFound,
                exception.ConductorHardwareInterfacesAlreadyRegistered,
                exception.InterfaceNotFoundInEntrypoint,
                exception.NoValidDefaultForInterface) as e:
            with excutils.save_and_reraise_exception():
                LOG.error('Failed to register hardware types. %s', e)
                self.del_host()

        # Start periodic tasks
        self._periodic_tasks_worker = self._executor.submit(
            self._periodic_tasks.start, allow_empty=True)
        self._periodic_tasks_worker.add_done_callback(
            self._on_periodic_tasks_stop)

        for state in states.STUCK_STATES_TREATED_AS_FAIL:
            self._fail_transient_state(
                state,
                _("The %(state)s state can't be resumed by conductor "
                  "%(host)s. Moving to fail state.") % {
                      'state': state,
                      'host': self.host
                  })

        # Start consoles if it set enabled in a greenthread.
        try:
            self._spawn_worker(self._start_consoles,
                               ironic_context.get_admin_context())
        except exception.NoFreeConductorWorker:
            LOG.warning('Failed to start worker for restarting consoles.')

        # Spawn a dedicated greenthread for the keepalive
        try:
            self._spawn_worker(self._conductor_service_record_keepalive)
            LOG.info(
                'Successfully started conductor with hostname '
                '%(hostname)s.', {'hostname': self.host})
        except exception.NoFreeConductorWorker:
            with excutils.save_and_reraise_exception():
                LOG.critical('Failed to start keepalive')
                self.del_host()

        # Resume allocations that started before the restart.
        try:
            self._spawn_worker(self._resume_allocations,
                               ironic_context.get_admin_context())
        except exception.NoFreeConductorWorker:
            LOG.warning('Failed to start worker for resuming allocations.')

        if CONF.conductor.enable_mdns:
            self._publish_endpoint()

        self._started = True
Beispiel #30
0
    def init_host(self, admin_context=None):
        """Initialize the conductor host.

        :param admin_context: the admin context to pass to periodic tasks.
        :raises: RuntimeError when conductor is already running.
        :raises: NoDriversLoaded when no drivers are enabled on the conductor.
        :raises: DriverNotFound if a driver is enabled that does not exist.
        :raises: DriverLoadError if an enabled driver cannot be loaded.
        """
        if self._started:
            raise RuntimeError(
                _('Attempt to start an already running '
                  'conductor manager'))

        self.dbapi = dbapi.get_instance()

        self._keepalive_evt = threading.Event()
        """Event for the keepalive thread."""

        # TODO(dtantsur): make the threshold configurable?
        rejection_func = rejection.reject_when_reached(
            CONF.conductor.workers_pool_size)
        self._executor = futurist.GreenThreadPoolExecutor(
            max_workers=CONF.conductor.workers_pool_size,
            check_and_reject=rejection_func)
        """Executor for performing tasks async."""

        self.ring_manager = hash.HashRingManager()
        """Consistent hash ring which maps drivers to conductors."""

        # NOTE(deva): these calls may raise DriverLoadError or DriverNotFound
        # NOTE(vdrok): Instantiate network and storage interface factory on
        # startup so that all the interfaces are loaded at the very
        # beginning, and failures prevent the conductor from starting.
        drivers = driver_factory.drivers()
        driver_factory.NetworkInterfaceFactory()
        driver_factory.StorageInterfaceFactory()
        if not drivers:
            msg = _LE("Conductor %s cannot be started because no drivers "
                      "were loaded.  This could be because no drivers were "
                      "specified in 'enabled_drivers' config option.")
            LOG.error(msg, self.host)
            raise exception.NoDriversLoaded(conductor=self.host)

        # NOTE(jroll) this is passed to the dbapi, which requires a list, not
        # a generator (which keys() returns in py3)
        driver_names = list(drivers)

        # Collect driver-specific periodic tasks.
        # Conductor periodic tasks accept context argument, driver periodic
        # tasks accept this manager and context. We have to ensure that the
        # same driver interface class is not traversed twice, otherwise
        # we'll have several instances of the same task.
        LOG.debug('Collecting periodic tasks')
        self._periodic_task_callables = []
        periodic_task_classes = set()
        self._collect_periodic_tasks(self, (admin_context, ))
        for driver_obj in drivers.values():
            # TODO(dtantsur): collecting tasks from driver objects is
            # deprecated and should be removed in Ocata.
            self._collect_periodic_tasks(driver_obj, (self, admin_context))
            for iface_name in driver_obj.all_interfaces:
                iface = getattr(driver_obj, iface_name, None)
                if iface and iface.__class__ not in periodic_task_classes:
                    self._collect_periodic_tasks(iface, (self, admin_context))
                    periodic_task_classes.add(iface.__class__)

        if (len(self._periodic_task_callables) >
                CONF.conductor.workers_pool_size):
            LOG.warning(
                _LW('This conductor has %(tasks)d periodic tasks '
                    'enabled, but only %(workers)d task workers '
                    'allowed by [conductor]workers_pool_size option'), {
                        'tasks': len(self._periodic_task_callables),
                        'workers': CONF.conductor.workers_pool_size
                    })

        self._periodic_tasks = periodics.PeriodicWorker(
            self._periodic_task_callables,
            executor_factory=periodics.ExistingExecutor(self._executor))

        # clear all target_power_state with locks by this conductor
        self.dbapi.clear_node_target_power_state(self.host)
        # clear all locks held by this conductor before registering
        self.dbapi.clear_node_reservations_for_conductor(self.host)
        try:
            # Register this conductor with the cluster
            self.conductor = objects.Conductor.register(
                admin_context, self.host, driver_names)
        except exception.ConductorAlreadyRegistered:
            # This conductor was already registered and did not shut down
            # properly, so log a warning and update the record.
            LOG.warning(
                _LW("A conductor with hostname %(hostname)s "
                    "was previously registered. Updating registration"),
                {'hostname': self.host})
            self.conductor = objects.Conductor.register(admin_context,
                                                        self.host,
                                                        driver_names,
                                                        update_existing=True)

        # Start periodic tasks
        self._periodic_tasks_worker = self._executor.submit(
            self._periodic_tasks.start, allow_empty=True)
        self._periodic_tasks_worker.add_done_callback(
            self._on_periodic_tasks_stop)

        # NOTE(lucasagomes): If the conductor server dies abruptly
        # mid deployment (OMM Killer, power outage, etc...) we
        # can not resume the deployment even if the conductor
        # comes back online. Cleaning the reservation of the nodes
        # (dbapi.clear_node_reservations_for_conductor) is not enough to
        # unstick it, so let's gracefully fail the deployment so the node
        # can go through the steps (deleting & cleaning) to make itself
        # available again.
        filters = {'reserved': False, 'provision_state': states.DEPLOYING}
        last_error = (_("The deployment can't be resumed by conductor "
                        "%s. Moving to fail state.") % self.host)
        self._fail_if_in_state(ironic_context.get_admin_context(),
                               filters,
                               states.DEPLOYING,
                               'provision_updated_at',
                               last_error=last_error)

        # Start consoles if it set enabled in a greenthread.
        try:
            self._spawn_worker(self._start_consoles,
                               ironic_context.get_admin_context())
        except exception.NoFreeConductorWorker:
            LOG.warning(_LW('Failed to start worker for restarting consoles.'))

        # Spawn a dedicated greenthread for the keepalive
        try:
            self._spawn_worker(self._conductor_service_record_keepalive)
            LOG.info(
                _LI('Successfully started conductor with hostname '
                    '%(hostname)s.'), {'hostname': self.host})
        except exception.NoFreeConductorWorker:
            with excutils.save_and_reraise_exception():
                LOG.critical(_LC('Failed to start keepalive'))
                self.del_host()

        self._started = True