示例#1
0
    def consume_in_thread(self):
        """Runs the ZmqProxy service"""
        ipc_dir = CONF.rpc_zmq_ipc_dir
        consume_in = "tcp://%s:%s" % \
            (CONF.rpc_zmq_bind_address,
             CONF.rpc_zmq_port)
        consumption_proxy = InternalContext(None)

        if not os.path.isdir(ipc_dir):
            try:
                utils.execute('mkdir', '-p', ipc_dir, run_as_root=True)
                utils.execute('chown', "%s:%s" % (os.getuid(), os.getgid()),
                              ipc_dir, run_as_root=True)
                utils.execute('chmod', '750', ipc_dir, run_as_root=True)
            except utils.ProcessExecutionError:
                with excutils.save_and_reraise_exception():
                    LOG.error(_("Could not create IPC directory %s") %
                              (ipc_dir, ))

        try:
            self.register(consumption_proxy,
                          consume_in,
                          zmq.PULL,
                          out_bind=True)
        except zmq.ZMQError:
            with excutils.save_and_reraise_exception():
                LOG.error(_("Could not create ZeroMQ receiver daemon. "
                            "Socket may already be in use."))

        super(ZmqProxy, self).consume_in_thread()
示例#2
0
    def consume_in_thread(self):
        """Runs the ZmqProxy service"""
        ipc_dir = CONF.rpc_zmq_ipc_dir
        consume_in = "tcp://%s:%s" % \
            (CONF.rpc_zmq_bind_address,
             CONF.rpc_zmq_port)
        consumption_proxy = InternalContext(None)

        if not os.path.isdir(ipc_dir):
            try:
                utils.execute('mkdir', '-p', ipc_dir, run_as_root=True)
                utils.execute('chown',
                              "%s:%s" % (os.getuid(), os.getgid()),
                              ipc_dir,
                              run_as_root=True)
                utils.execute('chmod', '750', ipc_dir, run_as_root=True)
            except utils.ProcessExecutionError:
                with excutils.save_and_reraise_exception():
                    LOG.error(
                        _("Could not create IPC directory %s") % (ipc_dir, ))

        try:
            self.register(consumption_proxy,
                          consume_in,
                          zmq.PULL,
                          out_bind=True)
        except zmq.ZMQError:
            with excutils.save_and_reraise_exception():
                LOG.error(
                    _("Could not create ZeroMQ receiver daemon. "
                      "Socket may already be in use."))

        super(ZmqProxy, self).consume_in_thread()
示例#3
0
    def consume_in_thread(self):
        """Runs the ZmqProxy service."""
        ipc_dir = CONF.rpc_zmq_ipc_dir
        consume_in = "tcp://%s:%s" % \
            (CONF.rpc_zmq_bind_address,
             CONF.rpc_zmq_port)
        consumption_proxy = InternalContext(None)

        try:
            os.makedirs(ipc_dir)
        except os.error:
            if not os.path.isdir(ipc_dir):
                with excutils.save_and_reraise_exception():
                    LOG.error(
                        _("Required IPC directory does not exist at"
                          " %s") % (ipc_dir, ))
        try:
            self.register(consumption_proxy, consume_in, zmq.PULL)
        except zmq.ZMQError:
            if os.access(ipc_dir, os.X_OK):
                with excutils.save_and_reraise_exception():
                    LOG.error(
                        _("Permission denied to IPC directory at"
                          " %s") % (ipc_dir, ))
            with excutils.save_and_reraise_exception():
                LOG.error(
                    _("Could not create ZeroMQ receiver daemon. "
                      "Socket may already be in use."))

        super(ZmqProxy, self).consume_in_thread()
示例#4
0
def deploy(address,
           port,
           iqn,
           lun,
           image_path,
           pxe_config_path,
           root_mb,
           swap_mb,
           ephemeral_mb,
           ephemeral_format,
           node_uuid,
           preserve_ephemeral=False):
    """All-in-one function to deploy a node.

    :param address: The iSCSI IP address.
    :param port: The iSCSI port number.
    :param iqn: The iSCSI qualified name.
    :param lun: The iSCSI logical unit number.
    :param image_path: Path for the instance's disk image.
    :param pxe_config_path: Path for the instance PXE config file.
    :param root_mb: Size of the root partition in megabytes.
    :param swap_mb: Size of the swap partition in megabytes.
    :param ephemeral_mb: Size of the ephemeral partition in megabytes. If 0,
        no ephemeral partition will be created.
    :param ephemeral_format: The type of file system to format the ephemeral
        partition.
    :param node_uuid: node's uuid. Used for logging.
    :param preserve_ephemeral: If True, no filesystem is written to the
        ephemeral block device, preserving whatever content it had (if the
        partition table has not changed).

    """
    dev = get_dev(address, port, iqn, lun)
    image_mb = get_image_mb(image_path)
    if image_mb > root_mb:
        root_mb = image_mb
    discovery(address, port)
    login_iscsi(address, port, iqn)
    try:
        root_uuid = work_on_disk(dev, root_mb, swap_mb, ephemeral_mb,
                                 ephemeral_format, image_path, node_uuid,
                                 preserve_ephemeral)
    except processutils.ProcessExecutionError as err:
        with excutils.save_and_reraise_exception():
            LOG.error(_("Deploy to address %s failed.") % address)
            LOG.error(_("Command: %s") % err.cmd)
            LOG.error(_("StdOut: %r") % err.stdout)
            LOG.error(_("StdErr: %r") % err.stderr)
    except exception.InstanceDeployFailure as e:
        with excutils.save_and_reraise_exception():
            LOG.error(_("Deploy to address %s failed.") % address)
            LOG.error(e)
    finally:
        logout_iscsi(address, port, iqn)
        delete_iscsi(address, port, iqn)
    switch_pxe_config(pxe_config_path, root_uuid)
    # Ensure the node started netcat on the port after POST the request.
    time.sleep(3)
    notify(address, 10000)
示例#5
0
def deploy(
    address,
    port,
    iqn,
    lun,
    image_path,
    pxe_config_path,
    root_mb,
    swap_mb,
    ephemeral_mb,
    ephemeral_format,
    preserve_ephemeral=False,
):
    """All-in-one function to deploy a node.

    :param address: The iSCSI IP address.
    :param port: The iSCSI port number.
    :param iqn: The iSCSI qualified name.
    :param lun: The iSCSI logical unit number.
    :param image_path: Path for the instance's disk image.
    :param pxe_config_path: Path for the instance PXE config file.
    :param root_mb: Size of the root partition in megabytes.
    :param swap_mb: Size of the swap partition in megabytes.
    :param ephemeral_mb: Size of the ephemeral partition in megabytes. If 0,
        no ephemeral partition will be created.
    :param ephemeral_format: The type of file system to format the ephemeral
        partition.
    :param preserve_ephemeral: If True, no filesystem is written to the
        ephemeral block device, preserving whatever content it had (if the
        partition table has not changed).

    """
    dev = get_dev(address, port, iqn, lun)
    image_mb = get_image_mb(image_path)
    if image_mb > root_mb:
        root_mb = image_mb
    discovery(address, port)
    login_iscsi(address, port, iqn)
    try:
        root_uuid = work_on_disk(dev, root_mb, swap_mb, ephemeral_mb, ephemeral_format, image_path, preserve_ephemeral)
    except processutils.ProcessExecutionError as err:
        with excutils.save_and_reraise_exception():
            LOG.error(_("Deploy to address %s failed.") % address)
            LOG.error(_("Command: %s") % err.cmd)
            LOG.error(_("StdOut: %r") % err.stdout)
            LOG.error(_("StdErr: %r") % err.stderr)
    except exception.InstanceDeployFailure as e:
        with excutils.save_and_reraise_exception():
            LOG.error(_("Deploy to address %s failed.") % address)
            LOG.error(e)
    finally:
        logout_iscsi(address, port, iqn)
        delete_iscsi(address, port, iqn)
    switch_pxe_config(pxe_config_path, root_uuid)
    # Ensure the node started netcat on the port after POST the request.
    time.sleep(3)
    notify(address, 10000)
