Exemplo n.º 1
0
 def test__client_is_cached(self, mock_get_client):
     mock_get_client.side_effect = get_new_fake_client
     ironicclient = client_wrapper.IronicClientWrapper()
     first_client = ironicclient._get_client()
     second_client = ironicclient._get_client()
     self.assertEqual(id(first_client), id(second_client))
Exemplo n.º 2
0
 def test_call_uses_cached_client(self, mock_get_client):
     mock_get_client.side_effect = get_new_fake_client
     ironicclient = client_wrapper.IronicClientWrapper()
     for n in range(0, 4):
         ironicclient.call("node.list")
     self.assertEqual(1, mock_get_client.call_count)
Exemplo n.º 3
0
    def spawn(self,
              context,
              instance,
              image_meta,
              injected_files,
              admin_password,
              network_info=None,
              block_device_info=None):
        """Deploy an instance.

        :param context: The security context.
        :param instance: The instance object.
        :param image_meta: Image dict returned by nova.image.glance
            that defines the image from which to boot this instance.
        :param injected_files: User files to inject into instance. Ignored
            by this driver.
        :param admin_password: Administrator password to set in
            instance. Ignored by this driver.
        :param network_info: Instance network information.
        :param block_device_info: Instance block device
            information. Ignored by this driver.

        """
        # The compute manager is meant to know the node uuid, so missing uuid
        # is a significant issue. It may mean we've been passed the wrong data.
        node_uuid = instance.get('node')
        if not node_uuid:
            raise ironic.exc.BadRequest(
                _("Ironic node uuid not supplied to "
                  "driver for instance %s.") % instance['uuid'])

        icli = client_wrapper.IronicClientWrapper()
        node = icli.call("node.get", node_uuid)
        flavor = objects.Flavor.get_by_id(context,
                                          instance['instance_type_id'])

        self._add_driver_fields(node, instance, image_meta, flavor)

        # NOTE(Shrews): The default ephemeral device needs to be set for
        # services (like cloud-init) that depend on it being returned by the
        # metadata server. Addresses bug https://launchpad.net/bugs/1324286.
        if flavor['ephemeral_gb']:
            instance.default_ephemeral_device = '/dev/sda1'
            instance.save()

        # validate we are ready to do the deploy
        validate_chk = icli.call("node.validate", node_uuid)
        if not validate_chk.deploy or not validate_chk.power:
            # something is wrong. undo what we have done
            self._cleanup_deploy(context, node, instance, network_info)
            raise exception.ValidationError(
                _("Ironic node: %(id)s failed to validate."
                  " (deploy: %(deploy)s, power: %(power)s)") % {
                      'id': node.uuid,
                      'deploy': validate_chk.deploy,
                      'power': validate_chk.power
                  })

        # prepare for the deploy
        try:
            self._plug_vifs(node, instance, network_info)
            self._start_firewall(instance, network_info)
        except Exception:
            with excutils.save_and_reraise_exception():
                LOG.error(
                    _LE("Error preparing deploy for instance "
                        "%(instance)s on baremetal node %(node)s."), {
                            'instance': instance['uuid'],
                            'node': node_uuid
                        })
                self._cleanup_deploy(context, node, instance, network_info)

        # trigger the node deploy
        try:
            icli.call("node.set_provision_state", node_uuid,
                      ironic_states.ACTIVE)
        except Exception as e:
            with excutils.save_and_reraise_exception():
                msg = (_LE("Failed to request Ironic to provision instance "
                           "%(inst)s: %(reason)s"), {
                               'inst': instance['uuid'],
                               'reason': six.text_type(e)
                           })
                LOG.error(msg)
                self._cleanup_deploy(context, node, instance, network_info)

        timer = loopingcall.FixedIntervalLoopingCall(self._wait_for_active,
                                                     icli, instance)
        try:
            timer.start(interval=CONF.ironic.api_retry_interval).wait()
        except Exception:
            with excutils.save_and_reraise_exception():
                LOG.error(
                    _LE("Error deploying instance %(instance)s on "
                        "baremetal node %(node)s."), {
                            'instance': instance['uuid'],
                            'node': node_uuid
                        })
                self.destroy(context, instance, network_info)
