Beispiel #1
0
def mock_the_extension_manager(driver="fake", namespace="ironic.drivers"):
    """Get a fake stevedore NameDispatchExtensionManager instance.

    :param namespace: A string representing the namespace over which to
                      search for entrypoints.
    :returns mock_ext_mgr: A DriverFactory instance that has been faked.
    :returns mock_ext: A real plugin loaded by mock_ext_mgr in the specified
                       namespace.

    """
    entry_point = None
    for ep in list(pkg_resources.iter_entry_points(namespace)):
        s = "%s" % ep
        if driver == s[:s.index(' =')]:
            entry_point = ep
            break

    # NOTE(lucasagomes): Initialize the _extension_manager before
    #                    instantiaing a DriverFactory class to avoid
    #                    a real NameDispatchExtensionManager to be created
    #                    with the real namespace.
    driver_factory.DriverFactory._extension_manager = (
        dispatch.NameDispatchExtensionManager('ironic.no-such-namespace',
                                              lambda x: True))
    mock_ext_mgr = driver_factory.DriverFactory()
    mock_ext = mock_ext_mgr._extension_manager._load_one_plugin(
        entry_point, True, [], {}, False)
    mock_ext_mgr._extension_manager.extensions = [mock_ext]
    mock_ext_mgr._extension_manager.by_name = dict(
        (e.name, e) for e in [mock_ext])

    return (mock_ext_mgr, mock_ext)
    def test_start_registers_driver_specific_tasks(self, get_mock):
        init_names = ['fake1']
        self.config(enabled_drivers=init_names)

        class TestInterface(object):
            @periodics.periodic(spacing=100500)
            def iface(self):
                pass

        class Driver(object):
            core_interfaces = []
            standard_interfaces = ['iface']
            all_interfaces = core_interfaces + standard_interfaces

            iface = TestInterface()

            @periodics.periodic(spacing=42)
            def task(self, context):
                pass

        obj = Driver()
        get_mock.return_value = mock.Mock(obj=obj)

        with mock.patch.object(
                driver_factory.DriverFactory()._extension_manager,
                'names') as mock_names:
            mock_names.return_value = init_names
            self._start_service(start_periodic_tasks=True)

        tasks = {c[0] for c in self.service._periodic_task_callables}
        for t in (obj.task, obj.iface.iface):
            self.assertTrue(periodics.is_periodic(t))
            self.assertIn(t, tasks)
Beispiel #3
0
    def test_start_registers_driver_names(self, net_factory,
                                          storage_factory):
        init_names = ['fake1', 'fake2']
        restart_names = ['fake3', 'fake4']

        df = driver_factory.DriverFactory()
        with mock.patch.object(df._extension_manager, 'names') as mock_names:
            # verify driver names are registered
            self.config(enabled_drivers=init_names)
            mock_names.return_value = init_names
            self._start_service()
            res = objects.Conductor.get_by_hostname(self.context,
                                                    self.hostname)
            self.assertEqual(init_names, res['drivers'])
            self._stop_service()

            # verify that restart registers new driver names
            self.config(enabled_drivers=restart_names)
            mock_names.return_value = restart_names
            self._start_service()
            res = objects.Conductor.get_by_hostname(self.context,
                                                    self.hostname)
            self.assertEqual(restart_names, res['drivers'])
        self.assertEqual(2, net_factory.call_count)
        self.assertEqual(2, storage_factory.call_count)
Beispiel #4
0
    def start(self):
        super(ConductorManager, self).start()
        self.dbapi = dbapi.get_instance()

        # create a DriverFactory instance, which initializes the stevedore
        # extension manager, when the service starts.
        # TODO(deva): Enable re-loading of the DriverFactory to load new
        #             extensions without restarting the whole service.
        df = driver_factory.DriverFactory()
        self.drivers = df.names
        """List of driver names which this conductor supports."""

        try:
            self.dbapi.register_conductor({
                'hostname': self.host,
                'drivers': self.drivers
            })
        except exception.ConductorAlreadyRegistered:
            LOG.warn(
                _("A conductor with hostname %(hostname)s "
                  "was previously registered. Updating registration") %
                {'hostname': self.host})
            self.dbapi.unregister_conductor(self.host)
            self.dbapi.register_conductor({
                'hostname': self.host,
                'drivers': self.drivers
            })

        self.driver_rings = self._get_current_driver_rings()
        """Consistent hash ring which maps drivers to conductors."""

        self._worker_pool = greenpool.GreenPool(size=CONF.rpc_thread_pool_size)
        """GreenPool of background workers for performing tasks async."""