示例#6
0
    def do_node_deploy(self, context, node_id):
        """RPC method to initiate deployment to a node.

        :param context: an admin context.
        :param node_id: the id or uuid of a node.
        :raises: InstanceDeployFailure

        """
        LOG.debug(_("RPC do_node_deploy called for node %s.") % node_id)

        with task_manager.acquire(context, node_id, shared=False) as task:
            node = task.node
            if node['provision_state'] is not states.NOSTATE:
                raise exception.InstanceDeployFailure(
                    _("RPC do_node_deploy called for %(node)s, but provision "
                      "state is already %(state)s.") % {
                          'node': node_id,
                          'state': node['provision_state']
                      })

            if node.maintenance:
                raise exception.InstanceDeployFailure(
                    _("RPC do_node_deploy called for %s, but node is in "
                      "maintenance mode.") % node_id)

            try:
                task.driver.deploy.validate(task, node)
            except Exception as e:
                with excutils.save_and_reraise_exception():
                    node['last_error'] = \
                        _("Failed to validate deploy info. Error: %s") % e
            else:
                # set target state to expose that work is in progress
                node['provision_state'] = states.DEPLOYING
                node['target_provision_state'] = states.DEPLOYDONE
                node['last_error'] = None
            finally:
                node.save(context)

            try:
                task.driver.deploy.prepare(task, node)
                new_state = task.driver.deploy.deploy(task, node)
            except Exception as e:
                with excutils.save_and_reraise_exception():
                    node['last_error'] = _("Failed to deploy. Error: %s") % e
                    node['provision_state'] = states.DEPLOYFAIL
                    node['target_provision_state'] = states.NOSTATE
            else:
                # NOTE(deva): Some drivers may return states.DEPLOYWAIT
                #             eg. if they are waiting for a callback
                if new_state == states.DEPLOYDONE:
                    node['target_provision_state'] = states.NOSTATE
                    node['provision_state'] = states.ACTIVE
                else:
                    node['provision_state'] = new_state
            finally:
                node.save(context)
示例#7
0
    def do_node_tear_down(self, context, node_id):
        """RPC method to tear down an existing node deployment.

        :param context: an admin context.
        :param node_id: the id or uuid of a node.
        :raises: InstanceDeployFailure

        """
        LOG.debug(_("RPC do_node_tear_down called for node %s.") % node_id)

        with task_manager.acquire(context, node_id, shared=False) as task:
            node = task.node
            if node['provision_state'] not in [
                    states.ACTIVE, states.DEPLOYFAIL, states.ERROR,
                    states.DEPLOYWAIT
            ]:
                raise exception.InstanceDeployFailure(
                    _("RCP do_node_tear_down "
                      "not allowed for node %(node)s in state %(state)s") % {
                          'node': node_id,
                          'state': node['provision_state']
                      })

            try:
                task.driver.deploy.validate(task, node)
            except Exception as e:
                with excutils.save_and_reraise_exception():
                    node['last_error'] = \
                        ("Failed to validate info for teardown. Error: %s") % e
            else:
                # set target state to expose that work is in progress
                node['provision_state'] = states.DELETING
                node['target_provision_state'] = states.DELETED
                node['last_error'] = None
            finally:
                node.save(context)

            try:
                task.driver.deploy.clean_up(task, node)
                new_state = task.driver.deploy.tear_down(task, node)
            except Exception as e:
                with excutils.save_and_reraise_exception():
                    node['last_error'] = \
                                      _("Failed to tear down. Error: %s") % e
                    node['provision_state'] = states.ERROR
                    node['target_provision_state'] = states.NOSTATE
            else:
                # NOTE(deva): Some drivers may return states.DELETING
                #             eg. if they are waiting for a callback
                if new_state == states.DELETED:
                    node['target_provision_state'] = states.NOSTATE
                    node['provision_state'] = states.NOSTATE
                else:
                    node['provision_state'] = new_state
            finally:
                node.save(context)
示例#8
0
    def set_console_mode(self, context, node_id, enabled):
        """Enable/Disable the console.

        :param context: request context.
        :param node_id: node id or uuid.
        :param enabled: Boolean value; whether the console is enabled or
                        disabled.
        :raises: UnsupportedDriverExtension if the node's driver doesn't
                 support console.
        :raises: InvalidParameterValue when the wrong driver info is specified.
        """
        LOG.debug(_('RPC set_console_mode called for node %(node)s with '
                    'enabled %(enabled)s') % {'node': node_id,
                                              'enabled': enabled})

        with task_manager.acquire(context, node_id) as task:
            node = task.node

            if not getattr(task.driver, 'console', None):
                exc = exception.UnsupportedDriverExtension(driver=node.driver,
                                                           extension='console')
                node.last_error = exc.format_message()
                node.save(context)
                raise exc

            try:
                task.driver.console.validate(task, node)
            except exception.InvalidParameterValue as e:
                with excutils.save_and_reraise_exception():
                    node.last_error = (_("Failed to validate console info. "
                                         "Error: %s") % e)
                    node.save(context)

            try:
                if enabled and not node.console_enabled:
                    task.driver.console.start_console(task, node)
                elif not enabled and node.console_enabled:
                    task.driver.console.stop_console(task, node)
                else:
                    op = _('enabled') if enabled else _('disabled')
                    LOG.info(_("No console action was triggered because the "
                               "console is already %s") % op)
            except Exception as e:
                with excutils.save_and_reraise_exception():
                    op = _('enabling') if enabled else _('disabling')
                    msg = (_('Error %(op)s the console on node %(node)s. '
                            'Reason: %(error)s') % {'op': op,
                                                    'node': node.uuid,
                                                    'error': e})
                    node.last_error = msg
            else:
                node.console_enabled = enabled
                node.last_error = None
            finally:
                node.save(context)
示例#9
0
    def do_node_tear_down(self, context, node_obj):
        """RPC method to tear down an existing node deployment.

        :param context: an admin context.
        :param node_obj: an RPC-style node object.
        :raises: InstanceDeployFailure

        """
        node_id = node_obj.get('uuid')
        LOG.debug(_("RPC do_node_tear_down called for node %s.") % node_id)

        with task_manager.acquire(context, node_id, shared=False) as task:
            node = task.node
            if node['provision_state'] not in [states.ACTIVE,
                                               states.DEPLOYFAIL,
                                               states.ERROR]:
                raise exception.InstanceDeployFailure(_(
                    "RCP do_node_tear_down "
                    "not allowed for node %(node)s in state %(state)s")
                    % {'node': node_id, 'state': node['provision_state']})

            try:
                task.driver.deploy.validate(node)
            except Exception as e:
                with excutils.save_and_reraise_exception():
                    node['last_error'] = \
                        ("Failed to validate info for teardown. Error: %s") % e
            else:
                # set target state to expose that work is in progress
                node['provision_state'] = states.DELETING
                node['target_provision_state'] = states.DELETED
                node['last_error'] = None
            finally:
                node.save(context)

            try:
                new_state = task.driver.deploy.tear_down(task, node)
            except Exception as e:
                with excutils.save_and_reraise_exception():
                    node['last_error'] = \
                                      _("Failed to tear down. Error: %s") % e
                    node['provision_state'] = states.ERROR
                    node['target_provision_state'] = states.NOSTATE
            else:
                # NOTE(deva): Some drivers may return states.DELETING
                #             eg. if they are waiting for a callback
                if new_state == states.DELETED:
                    node['target_provision_state'] = states.NOSTATE
                    node['provision_state'] = states.NOSTATE
                else:
                    node['provision_state'] = new_state
            finally:
                node.save(context)
示例#10
0
    def do_node_deploy(self, context, node_obj):
        """RPC method to initiate deployment to a node.

        :param context: an admin context.
        :param node_obj: an RPC-style node object.
        :raises: InstanceDeployFailure

        """
        node_id = node_obj.get('uuid')
        LOG.debug(_("RPC do_node_deploy called for node %s.") % node_id)

        with task_manager.acquire(context, node_id, shared=False) as task:
            node = task.node
            if node['provision_state'] is not states.NOSTATE:
                raise exception.InstanceDeployFailure(_(
                    "RPC do_node_deploy called for %(node)s, but provision "
                    "state is already %(state)s.") %
                    {'node': node_id, 'state': node['provision_state']})

            try:
                task.driver.deploy.validate(node)
            except Exception as e:
                with excutils.save_and_reraise_exception():
                    node['last_error'] = \
                        _("Failed to validate deploy info. Error: %s") % e
            else:
                # set target state to expose that work is in progress
                node['provision_state'] = states.DEPLOYING
                node['target_provision_state'] = states.DEPLOYDONE
                node['last_error'] = None
            finally:
                node.save(context)

            try:
                new_state = task.driver.deploy.deploy(task, node)
            except Exception as e:
                with excutils.save_and_reraise_exception():
                    node['last_error'] = _("Failed to deploy. Error: %s") % e
                    node['provision_state'] = states.ERROR
                    node['target_provision_state'] = states.NOSTATE
            else:
                # NOTE(deva): Some drivers may return states.DEPLOYING
                #             eg. if they are waiting for a callback
                if new_state == states.DEPLOYDONE:
                    node['target_provision_state'] = states.NOSTATE
                    node['provision_state'] = states.ACTIVE
                else:
                    node['provision_state'] = new_state
            finally:
                node.save(context)