Exemplo n.º 4
0
    def rebuild(self,
                context,
                instance,
                image_meta,
                injected_files,
                admin_password,
                bdms,
                detach_block_devices,
                attach_block_devices,
                network_info=None,
                recreate=False,
                block_device_info=None,
                preserve_ephemeral=False):
        """Rebuild/redeploy an instance.

        This version of rebuild() allows for supporting the option to
        preserve the ephemeral partition. We cannot call spawn() from
        here because it will attempt to set the instance_uuid value
        again, which is not allowed by the Ironic API. It also requires
        the instance to not have an 'active' provision state, but we
        cannot safely change that. Given that, we implement only the
        portions of spawn() we need within rebuild().

        :param context: The security context.
        :param instance: The instance object.
        :param image_meta: Image object returned by nova.image.glance
            that defines the image from which to boot this instance. Ignored
            by this driver.
        :param injected_files: User files to inject into instance. Ignored
            by this driver.
        :param admin_password: Administrator password to set in
            instance. Ignored by this driver.
        :param bdms: block-device-mappings to use for rebuild. Ignored
            by this driver.
        :param detach_block_devices: function to detach block devices. See
            nova.compute.manager.ComputeManager:_rebuild_default_impl for
            usage. Ignored by this driver.
        :param attach_block_devices: function to attach block devices. See
            nova.compute.manager.ComputeManager:_rebuild_default_impl for
            usage. Ignored by this driver.
        :param network_info: Instance network information. Ignored by
            this driver.
        :param recreate: Boolean value; if True the instance is
            recreated on a new hypervisor - all the cleanup of old state is
            skipped. Ignored by this driver.
        :param block_device_info: Instance block device
            information. Ignored by this driver.
        :param preserve_ephemeral: Boolean value; if True the ephemeral
            must be preserved on rebuild.

        """
        instance.task_state = task_states.REBUILD_SPAWNING
        instance.save(expected_task_state=[task_states.REBUILDING])

        node_uuid = instance.node
        icli = client_wrapper.IronicClientWrapper()
        node = icli.call("node.get", node_uuid)
        flavor = objects.Flavor.get_by_id(context,
                                          instance['instance_type_id'])

        self._add_driver_fields(node, instance, image_meta, flavor,
                                preserve_ephemeral)

        # Trigger the node rebuild/redeploy.
        try:
            icli.call("node.set_provision_state", node_uuid,
                      ironic_states.REBUILD)
        except (
                exception.NovaException,  # Retry failed
                ironic.exc.InternalServerError,  # Validations
                ironic.exc.BadRequest) as e:  # Maintenance
            msg = (_("Failed to request Ironic to rebuild instance "
                     "%(inst)s: %(reason)s") % {
                         'inst': instance['uuid'],
                         'reason': six.text_type(e)
                     })
            raise exception.InstanceDeployFailure(msg)

        # Although the target provision state is REBUILD, it will actually go
        # to ACTIVE once the redeploy is finished.
        timer = loopingcall.FixedIntervalLoopingCall(self._wait_for_active,
                                                     icli, instance)
        timer.start(interval=CONF.ironic.api_retry_interval).wait()
Exemplo n.º 5
0
 def setUp(self):
     super(IronicClientWrapperTestCase, self).setUp()
     self.ironicclient = client_wrapper.IronicClientWrapper()
     # Do not waste time sleeping
     cfg.CONF.set_override('api_retry_interval', 0, 'ironic')
Exemplo n.º 6
0
 def host_passes(self, host_state, spec_obj):
     ironic_client = ironic_client_wrapper.IronicClientWrapper()
     ironic_node = ironic_client.call('node.get', host_state.nodename)
     return (ironic_node.properties.get("available", "") == '*' or ironic_node.properties.get("project_id") == spec_obj.project_id)
Exemplo n.º 7
0
    def destroy(self,
                context,
                instance,
                network_info,
                block_device_info=None,
                destroy_disks=True,
                migrate_data=None):
        """Destroy the specified instance, if it can be found.

        :param context: The security context.
        :param instance: The instance object.
        :param network_info: Instance network information.
        :param block_device_info: Instance block device
            information. Ignored by this driver.
        :param destroy_disks: Indicates if disks should be
            destroyed. Ignored by this driver.
        :param migrate_data: implementation specific params.
            Ignored by this driver.
        """
        icli = client_wrapper.IronicClientWrapper()
        try:
            node = _validate_instance_and_node(icli, instance)
        except exception.InstanceNotFound:
            LOG.warning(_LW("Destroy called on non-existing instance %s."),
                        instance['uuid'])
            # NOTE(): if nova.compute.ComputeManager._delete_instance()
            #             is called on a non-existing instance, the only way
            #             to delete it is to return from this method
            #             without raising any exceptions.
            return

        # need to power on the node before clean local disk
        if node.power_state == ironic_states.POWER_OFF:
            try:
                LOG.info("powering on the node %s" % node.uuid)
                icli.call("node.set_power_state", node.uuid, "on")
                timer = loopingcall.FixedIntervalLoopingCall(
                    self._wait_for_power_state, icli, instance, "power on")
                timer.start(interval=CONF.ironic.api_retry_interval).wait()
            except Exception:
                LOG.ERROR("set the node : %s to power on failed." % node.uuid)
                raise exception.NovaException(
                    _("set the node : %s to "
                      "power on failed.") % node.uuid)
        LOG.debug(_("Enter clean node disk for baremetal-server: %s"), node)

        retry_times = CONF.clean_local_disk_retry_times
        while retry_times > 0:
            try:
                self._clean_local_disk(instance)
            except Exception as e:
                retry_times -= 1
                LOG.error(
                    _("Error clean local disk: %s, instance is %s, "
                      "Traceback is %s, remaining retry times %s." %
                      (e, instance['uuid'], traceback.format_exc(),
                       retry_times)))
            else:
                break

        if node.provision_state in (ironic_states.ACTIVE,
                                    ironic_states.DEPLOYFAIL,
                                    ironic_states.ERROR,
                                    ironic_states.DEPLOYWAIT):
            self._unprovision(icli, instance, node)

        self._cleanup_deploy(context, node, instance, network_info)