Beispiel #5
0
    def init_host(self):
        self.dbapi = dbapi.get_instance()

        self.driver_factory = driver_factory.DriverFactory()
        self.drivers = self.driver_factory.names
        """List of driver names which this conductor supports."""

        try:
            self.dbapi.register_conductor({'hostname': self.host,
                                           'drivers': self.drivers})
        except exception.ConductorAlreadyRegistered:
            LOG.warn(_("A conductor with hostname %(hostname)s "
                       "was previously registered. Updating registration")
                       % {'hostname': self.host})
            self.dbapi.unregister_conductor(self.host)
            self.dbapi.register_conductor({'hostname': self.host,
                                           'drivers': self.drivers})

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

        self._worker_pool = greenpool.GreenPool(
                                size=CONF.conductor.workers_pool_size)
        """GreenPool of background workers for performing tasks async."""

        # Spawn a dedicated greenthread for the keepalive
        try:
            self._keepalive_evt = threading.Event()
            self._spawn_worker(self._conductor_service_record_keepalive)
        except exception.NoFreeConductorWorker:
            with excutils.save_and_reraise_exception():
                LOG.critical(_('Failed to start keepalive'))
                self.del_host()
Beispiel #6
0
    def test_start_registers_driver_names(self):
        init_names = ['fake1', 'fake2']
        restart_names = ['fake3', 'fake4']

        df = driver_factory.DriverFactory()
        with mock.patch.object(df._extension_manager, 'names') as mock_names:
            # verify driver names are registered
            mock_names.return_value = init_names
            self.service.start()
            res = self.dbapi.get_conductor('test-host')
            self.assertEqual(res['drivers'], init_names)

            # verify that restart registers new driver names
            mock_names.return_value = restart_names
            self.service.start()
            res = self.dbapi.get_conductor('test-host')
            self.assertEqual(res['drivers'], restart_names)
Beispiel #7
0
    def test_start_registers_driver_specific_tasks(self, get_mock):
        init_names = ['fake1']
        expected_name = 'ironic.tests.unit.conductor.test_base_manager.task'
        expected_name2 = 'ironic.tests.unit.conductor.test_base_manager.iface'
        self.config(enabled_drivers=init_names)

        class TestInterface(object):
            @drivers_base.driver_periodic_task(spacing=100500)
            def iface(self):
                pass

        class Driver(object):
            core_interfaces = []
            standard_interfaces = ['iface']

            iface = TestInterface()

            @drivers_base.driver_periodic_task(spacing=42)
            def task(self, context):
                pass

        obj = Driver()
        self.assertTrue(obj.task._periodic_enabled)
        get_mock.return_value = mock.Mock(obj=obj)

        with mock.patch.object(
                driver_factory.DriverFactory()._extension_manager,
                'names') as mock_names:
            mock_names.return_value = init_names
            self._start_service()
        tasks = dict(self.service._periodic_tasks)
        self.assertEqual(obj.task, tasks[expected_name])
        self.assertEqual(obj.iface.iface, tasks[expected_name2])
        self.assertEqual(42, self.service._periodic_spacing[expected_name])
        self.assertEqual(100500,
                         self.service._periodic_spacing[expected_name2])
        self.assertIn(expected_name, self.service._periodic_last_run)
        self.assertIn(expected_name2, self.service._periodic_last_run)
Beispiel #8
0
    def init_host(self):
        self.dbapi = dbapi.get_instance()

        self.driver_factory = driver_factory.DriverFactory()
        self.drivers = self.driver_factory.names
        """List of driver names which this conductor supports."""

        try:
            self.dbapi.register_conductor({'hostname': self.host,
                                           'drivers': self.drivers})
        except exception.ConductorAlreadyRegistered:
            LOG.warn(_("A conductor with hostname %(hostname)s "
                       "was previously registered. Updating registration")
                       % {'hostname': self.host})
            self.dbapi.unregister_conductor(self.host)
            self.dbapi.register_conductor({'hostname': self.host,
                                           'drivers': self.drivers})

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

        self._worker_pool = greenpool.GreenPool(
                                size=CONF.conductor.workers_pool_size)
        """GreenPool of background workers for performing tasks async."""
Beispiel #9
0
    def init_host(self):
        self.dbapi = dbapi.get_instance()

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

        self._worker_pool = greenpool.GreenPool(
            size=CONF.conductor.workers_pool_size)
        """GreenPool of background workers for performing tasks async."""

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

        # NOTE(deva): instantiating DriverFactory may raise DriverLoadError
        #             or DriverNotFound
        self._driver_factory = driver_factory.DriverFactory()
        """Driver factory loads all enabled drivers."""

        self.drivers = self._driver_factory.names
        """List of driver names which this conductor supports."""

        if not self.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)

        # Collect driver-specific periodic tasks
        for driver_obj in driver_factory.drivers().values():
            self._collect_periodic_tasks(driver_obj)
            for iface_name in (driver_obj.core_interfaces +
                               driver_obj.standard_interfaces + ['vendor']):
                iface = getattr(driver_obj, iface_name, None)
                if iface:
                    self._collect_periodic_tasks(iface)

        # 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
            cdr = self.dbapi.register_conductor({
                'hostname': self.host,
                'drivers': self.drivers
            })
        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})
            cdr = self.dbapi.register_conductor(
                {
                    'hostname': self.host,
                    'drivers': self.drivers
                },
                update_existing=True)
        self.conductor = cdr

        # 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)

        # 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()