示例#11
0
def destroy_disk_metadata(dev, node_uuid):
    """Destroy metadata structures on node's disk.

       Ensure that node's disk appears to be blank without zeroing the entire
       drive. To do this we will zero:
       - the first 18KiB to clear MBR / GPT data
       - the last 18KiB to clear GPT and other metadata like: LVM, veritas,
         MDADM, DMRAID, ...
    """
    # NOTE(NobodyCam): This is needed to work around bug:
    # https://bugs.launchpad.net/ironic/+bug/1317647
    try:
        utils.execute('dd', 'if=/dev/zero', 'of=%s' % dev,
                      'bs=512', 'count=36', run_as_root=True,
                      check_exit_code=[0])
    except processutils.ProcessExecutionError as err:
        with excutils.save_and_reraise_exception():
            LOG.error(_("Failed to erase beginning of disk for node "
                        "%(node)s. Command: %(command)s. Error: %(error)s."),
                      {'node': node_uuid,
                       'command': err.cmd,
                       'error': err.stderr})

    # now wipe the end of the disk.
    # get end of disk seek value
    try:
        block_sz = get_dev_block_size(dev)
    except processutils.ProcessExecutionError as err:
        with excutils.save_and_reraise_exception():
            LOG.error(_("Failed to get disk block count for node %(node)s. "
                        "Command: %(command)s. Error: %(error)s."),
                      {'node': node_uuid,
                       'command': err.cmd,
                       'error': err.stderr})
    else:
        seek_value = block_sz - 36
        try:
            utils.execute('dd', 'if=/dev/zero', 'of=%s' % dev,
                          'bs=512', 'count=36', 'seek=%d' % seek_value,
                          run_as_root=True, check_exit_code=[0])
        except processutils.ProcessExecutionError as err:
            with excutils.save_and_reraise_exception():
                LOG.error(_("Failed to erase the end of the disk on node "
                            "%(node)s. Command: %(command)s. "
                            "Error: %(error)s."),
                          {'node': node_uuid,
                           'command': err.cmd,
                           'error': err.stderr})
示例#12
0
    def destroy(self, instance, network_info, block_device_info=None):
        context = nova_context.get_admin_context()

        try:
            node = _get_baremetal_node_by_instance_uuid(instance['uuid'])
        except exception.InstanceNotFound:
            LOG.warning(_("Destroy called on non-existing instance %s")
                    % instance['uuid'])
            return

        try:
            self.driver.deactivate_node(context, node, instance)
            self.power_off(instance, node)
            self.driver.deactivate_bootloader(context, node, instance)
            self.driver.destroy_images(context, node, instance)

            self._detach_block_devices(instance, block_device_info)
            self._stop_firewall(instance, network_info)
            self._unplug_vifs(instance, network_info)

            _update_state(context, node, None, states.DELETED)
        except Exception as e:
            with excutils.save_and_reraise_exception():
                try:
                    LOG.error(_("Error from baremetal driver "
                                "during destroy: %s") % e)
                    _update_state(context, node, instance,
                                  states.ERROR)
                except Exception:
                    LOG.error(_("Error while recording destroy failure in "
                                "baremetal database: %s") % e)
示例#13
0
def work_on_disk(dev,
                 root_mb,
                 swap_mb,
                 ephemeral_mb,
                 ephemeral_format,
                 image_path,
                 preserve_ephemeral=False):
    """Create partitions and copy an image to the root partition.

    :param dev: Path for the device to work on.
    :param root_mb: Size of the root partition in megabytes.
    :param swap_mb: Size of the swap partition in megabytes.
    :param ephemeral_mb: Size of the ephemeral partition in megabytes. If 0,
        no ephemeral partition will be created.
    :param ephemeral_format: The type of file system to format the ephemeral
        partition.
    :param image_path: Path for the instance's disk image.
    :param preserve_ephemeral: If True, no filesystem is written to the
        ephemeral block device, preserving whatever content it had (if the
        partition table has not changed).

    """
    # NOTE(lucasagomes): When there's an ephemeral partition we want
    # root to be last because that would allow root to resize and make it
    # safer to do takeovernode with slightly larger images
    if ephemeral_mb:
        ephemeral_part = "%s-part1" % dev
        swap_part = "%s-part2" % dev
        root_part = "%s-part3" % dev
    else:
        root_part = "%s-part1" % dev
        swap_part = "%s-part2" % dev

    if not is_block_device(dev):
        raise exception.InstanceDeployFailure(
            _("Parent device '%s' not found") % dev)
    make_partitions(dev, root_mb, swap_mb, ephemeral_mb)

    if not is_block_device(root_part):
        raise exception.InstanceDeployFailure(
            _("Root device '%s' not found") % root_part)
    if not is_block_device(swap_part):
        raise exception.InstanceDeployFailure(
            _("Swap device '%s' not found") % swap_part)
    if ephemeral_mb and not is_block_device(ephemeral_part):
        raise exception.InstanceDeployFailure(
            _("Ephemeral device '%s' not found") % ephemeral_part)

    dd(image_path, root_part)
    mkswap(swap_part)

    if ephemeral_mb and not preserve_ephemeral:
        mkfs_ephemeral(ephemeral_part, ephemeral_format)

    try:
        root_uuid = block_uuid(root_part)
    except processutils.ProcessExecutionError:
        with excutils.save_and_reraise_exception():
            LOG.error(_("Failed to detect root device UUID."))
    return root_uuid
示例#14
0
文件: node.py 项目: taomaree/ironic
    def patch(self, uuid, patch):
        """Update an existing node."""
        if self._from_chassis:
            raise exception.OperationNotPermitted

        node = objects.Node.get_by_uuid(pecan.request.context, uuid)
        node_dict = node.as_dict()

        utils.validate_patch(patch)
        patch_obj = jsonpatch.JsonPatch(patch)

        # Prevent states from being updated
        state_rel_path = ['/power_state', '/target_power_state',
                          '/provision_state', '/target_provision_state']
        if any(p['path'] in state_rel_path for p in patch_obj):
            raise wsme.exc.ClientSideError(_("Changing states is not allowed "
                                             "here; You must use the "
                                             "nodes/%s/state interface.")
                                             % uuid)

        # Prevent node from being updated when there's a state
        # change in progress
        if any(node.get(tgt) for tgt in ["target_power_state",
                                         "target_provision_state"]):
            raise wsme.exc.ClientSideError(_("Can not update node %s while "
                                             "a state transition is in "
                                             "progress.") % uuid,
                                             status_code=409)

        try:
            patched_node = jsonpatch.apply_patch(node_dict, patch_obj)
        except jsonpatch.JsonPatchException as e:
            LOG.exception(e)
            raise wsme.exc.ClientSideError(_("Patching Error: %s") % e)

        try:
            self. _convert_chassis_uuid_to_id(patched_node)
            defaults = objects.Node.get_defaults()
            for key in defaults:
                # Internal values that shouldn't be part of the patch
                if key in ['id', 'updated_at', 'created_at']:
                    continue

                # In case of a remove operation, add the missing fields back
                # to the document with their default value
                if key in node_dict and key not in patched_node:
                    patched_node[key] = defaults[key]

                # Update only the fields that have changed
                if node[key] != patched_node[key]:
                    node[key] = patched_node[key]

            node = pecan.request.rpcapi.update_node(pecan.request.context,
                                                    node)

        except exception.IronicException as e:
            with excutils.save_and_reraise_exception():
                LOG.exception(e)

        return Node.convert_with_links(node)
示例#15
0
 def _do_node_tear_down(self, context, task):
     """Internal RPC method to tear down an existing node deployment."""
     node = task.node
     try:
         task.driver.deploy.clean_up(task)
         new_state = task.driver.deploy.tear_down(task)
     except Exception as e:
         with excutils.save_and_reraise_exception():
             LOG.warning(_('Error in tear_down of node %(node)s: %(err)s'),
                         {'node': task.node.uuid, 'err': e})
             node.last_error = _("Failed to tear down. Error: %s") % e
             node.provision_state = states.ERROR
             node.target_provision_state = states.NOSTATE
     else:
         # NOTE(deva): Some drivers may return states.DELETING
         #             eg. if they are waiting for a callback
         if new_state == states.DELETED:
             node.target_provision_state = states.NOSTATE
             node.provision_state = states.NOSTATE
             LOG.info(_LI('Successfully unprovisioned node %(node)s with '
                          'instance %(instance)s.'),
                      {'node': node.uuid, 'instance': node.instance_uuid})
         else:
             node.provision_state = new_state
     finally:
         # Clean the instance_info
         node.instance_info = {}
         node.save(context)
示例#16
0
 def _do_node_deploy(self, context, task):
     """Prepare the environment and deploy a node."""
     node = task.node
     try:
         task.driver.deploy.prepare(task)
         new_state = task.driver.deploy.deploy(task)
     except Exception as e:
         with excutils.save_and_reraise_exception():
             LOG.warning(_('Error in deploy of node %(node)s: %(err)s'),
                         {'node': task.node.uuid, 'err': e})
             node.last_error = _("Failed to deploy. Error: %s") % e
             node.provision_state = states.DEPLOYFAIL
             node.target_provision_state = states.NOSTATE
     else:
         # NOTE(deva): Some drivers may return states.DEPLOYWAIT
         #             eg. if they are waiting for a callback
         if new_state == states.DEPLOYDONE:
             node.target_provision_state = states.NOSTATE
             node.provision_state = states.ACTIVE
             LOG.info(_LI('Successfully deployed node %(node)s with '
                          'instance %(instance)s.'),
                      {'node': node.uuid, 'instance': node.instance_uuid})
         else:
             node.provision_state = new_state
     finally:
         node.save(context)
示例#17
0
    def change_node_power_state(self, context, node_id, new_state):
        """RPC method to encapsulate changes to a node's state.

        Perform actions such as power on, power off. The validation and power
        action are performed in background (async). Once the power action is
        finished and successful, it updates the power_state for the node with
        the new power state.

        :param context: an admin context.
        :param node_id: the id or uuid of a node.
        :param new_state: the desired power state of the node.
        :raises: NoFreeConductorWorker when there is no free worker to start
                 async task.

        """
        LOG.debug(_("RPC change_node_power_state called for node %(node)s. "
                    "The desired new state is %(state)s.")
                    % {'node': node_id, 'state': new_state})

        task = task_manager.TaskManager(context, node_id, shared=False)

        try:
            # Start requested action in the background.
            thread = self._spawn_worker(utils.node_power_action,
                                        task, task.node, new_state)
            # Release node lock at the end.
            thread.link(lambda t: task.release_resources())
        except Exception:
            with excutils.save_and_reraise_exception():
                # Release node lock if error occurred.
                task.release_resources()
示例#18
0
文件: node.py 项目: mshabdiz/ironic
    def post(self, node):
        """Create a new node.

        :param node: a node within the request body.
        """
        if self._from_chassis:
            raise exception.OperationNotPermitted

        # NOTE(deva): get_topic_for checks if node.driver is in the hash ring
        #             and raises NoValidHost if it is not.
        #             We need to ensure that node has a UUID before it can
        #             be mapped onto the hash ring.
        if not node.uuid:
            node.uuid = utils.generate_uuid()

        try:
            pecan.request.rpcapi.get_topic_for(node)
        except exception.NoValidHost as e:
            # NOTE(deva): convert from 404 to 400 because client can see
            #             list of available drivers and shouldn't request
            #             one that doesn't exist.
            e.code = 400
            raise e

        try:
            new_node = pecan.request.dbapi.create_node(node.as_dict())
        except Exception as e:
            with excutils.save_and_reraise_exception():
                LOG.exception(e)
        return Node.convert_with_links(new_node)
示例#19
0
文件: power.py 项目: yuanying/ironic
def _get_power_state(node):
    """Returns the current power state of the node

    :param node: The node.
    :returns: power state, one of :mod: `ironic.common.states`.
    :raises: DracClientError if the client received unexpected response.
    :raises: InvalidParameterValue if required DRAC credentials are missing.
    """

    client = drac_common.get_wsman_client(node)
    options = pywsman.ClientOptions()
    filter_query = ('select EnabledState,ElementName from CIM_ComputerSystem '
                    'where Name="srv:system"')
    try:
        doc = client.wsman_enumerate(resource_uris.DCIM_ComputerSystem,
                                     options, filter_query=filter_query)
    except exception.DracClientError as exc:
        with excutils.save_and_reraise_exception():
            LOG.error(_LE('DRAC driver failed to get power state for node '
                          '%(node_uuid)s. Reason: %(error)s.'),
                      {'node_uuid': node.uuid, 'error': exc})

    enabled_state = drac_common.find_xml(doc, 'EnabledState',
                                         resource_uris.DCIM_ComputerSystem)
    return POWER_STATES[enabled_state.text]
示例#20
0
        def wrapped(self, context, *args, **kw):
            # Don't store self or context in the payload, it now seems to
            # contain confidential information.
            try:
                return f(self, context, *args, **kw)
            except Exception, e:
                with excutils.save_and_reraise_exception():
                    if notifier:
                        payload = dict(exception=e)
                        call_dict = safe_utils.getcallargs(f, *args, **kw)
                        cleansed = _cleanse_dict(call_dict)
                        payload.update({'args': cleansed})

                        # Use a temp vars so we don't shadow
                        # our outer definitions.
                        temp_level = level
                        if not temp_level:
                            temp_level = notifier.ERROR

                        temp_type = event_type
                        if not temp_type:
                            # If f has multiple decorators, they must use
                            # functools.wraps to ensure the name is
                            # propagated.
                            temp_type = f.__name__

                        notifier.notify(context, publisher_id, temp_type,
                                        temp_level, payload)
示例#21
0
        def wrapped(self, context, *args, **kw):
            # Don't store self or context in the payload, it now seems to
            # contain confidential information.
            try:
                return f(self, context, *args, **kw)
            except Exception, e:
                with excutils.save_and_reraise_exception():
                    if notifier:
                        payload = dict(exception=e)
                        call_dict = safe_utils.getcallargs(f, *args, **kw)
                        cleansed = _cleanse_dict(call_dict)
                        payload.update({'args': cleansed})

                        # Use a temp vars so we don't shadow
                        # our outer definitions.
                        temp_level = level
                        if not temp_level:
                            temp_level = notifier.ERROR

                        temp_type = event_type
                        if not temp_type:
                            # If f has multiple decorators, they must use
                            # functools.wraps to ensure the name is
                            # propagated.
                            temp_type = f.__name__

                        notifier.notify(context, publisher_id, temp_type,
                                        temp_level, payload)
示例#22
0
文件: node.py 项目: mshabdiz/ironic
    def post(self, node):
        """Create a new node.

        :param node: a node within the request body.
        """
        if self._from_chassis:
            raise exception.OperationNotPermitted

        # NOTE(deva): get_topic_for checks if node.driver is in the hash ring
        #             and raises NoValidHost if it is not.
        #             We need to ensure that node has a UUID before it can
        #             be mapped onto the hash ring.
        if not node.uuid:
            node.uuid = utils.generate_uuid()

        try:
            pecan.request.rpcapi.get_topic_for(node)
        except exception.NoValidHost as e:
            # NOTE(deva): convert from 404 to 400 because client can see
            #             list of available drivers and shouldn't request
            #             one that doesn't exist.
            e.code = 400
            raise e

        try:
            new_node = pecan.request.dbapi.create_node(node.as_dict())
        except Exception as e:
            with excutils.save_and_reraise_exception():
                LOG.exception(e)
        return Node.convert_with_links(new_node)
示例#23
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()
示例#24
0
    def change_node_power_state(self, context, node_id, new_state):
        """RPC method to encapsulate changes to a node's state.

        Perform actions such as power on, power off. The validation and power
        action are performed in background (async). Once the power action is
        finished and successful, it updates the power_state for the node with
        the new power state.

        :param context: an admin context.
        :param node_id: the id or uuid of a node.
        :param new_state: the desired power state of the node.
        :raises: NoFreeConductorWorker when there is no free worker to start
                 async task.

        """
        LOG.debug(
            _("RPC change_node_power_state called for node %(node)s. "
              "The desired new state is %(state)s.") % {
                  'node': node_id,
                  'state': new_state
              })

        task = task_manager.TaskManager(context, node_id, shared=False)

        try:
            # Start requested action in the background.
            thread = self._spawn_worker(utils.node_power_action, task,
                                        task.node, new_state)
            # Release node lock at the end.
            thread.link(lambda t: task.release_resources())
        except Exception:
            with excutils.save_and_reraise_exception():
                # Release node lock if error occurred.
                task.release_resources()
示例#25
0
文件: manager.py 项目: ravello/ironic
    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()
示例#26
0
    def destroy(self, instance, network_info, block_device_info=None):
        context = nova_context.get_admin_context()

        try:
            node = _get_baremetal_node_by_instance_uuid(instance['uuid'])
        except exception.InstanceNotFound:
            LOG.warning(
                _("Destroy called on non-existing instance %s") %
                instance['uuid'])
            return

        try:
            self.driver.deactivate_node(context, node, instance)
            self.power_off(instance, node)
            self.driver.deactivate_bootloader(context, node, instance)
            self.driver.destroy_images(context, node, instance)

            self._detach_block_devices(instance, block_device_info)
            self._stop_firewall(instance, network_info)
            self._unplug_vifs(instance, network_info)

            _update_state(context, node, None, states.DELETED)
        except Exception as e:
            with excutils.save_and_reraise_exception():
                try:
                    LOG.error(
                        _("Error from baremetal driver "
                          "during destroy: %s") % e)
                    _update_state(context, node, instance, states.ERROR)
                except Exception:
                    LOG.error(
                        _("Error while recording destroy failure in "
                          "baremetal database: %s") % e)
示例#27
0
    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type is None and self._spawn_method is not None:
            # Spawn a worker to complete the task
            # The linked callback below will be called whenever:
            #   - background task finished with no errors.
            #   - background task has crashed with exception.
            #   - callback was added after the background task has
            #     finished or crashed. While eventlet currently doesn't
            #     schedule the new thread until the current thread blocks
            #     for some reason, this is true.
            # All of the above are asserted in tests such that we'll
            # catch if eventlet ever changes this behavior.
            thread = None
            try:
                thread = self._spawn_method(*self._spawn_args,
                                            **self._spawn_kwargs)

                # NOTE(comstud): Trying to use a lambda here causes
                # the callback to not occur for some reason. This
                # also makes it easier to test.
                thread.link(self._thread_release_resources)
                # Don't unlock! The unlock will occur when the
                # thread finshes.
                return
            except Exception:
                with excutils.save_and_reraise_exception():
                    if thread is not None:
                        # This means the link() failed for some
                        # reason. Nuke the thread.
                        thread.cancel()
                    self.release_resources()
        self.release_resources()
示例#28
0
def work_on_disk(dev, root_mb, swap_mb, ephemeral_mb, ephemeral_format,
                 image_path, node_uuid, preserve_ephemeral=False):
    """Create partitions and copy an image to the root partition.

    :param dev: Path for the device to work on.
    :param root_mb: Size of the root partition in megabytes.
    :param swap_mb: Size of the swap partition in megabytes.
    :param ephemeral_mb: Size of the ephemeral partition in megabytes. If 0,
        no ephemeral partition will be created.
    :param ephemeral_format: The type of file system to format the ephemeral
        partition.
    :param image_path: Path for the instance's disk image.
    :param node_uuid: node's uuid. Used for logging.
    :param preserve_ephemeral: If True, no filesystem is written to the
        ephemeral block device, preserving whatever content it had (if the
        partition table has not changed).

    """
    if not is_block_device(dev):
        raise exception.InstanceDeployFailure(_("Parent device '%s' not found")
                                              % dev)

    # the only way for preserve_ephemeral to be set to true is if we are
    # rebuilding an instance with --preserve_ephemeral.
    commit = not preserve_ephemeral
    # now if we are committing the changes to disk clean first.
    if commit:
        destroy_disk_metadata(dev, node_uuid)
    part_dict = make_partitions(dev, root_mb, swap_mb, ephemeral_mb,
                                commit=commit)

    ephemeral_part = part_dict.get('ephemeral')
    swap_part = part_dict.get('swap')
    root_part = part_dict.get('root')

    if not is_block_device(root_part):
        raise exception.InstanceDeployFailure(_("Root device '%s' not found")
                                              % root_part)
    if swap_part and not is_block_device(swap_part):
        raise exception.InstanceDeployFailure(_("Swap device '%s' not found")
                                              % swap_part)
    if ephemeral_part and not is_block_device(ephemeral_part):
        raise exception.InstanceDeployFailure(
                         _("Ephemeral device '%s' not found") % ephemeral_part)

    dd(image_path, root_part)

    if swap_part:
        mkswap(swap_part)

    if ephemeral_part and not preserve_ephemeral:
        mkfs_ephemeral(ephemeral_part, ephemeral_format)

    try:
        root_uuid = block_uuid(root_part)
    except processutils.ProcessExecutionError:
        with excutils.save_and_reraise_exception():
            LOG.error(_("Failed to detect root device UUID."))
    return root_uuid
示例#29
0
 def post(self, chassis):
     """Create a new chassis."""
     try:
         new_chassis = pecan.request.dbapi.create_chassis(chassis.as_dict())
     except Exception as e:
         with excutils.save_and_reraise_exception():
             LOG.exception(e)
     return Chassis.convert_with_links(new_chassis)
示例#30
0
    def set_console_mode(self, context, node_id, enabled):
        """Enable/Disable the console.

        Validate driver specific information synchronously, and then
        spawn a background worker to set console mode asynchronously.

        :param context: request context.
        :param node_id: node id or uuid.
        :param enabled: Boolean value; whether the console is enabled or
                        disabled.
        :raises: UnsupportedDriverExtension if the node's driver doesn't
                 support console.
        :raises: InvalidParameterValue when the wrong driver info is specified.
        :raises: NoFreeConductorWorker when there is no free worker to start
                 async task
        """
        LOG.debug(
            _('RPC set_console_mode called for node %(node)s with '
              'enabled %(enabled)s') % {
                  'node': node_id,
                  'enabled': enabled
              })

        task = task_manager.TaskManager(context, node_id, shared=False)
        node = task.node

        try:
            if not getattr(task.driver, 'console', None):
                exc = exception.UnsupportedDriverExtension(driver=node.driver,
                                                           extension='console')
                node.last_error = exc.format_message()
                node.save(context)
                raise exc

            task.driver.console.validate(task, node)

            if enabled == node.console_enabled:
                op = _('enabled') if enabled else _('disabled')
                LOG.info(
                    _("No console action was triggered because the "
                      "console is already %s") % op)
            else:
                node.last_error = None
                node.save(context)

                # Start the requested action in the background.
                thread = self._spawn_worker(self._set_console_mode, task,
                                            enabled)
                # Release node lock at the end.
                thread.link(lambda t: task.release_resources())

        except Exception:
            with excutils.save_and_reraise_exception():
                # Release node lock if error occurred.
                task.release_resources()
示例#31
0
def work_on_disk(dev, root_mb, swap_mb, ephemeral_mb, ephemeral_format,
                 image_path, preserve_ephemeral=False):
    """Create partitions and copy an image to the root partition.

    :param dev: Path for the device to work on.
    :param root_mb: Size of the root partition in megabytes.
    :param swap_mb: Size of the swap partition in megabytes.
    :param ephemeral_mb: Size of the ephemeral partition in megabytes. If 0,
        no ephemeral partition will be created.
    :param ephemeral_format: The type of file system to format the ephemeral
        partition.
    :param image_path: Path for the instance's disk image.
    :param preserve_ephemeral: If True, no filesystem is written to the
        ephemeral block device, preserving whatever content it had (if the
        partition table has not changed).

    """
    # NOTE(lucasagomes): When there's an ephemeral partition we want
    # root to be last because that would allow root to resize and make it
    # safer to do takeovernode with slightly larger images
    if ephemeral_mb:
        ephemeral_part = "%s-part1" % dev
        swap_part = "%s-part2" % dev
        root_part = "%s-part3" % dev
    else:
        root_part = "%s-part1" % dev
        swap_part = "%s-part2" % dev

    if not is_block_device(dev):
        raise exception.InstanceDeployFailure(_("Parent device '%s' not found")
                                              % dev)
    make_partitions(dev, root_mb, swap_mb, ephemeral_mb)

    if not is_block_device(root_part):
        raise exception.InstanceDeployFailure(_("Root device '%s' not found")
                                              % root_part)
    if not is_block_device(swap_part):
        raise exception.InstanceDeployFailure(_("Swap device '%s' not found")
                                              % swap_part)
    if ephemeral_mb and not is_block_device(ephemeral_part):
        raise exception.InstanceDeployFailure(
                         _("Ephemeral device '%s' not found") % ephemeral_part)

    dd(image_path, root_part)
    mkswap(swap_part)

    if ephemeral_mb and not preserve_ephemeral:
        mkfs_ephemeral(ephemeral_part, ephemeral_format)

    try:
        root_uuid = block_uuid(root_part)
    except processutils.ProcessExecutionError:
        with excutils.save_and_reraise_exception():
            LOG.error(_("Failed to detect root device UUID."))
    return root_uuid
示例#32
0
    def do_node_deploy(self, context, node_id):
        """RPC method to initiate deployment to a node.

        Initiate the deployment of a node. Validations are done
        synchronously and the actual deploy work is performed in
        background (asynchronously).

        :param context: an admin context.
        :param node_id: the id or uuid of a node.
        :raises: InstanceDeployFailure
        :raises: NodeInMaintenance if the node is in maintenance mode.
        :raises: NoFreeConductorWorker when there is no free worker to start
                 async task.

        """
        LOG.debug(_("RPC do_node_deploy called for node %s.") % node_id)

        # NOTE(comstud): If the _sync_power_states() periodic task happens
        # to have locked this node, we'll fail to acquire the lock. The
        # client should perhaps retry in this case unless we decide we
        # want to add retries or extra synchronization here.
        task = task_manager.TaskManager(context, node_id, shared=False)
        node = task.node
        try:
            if node.provision_state is not states.NOSTATE:
                raise exception.InstanceDeployFailure(_(
                    "RPC do_node_deploy called for %(node)s, but provision "
                    "state is already %(state)s.") %
                    {'node': node.uuid, 'state': node.provision_state})

            if node.maintenance:
                raise exception.NodeInMaintenance(op=_('provisioning'),
                                                  node=node.uuid)

            try:
                task.driver.deploy.validate(task, node)
            except exception.InvalidParameterValue as e:
                raise exception.InstanceDeployFailure(_(
                    "RPC do_node_deploy failed to validate deploy info. "
                    "Error: %(msg)s") % {'msg': e})

            # Set target state to expose that work is in progress
            node.provision_state = states.DEPLOYING
            node.target_provision_state = states.DEPLOYDONE
            node.last_error = None
            node.save(context)

            # Start requested action in the background.
            thread = self._spawn_worker(self._do_node_deploy, context, task)
            # Release node lock at the end.
            thread.link(lambda t: task.release_resources())
        except Exception:
            with excutils.save_and_reraise_exception():
                # Release node lock if error occurred.
                task.release_resources()
示例#33
0
def _serialize(data):
    """Serialization wrapper.

    We prefer using JSON, but it cannot encode all types.
    Error if a developer passes us bad data.
    """
    try:
        return jsonutils.dumps(data, ensure_ascii=True)
    except TypeError:
        with excutils.save_and_reraise_exception():
            LOG.error(_("JSON serialization failed."))
示例#34
0
def remove_path_on_error(path):
    """Protect code that wants to operate on PATH atomically.
    Any exception will cause PATH to be removed.

    :param path: File to work with
    """
    try:
        yield
    except Exception:
        with excutils.save_and_reraise_exception():
            delete_if_exists(path)
示例#35
0
def _serialize(data):
    """
    Serialization wrapper
    We prefer using JSON, but it cannot encode all types.
    Error if a developer passes us bad data.
    """
    try:
        return jsonutils.dumps(data, ensure_ascii=True)
    except TypeError:
        with excutils.save_and_reraise_exception():
            LOG.error(_("JSON serialization failed."))
示例#36
0
    def post(self, chassis):
        """Create a new chassis.

        :param chassis: a chassis within the request body.
        """
        try:
            new_chassis = pecan.request.dbapi.create_chassis(chassis.as_dict())
        except Exception as e:
            with excutils.save_and_reraise_exception():
                LOG.exception(e)
        return Chassis.convert_with_links(new_chassis)
示例#37
0
def remove_path_on_error(path):
    """Protect code that wants to operate on PATH atomically.
    Any exception will cause PATH to be removed.

    :param path: File to work with
    """
    try:
        yield
    except Exception:
        with excutils.save_and_reraise_exception():
            delete_if_exists(path)
示例#38
0
def _make_password_file(password):
    try:
        fd, path = tempfile.mkstemp()
        os.fchmod(fd, stat.S_IRUSR | stat.S_IWUSR)
        with os.fdopen(fd, "w") as f:
            f.write(password)

        yield path
        utils.delete_if_exists(path)
    except Exception:
        with excutils.save_and_reraise_exception():
            utils.delete_if_exists(path)
示例#39
0
def _make_password_file(password):
    try:
        fd, path = tempfile.mkstemp()
        os.fchmod(fd, stat.S_IRUSR | stat.S_IWUSR)
        with os.fdopen(fd, "w") as f:
            f.write(password)

        yield path
        utils.delete_if_exists(path)
    except Exception:
        with excutils.save_and_reraise_exception():
            utils.delete_if_exists(path)
示例#40
0
    def do_node_deploy(self, context, node_id):
        """RPC method to initiate deployment to a node.

        Initiate the deployment of a node. Validations are done
        synchronously and the actual deploy work is performed in
        background (asynchronously).

        :param context: an admin context.
        :param node_id: the id or uuid of a node.
        :raises: InstanceDeployFailure
        :raises: NodeInMaintenance if the node is in maintenance mode.
        :raises: NoFreeConductorWorker when there is no free worker to start
                 async task.

        """
        LOG.debug(_("RPC do_node_deploy called for node %s.") % node_id)

        task = task_manager.TaskManager(context, node_id, shared=False)
        node = task.node
        try:
            if node.provision_state is not states.NOSTATE:
                raise exception.InstanceDeployFailure(
                    _("RPC do_node_deploy called for %(node)s, but provision "
                      "state is already %(state)s.") % {
                          'node': node.uuid,
                          'state': node.provision_state
                      })

            if node.maintenance:
                raise exception.NodeInMaintenance(op=_('provisioning'),
                                                  node=node.uuid)

            try:
                task.driver.deploy.validate(task, node)
            except exception.InvalidParameterValue as e:
                raise exception.InstanceDeployFailure(
                    _("RPC do_node_deploy failed to validate deploy info. "
                      "Error: %(msg)s") % {'msg': e})

            # Set target state to expose that work is in progress
            node.provision_state = states.DEPLOYING
            node.target_provision_state = states.DEPLOYDONE
            node.last_error = None
            node.save(context)

            # Start requested action in the background.
            thread = self._spawn_worker(self._do_node_deploy, context, task)
            # Release node lock at the end.
            thread.link(lambda t: task.release_resources())
        except Exception:
            with excutils.save_and_reraise_exception():
                # Release node lock if error occurred.
                task.release_resources()
示例#41
0
    def set_console_mode(self, context, node_id, enabled):
        """Enable/Disable the console.

        Validate driver specific information synchronously, and then
        spawn a background worker to set console mode asynchronously.

        :param context: request context.
        :param node_id: node id or uuid.
        :param enabled: Boolean value; whether the console is enabled or
                        disabled.
        :raises: UnsupportedDriverExtension if the node's driver doesn't
                 support console.
        :raises: InvalidParameterValue when the wrong driver info is specified.
        :raises: NoFreeConductorWorker when there is no free worker to start
                 async task
        """
        LOG.debug(_('RPC set_console_mode called for node %(node)s with '
                    'enabled %(enabled)s') % {'node': node_id,
                                              'enabled': enabled})

        task = task_manager.TaskManager(context, node_id, shared=False)
        node = task.node

        try:
            if not getattr(task.driver, 'console', None):
                exc = exception.UnsupportedDriverExtension(driver=node.driver,
                                                           extension='console')
                node.last_error = exc.format_message()
                node.save(context)
                raise exc

            task.driver.console.validate(task, node)

            if enabled == node.console_enabled:
                op = _('enabled') if enabled else _('disabled')
                LOG.info(_("No console action was triggered because the "
                           "console is already %s") % op)
                task.release_resources()
            else:
                node.last_error = None
                node.save(context)

                # Start the requested action in the background.
                thread = self._spawn_worker(self._set_console_mode,
                                            task, enabled)
                # Release node lock at the end.
                thread.link(lambda t: task.release_resources())

        except Exception:
            with excutils.save_and_reraise_exception():
                # Release node lock if error occurred.
                task.release_resources()
示例#42
0
    def consume_in_thread(self):
        """Runs the ZmqProxy service."""
        ipc_dir = CONF.rpc_zmq_ipc_dir
        consume_in = "tcp://%s:%s" % (CONF.rpc_zmq_bind_address, CONF.rpc_zmq_port)
        consumption_proxy = InternalContext(None)

        try:
            os.makedirs(ipc_dir)
        except os.error:
            if not os.path.isdir(ipc_dir):
                with excutils.save_and_reraise_exception():
                    LOG.error(_("Required IPC directory does not exist at" " %s") % (ipc_dir,))
        try:
            self.register(consumption_proxy, consume_in, zmq.PULL)
        except zmq.ZMQError:
            if os.access(ipc_dir, os.X_OK):
                with excutils.save_and_reraise_exception():
                    LOG.error(_("Permission denied to IPC directory at" " %s") % (ipc_dir,))
            with excutils.save_and_reraise_exception():
                LOG.error(_("Could not create ZeroMQ receiver daemon. " "Socket may already be in use."))

        super(ZmqProxy, self).consume_in_thread()
示例#43
0
    def do_node_tear_down(self, context, node_id):
        """RPC method to tear down an existing node deployment.

        Validate driver specific information synchronously, and then
        spawn a background worker to tear down the node asynchronously.

        :param context: an admin context.
        :param node_id: the id or uuid of a node.
        :raises: InstanceDeployFailure
        :raises: NoFreeConductorWorker when there is no free worker to start
                 async task

        """
        LOG.debug(_("RPC do_node_tear_down called for node %s.") % node_id)

        task = task_manager.TaskManager(context, node_id, shared=False)
        node = task.node
        try:
            if node.provision_state not in [
                    states.ACTIVE, states.DEPLOYFAIL, states.ERROR,
                    states.DEPLOYWAIT
            ]:
                raise exception.InstanceDeployFailure(
                    _("RPC do_node_tear_down "
                      "not allowed for node %(node)s in state %(state)s") % {
                          'node': node_id,
                          'state': node.provision_state
                      })

            try:
                task.driver.deploy.validate(task, node)
            except exception.InvalidParameterValue as e:
                raise exception.InstanceDeployFailure(
                    _("RPC do_node_tear_down failed to validate deploy info. "
                      "Error: %(msg)s") % {'msg': e})

            node.provision_state = states.DELETING
            node.target_provision_state = states.DELETED
            node.last_error = None
            node.save(context)

            # Start requested action in the background.
            thread = self._spawn_worker(self._do_node_tear_down, context, task)

            # Release node lock at the end.
            thread.link(lambda t: task.release_resources())

        except Exception:
            with excutils.save_and_reraise_exception():
                # Release node lock if error occurred.
                task.release_resources()
示例#44
0
    def __init__(self, context, node_id, shared=False, driver_name=None):
        """Create a new TaskManager.

        Acquire a lock on a node. The lock can be either shared or
        exclusive. Shared locks may be used for read-only or
        non-disruptive actions only, and must be considerate to what
        other threads may be doing on the same node at the same time.

        :param context: request context
        :param node_id: ID or UUID of node to lock.
        :param shared: Boolean indicating whether to take a shared or exclusive
                       lock. Default: False.
        :param driver_name: The name of the driver to load, if different
                            from the Node's current driver.
        :raises: DriverNotFound
        :raises: NodeNotFound
        :raises: NodeLocked

        """

        self._dbapi = dbapi.get_instance()
        self._spawn_method = None
        self._on_error_method = None

        self.context = context
        self.node = None
        self.shared = shared

        # NodeLocked exceptions can be annoying. Let's try to alleviate
        # some of that pain by retrying our lock attempts. The retrying
        # module expects a wait_fixed value in milliseconds.
        @retrying.retry(
            retry_on_exception=lambda e: isinstance(e, exception.NodeLocked),
            stop_max_attempt_number=CONF.conductor.node_locked_retry_attempts,
            wait_fixed=CONF.conductor.node_locked_retry_interval * 1000)
        def reserve_node():
            LOG.debug("Attempting to reserve node %(node)s",
                      {'node': node_id})
            self.node = self._dbapi.reserve_node(CONF.host, node_id)

        try:
            if not self.shared:
                reserve_node()
            else:
                self.node = objects.Node.get(context, node_id)
            self.ports = self._dbapi.get_ports_by_node_id(self.node.id)
            self.driver = driver_factory.get_driver(driver_name or
                                                    self.node.driver)
        except Exception:
            with excutils.save_and_reraise_exception():
                self.release_resources()
示例#45
0
文件: node.py 项目: mshabdiz/ironic
    def patch(self, node_uuid, patch):
        """Update an existing node.

        :param node_uuid: UUID of a node.
        :param patch: a json PATCH document to apply to this node.
        """
        if self._from_chassis:
            raise exception.OperationNotPermitted

        rpc_node = objects.Node.get_by_uuid(pecan.request.context, node_uuid)

        # Check if node is transitioning state
        if rpc_node['target_power_state'] or \
             rpc_node['target_provision_state']:
            msg = _("Node %s can not be updated while a state transition "
                    "is in progress.")
            raise wsme.exc.ClientSideError(msg % node_uuid, status_code=409)

        try:
            node = Node(**jsonpatch.apply_patch(rpc_node.as_dict(),
                                                jsonpatch.JsonPatch(patch)))
        except api_utils.JSONPATCH_EXCEPTIONS as e:
            raise exception.PatchError(patch=patch, reason=e)

        # Update only the fields that have changed
        for field in objects.Node.fields:
            if rpc_node[field] != getattr(node, field):
                rpc_node[field] = getattr(node, field)

        # NOTE(deva): we calculate the rpc topic here in case node.driver
        #             has changed, so that update is sent to the
        #             new conductor, not the old one which may fail to
        #             load the new driver.
        try:
            topic = pecan.request.rpcapi.get_topic_for(rpc_node)
        except exception.NoValidHost as e:
            # NOTE(deva): convert from 404 to 400 because client can see
            #             list of available drivers and shouldn't request
            #             one that doesn't exist.
            e.code = 400
            raise e

        try:
            new_node = pecan.request.rpcapi.update_node(
                    pecan.request.context, rpc_node, topic)
        except Exception as e:
            with excutils.save_and_reraise_exception():
                LOG.exception(e)

        return Node.convert_with_links(new_node)
示例#46
0
文件: port.py 项目: mshabdiz/ironic
    def post(self, port):
        """Create a new port.

        :param port: a port within the request body.
        """
        if self._from_nodes:
            raise exception.OperationNotPermitted

        try:
            new_port = pecan.request.dbapi.create_port(port.as_dict())
        except Exception as e:
            with excutils.save_and_reraise_exception():
                LOG.exception(e)
        return Port.convert_with_links(new_port)
示例#47
0
def work_on_disk(dev, root_mb, swap_mb, ephemeral_mb, ephemeral_format,
                 image_path, preserve_ephemeral=False):
    """Create partitions and copy an image to the root partition.

    :param dev: Path for the device to work on.
    :param root_mb: Size of the root partition in megabytes.
    :param swap_mb: Size of the swap partition in megabytes.
    :param ephemeral_mb: Size of the ephemeral partition in megabytes. If 0,
        no ephemeral partition will be created.
    :param ephemeral_format: The type of file system to format the ephemeral
        partition.
    :param image_path: Path for the instance's disk image.
    :param preserve_ephemeral: If True, no filesystem is written to the
        ephemeral block device, preserving whatever content it had (if the
        partition table has not changed).

    """
    if not is_block_device(dev):
        raise exception.InstanceDeployFailure(_("Parent device '%s' not found")
                                              % dev)

    part_dict = make_partitions(dev, root_mb, swap_mb, ephemeral_mb)
    ephemeral_part = part_dict.get('ephemeral')
    swap_part = part_dict.get('swap')
    root_part = part_dict.get('root')

    if not is_block_device(root_part):
        raise exception.InstanceDeployFailure(_("Root device '%s' not found")
                                              % root_part)
    if swap_part and not is_block_device(swap_part):
        raise exception.InstanceDeployFailure(_("Swap device '%s' not found")
                                              % swap_part)
    if ephemeral_part and not is_block_device(ephemeral_part):
        raise exception.InstanceDeployFailure(
                         _("Ephemeral device '%s' not found") % ephemeral_part)

    dd(image_path, root_part)

    if swap_part:
        mkswap(swap_part)

    if ephemeral_part and not preserve_ephemeral:
        mkfs_ephemeral(ephemeral_part, ephemeral_format)

    try:
        root_uuid = block_uuid(root_part)
    except processutils.ProcessExecutionError:
        with excutils.save_and_reraise_exception():
            LOG.error(_("Failed to detect root device UUID."))
    return root_uuid
示例#48
0
    def post(self, port):
        """Create a new port.

        :param port: a port within the request body.
        """
        if self._from_nodes:
            raise exception.OperationNotPermitted

        try:
            new_port = pecan.request.dbapi.create_port(port.as_dict())
        except Exception as e:
            with excutils.save_and_reraise_exception():
                LOG.exception(e)
        return Port.convert_with_links(new_port)
示例#49
0
文件: node.py 项目: mshabdiz/ironic
    def patch(self, node_uuid, patch):
        """Update an existing node.

        :param node_uuid: UUID of a node.
        :param patch: a json PATCH document to apply to this node.
        """
        if self._from_chassis:
            raise exception.OperationNotPermitted

        rpc_node = objects.Node.get_by_uuid(pecan.request.context, node_uuid)

        # Check if node is transitioning state
        if rpc_node['target_power_state'] or \
             rpc_node['target_provision_state']:
            msg = _("Node %s can not be updated while a state transition "
                    "is in progress.")
            raise wsme.exc.ClientSideError(msg % node_uuid, status_code=409)

        try:
            node = Node(**jsonpatch.apply_patch(rpc_node.as_dict(),
                                                jsonpatch.JsonPatch(patch)))
        except api_utils.JSONPATCH_EXCEPTIONS as e:
            raise exception.PatchError(patch=patch, reason=e)

        # Update only the fields that have changed
        for field in objects.Node.fields:
            if rpc_node[field] != getattr(node, field):
                rpc_node[field] = getattr(node, field)

        # NOTE(deva): we calculate the rpc topic here in case node.driver
        #             has changed, so that update is sent to the
        #             new conductor, not the old one which may fail to
        #             load the new driver.
        try:
            topic = pecan.request.rpcapi.get_topic_for(rpc_node)
        except exception.NoValidHost as e:
            # NOTE(deva): convert from 404 to 400 because client can see
            #             list of available drivers and shouldn't request
            #             one that doesn't exist.
            e.code = 400
            raise e

        try:
            new_node = pecan.request.rpcapi.update_node(
                pecan.request.context, rpc_node, topic)
        except Exception as e:
            with excutils.save_and_reraise_exception():
                LOG.exception(e)

        return Node.convert_with_links(new_node)
示例#50
0
文件: node.py 项目: Haomeng/ironic
    def post(self, node):
        """Create a new node.

        :param node: a node within the request body.
        """
        if self._from_chassis:
            raise exception.OperationNotPermitted

        try:
            new_node = pecan.request.dbapi.create_node(node.as_dict())
        except Exception as e:
            with excutils.save_and_reraise_exception():
                LOG.exception(e)
        return Node.convert_with_links(new_node)
示例#51
0
    def __init__(self, context, node_ids, shared=False, driver_name=None):
        """Create a new TaskManager.

        Acquire a lock atomically on a non-empty set of nodes. The lock
        can be either shared or exclusive. Shared locks may be used for
        read-only or non-disruptive actions only, and must be considerate
        to what other threads may be doing on the nodes at the same time.

        :param context: request context
        :param node_ids: A list of ids or uuids of nodes to lock.
        :param shared: Boolean indicating whether to take a shared or exclusive
                       lock. Default: False.
        :param driver_name: The name of the driver to load, if different
                            from the Node's current driver.
        :raises: DriverNotFound
        :raises: NodeAlreadyLocked

        """

        self.context = context
        self.resources = []
        self.shared = shared
        self.dbapi = dbapi.get_instance()
        self._spawn_method = None

        # instead of generating an exception, DTRT and convert to a list
        if not isinstance(node_ids, list):
            node_ids = [node_ids]

        locked_node_list = []
        try:
            for id in node_ids:
                if not self.shared:
                    # NOTE(deva): Only lock one node at a time so we can ensure
                    #             that only the right nodes are unlocked.
                    #             However, reserve_nodes takes and returns a
                    #             list. This should be refactored.
                    node = self.dbapi.reserve_nodes(CONF.host, [id])[0]
                    locked_node_list.append(node.id)
                else:
                    node = objects.Node.get(context, id)
                ports = self.dbapi.get_ports_by_node_id(node.id)
                driver = driver_factory.get_driver(driver_name or node.driver)

                self.resources.append(NodeResource(node, ports, driver))
        except Exception:
            with excutils.save_and_reraise_exception():
                if locked_node_list:
                    self.dbapi.release_nodes(CONF.host, locked_node_list)
示例#52
0
    def vendor_passthru(self, context, node_id, driver_method, info):
        """RPC method to encapsulate vendor action.

        Synchronously validate driver specific info or get driver status,
        and if successful, start background worker to perform vendor action
        asynchronously.

        :param context: an admin context.
        :param node_id: the id or uuid of a node.
        :param driver_method: the name of the vendor method.
        :param info: vendor method args.
        :raises: InvalidParameterValue if supplied info is not valid.
        :raises: UnsupportedDriverExtension if current driver does not have
                 vendor interface or method is unsupported.
        :raises: NoFreeConductorWorker when there is no free worker to start
                 async task.

        """
        LOG.debug(_("RPC vendor_passthru called for node %s.") % node_id)
        # NOTE(max_lobur): Even though not all vendor_passthru calls may
        # require an exclusive lock, we need to do so to guarantee that the
        # state doesn't unexpectedly change between doing a vendor.validate
        # and vendor.vendor_passthru.
        task = task_manager.TaskManager(context, node_id, shared=False)

        try:
            if not getattr(task.driver, 'vendor', None):
                raise exception.UnsupportedDriverExtension(
                    driver=task.node.driver, extension='vendor passthru')

            task.driver.vendor.validate(task,
                                        task.node,
                                        method=driver_method,
                                        **info)
            # Start requested action in the background.
            thread = self._spawn_worker(task.driver.vendor.vendor_passthru,
                                        task,
                                        task.node,
                                        method=driver_method,
                                        **info)
            # Release node lock at the end of async action.
            thread.link(lambda t: task.release_resources())
        except Exception:
            with excutils.save_and_reraise_exception():
                # Release node lock if error occurred.
                task.release_resources()
示例#53
0
文件: ipmitool.py 项目: nkaul/ironic
def _make_password_file(password):
    """Makes a temporary file that contains the password.

    :param password: the password
    :returns: the absolute pathname of the temporary file
    :raises: Exception from creating or writing to the temporary file
    """
    try:
        fd, path = tempfile.mkstemp()
        os.fchmod(fd, stat.S_IRUSR | stat.S_IWUSR)
        with os.fdopen(fd, "w") as f:
            f.write(password)

        yield path
        utils.delete_if_exists(path)
    except Exception:
        with excutils.save_and_reraise_exception():
            utils.delete_if_exists(path)
示例#54
0
文件: amqp.py 项目: schatt/ironic
 def __iter__(self):
     """Return a result until we get a 'None' response from consumer"""
     if self._done:
         raise StopIteration
     while True:
         try:
             self._iterator.next()
         except Exception:
             with excutils.save_and_reraise_exception():
                 self.done()
         if self._got_ending:
             self.done()
             raise StopIteration
         result = self._result
         if isinstance(result, Exception):
             self.done()
             raise result
         yield result
示例#55
0
    def validate_vendor_action(self, context, node_id, driver_method, info):
        """Validate driver specific info or get driver status."""

        LOG.debug(
            _("RPC validate_vendor_action called for node %s.") % node_id)
        with task_manager.acquire(context, node_id, shared=True) as task:
            try:
                if getattr(task.driver, 'vendor', None):
                    return task.driver.vendor.validate(task,
                                                       task.node,
                                                       method=driver_method,
                                                       **info)
                else:
                    raise exception.UnsupportedDriverExtension(
                        driver=task.node.driver, extension='vendor passthru')
            except Exception as e:
                with excutils.save_and_reraise_exception():
                    task.node.last_error = \
                        _("Failed to validate vendor info. Error: %s") % e
                    task.node.save(context)
示例#56
0
文件: amqp.py 项目: schatt/ironic
 def __iter__(self):
     """Return a result until we get a reply with an 'ending" flag"""
     if self._done:
         raise StopIteration
     while True:
         try:
             data = self._dataqueue.get(timeout=self._timeout)
             result = self._process_data(data)
         except queue.Empty:
             self.done()
             raise rpc_common.Timeout()
         except Exception:
             with excutils.save_and_reraise_exception():
                 self.done()
         if self._got_ending:
             self.done()
             raise StopIteration
         if isinstance(result, Exception):
             self.done()
             raise result
         yield result