Пример #1
0
def _parse_root_device_hints(node):
    """Convert string with hints to dict. """
    root_device = node.properties.get('root_device')
    if not root_device:
        return {}
    try:
        parsed_hints = irlib_utils.parse_root_device_hints(root_device)
    except ValueError as e:
        raise exception.InvalidParameterValue(
            _('Failed to validate the root device hints for node %(node)s. '
              'Error: %(error)s') % {'node': node.uuid, 'error': e})
    root_device_hints = {}
    advanced = {}
    for hint, value in parsed_hints.items():
        if isinstance(value, six.string_types):
            if value.startswith('== '):
                root_device_hints[hint] = int(value[3:])
            elif value.startswith('s== '):
                root_device_hints[hint] = urlparse.unquote(value[4:])
            else:
                advanced[hint] = value
        else:
            root_device_hints[hint] = value
    if advanced:
        raise exception.InvalidParameterValue(
            _('Ansible-deploy does not support advanced root device hints '
              'based on oslo.utils operators. '
              'Present advanced hints for node %(node)s are %(hints)s.') % {
                  'node': node.uuid, 'hints': advanced})
    return root_device_hints
Пример #2
0
def _validate(task):
    """Validate the prerequisites for virtual media based deploy.

    This method validates whether the 'driver_info' property of the
    supplied node contains the required information for this driver.

    :param task: a TaskManager instance containing the node to act on.
    :raises: InvalidParameterValue if any parameters are incorrect
    :raises: MissingParameterValue if some mandatory information
        is missing on the node
    """
    node = task.node
    ilo_common.parse_driver_info(node)
    if 'ilo_deploy_iso' not in node.driver_info:
        raise exception.MissingParameterValue(_(
            "Missing 'ilo_deploy_iso' parameter in node's 'driver_info'."))
    deploy_iso = node.driver_info['ilo_deploy_iso']
    if not service_utils.is_glance_image(deploy_iso):
        try:
            image_service.HttpImageService().validate_href(deploy_iso)
        except exception.ImageRefValidationFailed:
            raise exception.InvalidParameterValue(_(
                "Virtual media deploy accepts only Glance images or "
                "HTTP(S) as driver_info['ilo_deploy_iso']. Either '%s' "
                "is not a glance UUID or not a valid HTTP(S) URL or "
                "the given URL is not reachable.") % deploy_iso)
Пример #3
0
def _parse_driver_info(node):
    info = node.driver_info or {}
    missing_info = [key for key in REQUIRED_PROPERTIES if not info.get(key)]
    if missing_info:
        raise exception.MissingParameterValue(
            _("Missing the following iBoot credentials in node's"
              " driver_info: %s.") % missing_info)

    address = info.get('iboot_address', None)
    username = info.get('iboot_username', None)
    password = info.get('iboot_password', None)

    relay_id = info.get('iboot_relay_id', 1)
    try:
        relay_id = int(relay_id)
    except ValueError:
        raise exception.InvalidParameterValue(
            _("iBoot PDU relay id must be an integer."))

    port = info.get('iboot_port', 9100)
    try:
        port = int(port)
    except ValueError:
        raise exception.InvalidParameterValue(
            _("iBoot PDU port must be an integer."))

    return {
        'address': address,
        'username': username,
        'password': password,
        'port': port,
        'relay_id': relay_id,
        'uuid': node.uuid,
    }
Пример #4
0
def _validate_clean_steps(steps, node_uuid):
    missing = []
    for step in steps:
        name = step.get('name')
        if not name:
            missing.append({'name': 'undefined', 'field': 'name'})
            continue
        if 'interface' not in step:
            missing.append({'name': name, 'field': 'interface'})
        args = step.get('args', {})
        for arg_name, arg in args.items():
            if arg.get('required', False) and 'value' not in arg:
                missing.append({'name': name,
                                'field': '%s.value' % arg_name})
    if missing:
        err_string = ', '.join(
            'name %(name)s, field %(field)s' % i for i in missing)
        msg = _("Malformed clean_steps file: %s") % err_string
        LOG.error(msg)
        raise exception.NodeCleaningFailure(node=node_uuid,
                                            reason=msg)
    if len(set(s['name'] for s in steps)) != len(steps):
        msg = _("Cleaning steps do not have unique names.")
        LOG.error(msg)
        raise exception.NodeCleaningFailure(node=node_uuid,
                                            reason=msg)
Пример #5
0
    def delete_cleaning_ports(self, task):
        """Deletes the neutron port created for booting the ramdisk.

        :param task: a TaskManager instance.
        """
        neutron_client = _build_client(task.context.auth_token)
        macs = [p.address for p in task.ports]
        params = {
            'network_id': CONF.neutron.cleaning_network_uuid
        }
        try:
            ports = neutron_client.list_ports(**params)
        except neutron_client_exc.ConnectionFailed as e:
            msg = (_('Could not get cleaning network vif for %(node)s '
                     'from Neutron, possible network issue. %(exc)s') %
                   {'node': task.node.uuid,
                    'exc': e})
            LOG.exception(msg)
            raise exception.NodeCleaningFailure(msg)

        # Iterate the list of Neutron port dicts, remove the ones we added
        for neutron_port in ports.get('ports', []):
            # Only delete ports using the node's mac addresses
            if neutron_port.get('mac_address') in macs:
                try:
                    neutron_client.delete_port(neutron_port.get('id'))
                except neutron_client_exc.ConnectionFailed as e:
                    msg = (_('Could not remove cleaning ports on network '
                             '%(net)s from %(node)s, possible network issue. '
                             '%(exc)s') %
                           {'net': CONF.neutron.cleaning_network_uuid,
                            'node': task.node.uuid,
                            'exc': e})
                    LOG.exception(msg)
                    raise exception.NodeCleaningFailure(msg)
Пример #6
0
def _parse_driver_info(node):
    """Gets the information needed for accessing the node.

    :param node: the Node object.
    :returns: dictionary of information.
    :raises: InvalidParameterValue if any required parameters are incorrect.
    :raises: MissingParameterValue if any required parameters are missing.

    """
    info = node.driver_info
    d_info = {}
    error_msgs = []

    d_info['username'] = info.get('fuel_username', 'root')
    d_info['key_filename'] = info.get('fuel_key_filename',
                                      '/etc/ironic/fuel_key')

    if not os.path.isfile(d_info['key_filename']):
        error_msgs.append(_("SSH key file %s not found.") %
                          d_info['key_filename'])

    try:
        d_info['port'] = int(info.get('fuel_ssh_port', 22))
    except ValueError:
        error_msgs.append(_("'fuel_ssh_port' must be an integer."))

    if error_msgs:
        msg = (_('The following errors were encountered while parsing '
                 'driver_info:\n%s') % '\n'.join(error_msgs))
        raise exception.InvalidParameterValue(msg)

    d_info['script'] = info.get('fuel_deploy_script', 'provision')

    return d_info
Пример #7
0
    def _wait(node_uuid, popen_obj):
        locals['returncode'] = popen_obj.poll()

        # check if the console pid is created and the process is running.
        # if it is, then the shellinaboxd is invoked successfully as a daemon.
        # otherwise check the error.
        if locals['returncode'] is not None:
            if (locals['returncode'] == 0 and os.path.exists(pid_file) and
                psutil.pid_exists(_get_console_pid(node_uuid))):
                raise loopingcall.LoopingCallDone()
            else:
                (stdout, stderr) = popen_obj.communicate()
                locals['errstr'] = _(
                    "Command: %(command)s.\n"
                    "Exit code: %(return_code)s.\n"
                    "Stdout: %(stdout)r\n"
                    "Stderr: %(stderr)r") % {
                        'command': ' '.join(args),
                        'return_code': locals['returncode'],
                        'stdout': stdout,
                        'stderr': stderr}
                LOG.warning(locals['errstr'])
                raise loopingcall.LoopingCallDone()

        if (time.time() > expiration):
            locals['errstr'] = _("Timeout while waiting for console subprocess"
                                 "to start for node %s.") % node_uuid
            LOG.warning(locals['errstr'])
            raise loopingcall.LoopingCallDone()
Пример #8
0
def validate_pass_bootloader_info_input(task, input_params):
    """Validates the input sent with bootloader install info passthru.

    This method validates the input sent with bootloader install info
    passthru.

    :param task: A TaskManager object.
    :param input_params: A dictionary of params sent as input to passthru.
    :raises: InvalidParameterValue, if deploy key passed doesn't match the
        one stored in instance_info.
    :raises: MissingParameterValue, if some input is missing.
    """
    params = {
        "address": input_params.get("address"),
        "key": input_params.get("key"),
        "status": input_params.get("status"),
    }
    msg = _("Some mandatory input missing in 'pass_bootloader_info' " "vendor passthru from ramdisk.")
    deploy_utils.check_for_missing_params(params, msg)

    deploy_key = task.node.instance_info["deploy_key"]
    if deploy_key != input_params.get("key"):
        raise exception.InvalidParameterValue(
            _("Deploy key %(key_sent)s does not match " "with %(expected_key)s")
            % {"key_sent": input_params.get("key"), "expected_key": deploy_key}
        )
Пример #9
0
def validate_image_proxies(node):
    """Check that the provided proxy parameters are valid.

    :param node: an Ironic node.
    :raises: InvalidParameterValue if any of the provided proxy parameters are
        incorrect.
    """
    invalid_proxies = {}
    for scheme in ('http', 'https'):
        proxy_param = 'image_%s_proxy' % scheme
        proxy = node.driver_info.get(proxy_param)
        if proxy:
            chunks = urlparse.urlparse(proxy)
            # NOTE(vdrok) If no scheme specified, this is still a valid
            # proxy address. It is also possible for a proxy to have a
            # scheme different from the one specified in the image URL,
            # e.g. it is possible to use https:// proxy for downloading
            # http:// image.
            if chunks.scheme not in ('', 'http', 'https'):
                invalid_proxies[proxy_param] = proxy
    msg = ''
    if invalid_proxies:
        msg += _("Proxy URL should either have HTTP(S) scheme "
                 "or no scheme at all, the following URLs are "
                 "invalid: %s.") % invalid_proxies
    no_proxy = node.driver_info.get('image_no_proxy')
    if no_proxy is not None and not utils.is_valid_no_proxy(no_proxy):
        msg += _(
            "image_no_proxy should be a list of host names, IP addresses "
            "or domain names to exclude from proxying, the specified list "
            "%s is incorrect. To denote a domain name, prefix it with a dot "
            "(instead of e.g. '.*').") % no_proxy
    if msg:
        raise exception.InvalidParameterValue(msg)
Пример #10
0
    def create_cleaning_ports(self, task):
        """Create neutron ports for each port on task.node to boot the ramdisk.

        :param task: a TaskManager instance.
        :raises: InvalidParameterValue if the cleaning network is None
        :returns: a dictionary in the form {port.uuid: neutron_port['id']}
        """
        if not CONF.neutron.cleaning_network_uuid:
            raise exception.InvalidParameterValue(_("Valid cleaning network " "UUID not provided"))
        neutron_client = _build_client(task.context.auth_token)
        body = {"port": {"network_id": CONF.neutron.cleaning_network_uuid, "admin_state_up": True}}
        ports = {}
        for ironic_port in task.ports:
            body["port"]["mac_address"] = ironic_port.address
            try:
                port = neutron_client.create_port(body)
            except neutron_client_exc.ConnectionFailed as e:
                self._rollback_cleaning_ports(task)
                msg = _("Could not create cleaning port on network %(net)s " "from %(node)s. %(exc)s") % {
                    "net": CONF.neutron.cleaning_network_uuid,
                    "node": task.node.uuid,
                    "exc": e,
                }
                LOG.exception(msg)
                raise exception.NodeCleaningFailure(msg)
            if not port.get("port") or not port["port"].get("id"):
                self._rollback_cleaning_ports(task)
                msg = _("Failed to create cleaning ports for node " "%(node)s") % {"node": task.node.uuid}
                LOG.error(msg)
                raise exception.NodeCleaningFailure(msg)
            # Match return value of get_node_vif_ids()
            ports[ironic_port.uuid] = port["port"]["id"]
        return ports
Пример #11
0
def _check_disk_layout_unchanged(node, i_info):
    """Check whether disk layout is unchanged.

    If the node has already been deployed to, this checks whether the disk
    layout for the node is the same as when it had been deployed to.

    :param node: the node of interest
    :param i_info: instance information (a dictionary) for the node, containing
                   disk layout information
    :raises: InvalidParameterValue if the disk layout changed
    """
    # If a node has been deployed to, this is the instance information
    # used for that deployment.
    driver_internal_info = node.driver_internal_info
    if "instance" not in driver_internal_info:
        return

    error_msg = ""
    for param in DISK_LAYOUT_PARAMS:
        param_value = int(driver_internal_info["instance"][param])
        if param_value != int(i_info[param]):
            error_msg += _(
                " Deployed value of %(param)s was %(param_value)s " "but requested value is %(request_value)s."
            ) % {"param": param, "param_value": param_value, "request_value": i_info[param]}

    if error_msg:
        err_msg_invalid = _("The following parameters have different values " "from previous deployment:%(error_msg)s")
        raise exception.InvalidParameterValue(err_msg_invalid % {"error_msg": error_msg})
Пример #12
0
    def _validate_lan_port(self, node, port):
        """Validate ports for VIOM configuration.

        Physical information of LAN ports must be registered to VIOM
        configuration to activate them under VIOM management. The information
        has to be set to "irmc_pci_physical_id" parameter in a nodes
        driver_info.

        :param node: an ironic node object
        :param port: a port to be validated
        :raises: MissingParameterValue if a physical ID of the port is not set.
        :raises: InvalidParameterValue if a physical ID is invalid.
        """
        physical_id = node.driver_info['irmc_pci_physical_ids'].get(port.uuid)
        if not physical_id:
            raise exception.MissingParameterValue(
                _('Failed to validate for node %(node)s because of '
                  'missing physical port information of port %(port)s. '
                  'This information should be contained in '
                  '"pci_physical_ids" parameter of node\'s driver_info.') %
                {'node': node.uuid,
                 'port': port.uuid})
        try:
            viom.validate_physical_port_id(physical_id)
        except scci.SCCIInvalidInputError as e:
            raise exception.InvalidParameterValue(
                _('Failed to validate for node %(node)s because '
                  'the physical port ID for port %(port)s in node\'s'
                  ' driver_info is invalid: %(reason)s') %
                {'node': node.uuid,
                 'port': port.uuid,
                 'reason': e})
Пример #13
0
    def process_event(self, event):
        """Trigger a state change in response to the provided event."""
        current = self._current
        if current is None:
            raise excp.InvalidState(_("Can only process events after"
                                      " being initialized (not before)"))
        if self._states[current.name]['terminal']:
            raise excp.InvalidState(
                _("Can not transition from terminal "
                  "state '%(state)s' on event '%(event)s'")
                % {'state': current.name, 'event': event})
        if event not in self._transitions[current.name]:
            raise excp.InvalidState(
                _("Can not transition from state '%(state)s' on "
                  "event '%(event)s' (no defined transition)")
                % {'state': current.name, 'event': event})
        replacement = self._transitions[current.name][event]
        if current.on_exit is not None:
            current.on_exit(current.name, event)
        if replacement.on_enter is not None:
            replacement.on_enter(replacement.name, event)
        self._current = replacement

        # clear _target if we've reached it
        if (self._target_state is not None and
                self._target_state == replacement.name):
            self._target_state = None
        # if new state has a different target, update the target
        if self._states[replacement.name]['target'] is not None:
            self._target_state = self._states[replacement.name]['target']
Пример #14
0
def cleanup_after_timeout(task):
    """Cleanup deploy task after timeout.

    :param task: a TaskManager instance.
    """
    node = task.node
    msg = (_('Timeout reached while waiting for callback for node %s')
             % node.uuid)
    node.last_error = msg
    LOG.error(msg)
    node.save()

    error_msg = _('Cleanup failed for node %(node)s after deploy timeout: '
                  ' %(error)s')
    try:
        task.driver.deploy.clean_up(task)
    except exception.IronicException as e:
        msg = error_msg % {'node': node.uuid, 'error': e}
        LOG.error(msg)
        node.last_error = msg
        node.save()
    except Exception as e:
        msg = error_msg % {'node': node.uuid, 'error': e}
        LOG.error(msg)
        node.last_error = _('Deploy timed out, but an unhandled exception was '
                            'encountered while aborting. More info may be '
                            'found in the log file.')
        node.save()
Пример #15
0
    def create_object(self, container, object, filename,
                      object_headers=None):
        """Uploads a given file to Swift.

        :param container: The name of the container for the object.
        :param object: The name of the object in Swift
        :param filename: The file to upload, as the object data
        :param object_headers: the headers for the object to pass to Swift
        :returns: The Swift UUID of the object
        :raises: SwiftOperationError, if any operation with Swift fails.
        """
        try:
            self.connection.put_container(container)
        except swift_exceptions.ClientException as e:
            operation = _("put container")
            raise exception.SwiftOperationError(operation=operation, error=e)

        with open(filename, "r") as fileobj:

            try:
                obj_uuid = self.connection.put_object(container,
                                                      object,
                                                      fileobj,
                                                      headers=object_headers)
            except swift_exceptions.ClientException as e:
                operation = _("put object")
                raise exception.SwiftOperationError(operation=operation,
                                                    error=e)

        return obj_uuid
Пример #16
0
    def validate(self, task, **kwargs):
        """Validate vendor-specific actions.

        If invalid, raises an exception; otherwise returns None.

        Valid methods:
          * send_raw
          * bmc_reset

        :param task: a task from TaskManager.
        :param kwargs: info for action.
        :raises: InvalidParameterValue if kwargs does not contain 'method',
                 'method' is not supported or a byte string is not given for
                 'raw_bytes'.
        :raises: MissingParameterValue if a required parameter is missing.

        """
        method = kwargs['method']
        if method == 'send_raw':
            if not kwargs.get('raw_bytes'):
                raise exception.InvalidParameterValue(_(
                    'Parameter raw_bytes (string of bytes) was not '
                    'specified.'))
        elif method == 'bmc_reset':
            # no additional parameters needed
            pass
        else:
            raise exception.InvalidParameterValue(_(
                "Unsupported method (%s) passed to IPMItool driver.")
                % method)
        _parse_driver_info(task.node)
Пример #17
0
def _parse_driver_info(node):
    """Gets the driver specific Node deployment info.

    This method validates whether the 'driver_info' property of the
    supplied node contains the required or optional information properly
    for this driver to deploy images to the node.

    :param node: a target node of the deployment
    :returns: the driver_info values of the node.
    :raises: MissingParameterValue, if any of the required parameters are
        missing.
    :raises: InvalidParameterValue, if any of the parameters have invalid
        value.
    """
    d_info = node.driver_info
    deploy_info = {}

    deploy_info["irmc_deploy_iso"] = d_info.get("irmc_deploy_iso")
    error_msg = _("Error validating iRMC virtual media deploy. Some parameters" " were missing in node's driver_info")
    deploy_utils.check_for_missing_params(deploy_info, error_msg)

    if service_utils.is_image_href_ordinary_file_name(deploy_info["irmc_deploy_iso"]):
        deploy_iso = os.path.join(CONF.irmc.remote_image_share_root, deploy_info["irmc_deploy_iso"])
        if not os.path.isfile(deploy_iso):
            msg = _("Deploy ISO file, %(deploy_iso)s, " "not found for node: %(node)s.") % {
                "deploy_iso": deploy_iso,
                "node": node.uuid,
            }
            raise exception.InvalidParameterValue(msg)

    return deploy_info
Пример #18
0
def validate(task):
    """Validates the pre-requisites for iSCSI deploy.

    Validates whether node in the task provided has some ports enrolled.
    This method validates whether conductor url is available either from CONF
    file or from keystone.

    :param task: a TaskManager instance containing the node to act on.
    :raises: InvalidParameterValue if the URL of the Ironic API service is not
             configured in config file and is not accessible via Keystone
             catalog.
    :raises: MissingParameterValue if no ports are enrolled for the given node.
    """
    node = task.node
    if not driver_utils.get_node_mac_addresses(task):
        raise exception.MissingParameterValue(_("Node %s does not have " "any port associated with it.") % node.uuid)

    try:
        # TODO(lucasagomes): Validate the format of the URL
        CONF.conductor.api_url or keystone.get_service_url()
    except (exception.KeystoneFailure, exception.CatalogNotFound, exception.KeystoneUnauthorized) as e:
        raise exception.InvalidParameterValue(
            _(
                "Couldn't get the URL of the Ironic API service from the "
                "configuration file or keystone catalog. Keystone error: %s"
            )
            % e
        )

    # Validate the root device hints
    deploy_utils.parse_root_device_hints(node)
Пример #19
0
def get_image_service(image_href, client=None, context=None):
    """Get image service instance to download the image.

    :param image_href: String containing href to get image service for.
    :param client: Glance client to be used for download, used only if
        image_href is Glance href.
    :param context: request context, used only if image_href is Glance href.
    :raises: exception.ImageRefValidationFailed if no image service can
        handle specified href.
    :returns: Instance of an image service class that is able to download
        specified image.
    """
    scheme = urlparse.urlparse(image_href).scheme.lower()

    if not scheme:
        if uuidutils.is_uuid_like(six.text_type(image_href)):
            cls = GlanceImageService
        else:
            raise exception.ImageRefValidationFailed(
                image_href=image_href,
                reason=_('Scheme-less image href is not a UUID.'))
    else:
        cls = protocol_mapping.get(scheme)
        if not cls:
            raise exception.ImageRefValidationFailed(
                image_href=image_href,
                reason=_('Image download protocol %s is not supported.'
                         ) % scheme)

    if cls == GlanceImageService:
        return cls(client, context)
    return cls()
Пример #20
0
def _execute_ilo_clean_step(node, step, *args, **kwargs):
    """Executes a particular clean step.

    :param node: an Ironic node object.
    :param step: a clean step to be executed.
    :param args: The args to be passed to the clean step.
    :param kwargs: The kwargs to be passed to the clean step.
    :raises: NodeCleaningFailure, on failure to execute step.
    """
    ilo_object = ilo_common.get_ilo_object(node)

    try:
        clean_step = getattr(ilo_object, step)
    except AttributeError:
        # The specified clean step is not present in the proliantutils
        # package. Raise exception to update the proliantutils package
        # to newer version.
        raise exception.NodeCleaningFailure(
            _("Clean step '%s' not found. 'proliantutils' package needs to be "
              "updated.") % step)
    try:
        clean_step(*args, **kwargs)
    except ilo_error.IloCommandNotSupportedError:
        # This clean step is not supported on Gen8 and below servers.
        # Log the failure and continue with cleaning.
        LOG.warning("'%(step)s' clean step is not supported on node "
                    "%(uuid)s. Skipping the clean step.",
                    {'step': step, 'uuid': node.uuid})
    except ilo_error.IloError as ilo_exception:
        raise exception.NodeCleaningFailure(_(
            "Clean step %(step)s failed "
            "on node %(node)s with error: %(err)s") %
            {'node': node.uuid, 'step': step, 'err': ilo_exception})
Пример #21
0
def parse_instance_info(node):
    """Gets the instance specific Node deployment info.

    This method validates whether the 'instance_info' property of the
    supplied node contains the required information for this driver to
    deploy images to the node.

    :param node: a single Node.
    :returns: A dict with the instance_info values.
    :raises: MissingParameterValue, if any of the required parameters are
        missing.
    :raises: InvalidParameterValue, if any of the parameters have invalid
        value.
    """
    info = node.instance_info
    i_info = {}
    i_info["image_source"] = info.get("image_source")
    is_whole_disk_image = node.driver_internal_info.get("is_whole_disk_image")
    if not is_whole_disk_image:
        if i_info["image_source"] and not glance_service_utils.is_glance_image(i_info["image_source"]):
            i_info["kernel"] = info.get("kernel")
            i_info["ramdisk"] = info.get("ramdisk")
    i_info["root_gb"] = info.get("root_gb")

    error_msg = _("Cannot validate iSCSI deploy. Some parameters were missing" " in node's instance_info")
    deploy_utils.check_for_missing_params(i_info, error_msg)

    # Internal use only
    i_info["deploy_key"] = info.get("deploy_key")

    i_info["swap_mb"] = info.get("swap_mb", 0)
    i_info["ephemeral_gb"] = info.get("ephemeral_gb", 0)
    err_msg_invalid = _(
        "Cannot validate parameter for iSCSI deploy. " "Invalid parameter %(param)s. Reason: %(reason)s"
    )
    for param in ("root_gb", "swap_mb", "ephemeral_gb"):
        try:
            int(i_info[param])
        except ValueError:
            reason = _("%s is not an integer value.") % i_info[param]
            raise exception.InvalidParameterValue(err_msg_invalid % {"param": param, "reason": reason})

    if is_whole_disk_image:
        if int(i_info["swap_mb"]) > 0 or int(i_info["ephemeral_gb"]) > 0:
            err_msg_invalid = _("Cannot deploy whole disk image with " "swap or ephemeral size set")
            raise exception.InvalidParameterValue(err_msg_invalid)
        return i_info

    i_info["ephemeral_format"] = info.get("ephemeral_format")
    i_info["configdrive"] = info.get("configdrive")

    if i_info["ephemeral_gb"] and not i_info["ephemeral_format"]:
        i_info["ephemeral_format"] = CONF.pxe.default_ephemeral_format

    preserve_ephemeral = info.get("preserve_ephemeral", False)
    try:
        i_info["preserve_ephemeral"] = strutils.bool_from_string(preserve_ephemeral, strict=True)
    except ValueError as e:
        raise exception.InvalidParameterValue(err_msg_invalid % {"param": "preserve_ephemeral", "reason": e})
    return i_info
Пример #22
0
def parse_driver_info(node):
    """Parses and creates AMT driver info

    :param node: an Ironic node object.
    :returns: AMT driver info.
    :raises: MissingParameterValue if any required parameters are missing.
    :raises: InvalidParameterValue if any parameters have invalid values.
    """

    info = node.driver_info or {}
    d_info = {}
    missing_info = []

    for param in REQUIRED_PROPERTIES:
        value = info.get(param)
        if value:
            d_info[param[4:]] = six.binary_type(value)
        else:
            missing_info.append(param)

    if missing_info:
        raise exception.MissingParameterValue(
            _("AMT driver requires the following to be set in " "node's driver_info: %s.") % missing_info
        )

    d_info["uuid"] = node.uuid
    param = "amt_protocol"
    protocol = info.get(param, CONF.amt.get(param[4:]))
    if protocol not in AMT_PROTOCOL_PORT_MAP:
        raise exception.InvalidParameterValue(_("Invalid " "protocol %s.") % protocol)
    d_info[param[4:]] = six.binary_type(protocol)

    return d_info
Пример #23
0
def image_to_raw(image_href, path, path_tmp):
    with fileutils.remove_path_on_error(path_tmp):
        data = disk_utils.qemu_img_info(path_tmp)

        fmt = data.file_format
        if fmt is None:
            raise exception.ImageUnacceptable(
                reason=_("'qemu-img info' parsing failed."),
                image_id=image_href)

        backing_file = data.backing_file
        if backing_file is not None:
            raise exception.ImageUnacceptable(
                image_id=image_href,
                reason=_("fmt=%(fmt)s backed by: %(backing_file)s") %
                {'fmt': fmt, 'backing_file': backing_file})

        if fmt != "raw":
            staged = "%s.converted" % path
            LOG.debug("%(image)s was %(format)s, converting to raw" %
                      {'image': image_href, 'format': fmt})
            with fileutils.remove_path_on_error(staged):
                disk_utils.convert_image(path_tmp, staged, 'raw')
                os.unlink(path_tmp)

                data = disk_utils.qemu_img_info(staged)
                if data.file_format != "raw":
                    raise exception.ImageConvertFailed(
                        image_id=image_href,
                        reason=_("Converted to raw, but format is "
                                 "now %s") % data.file_format)

                os.rename(staged, path)
        else:
            os.rename(path_tmp, path)
Пример #24
0
def update_port_address(port_id, address):
    """Update a port's mac address.

    :param port_id: Neutron port id.
    :param address: new MAC address.
    :raises: FailedToUpdateMacOnPort
    """
    client = get_client()
    port_req_body = {'port': {'mac_address': address}}

    try:
        msg = (_("Failed to get the current binding on Neutron "
                 "port %s.") % port_id)
        port = client.show_port(port_id).get('port', {})
        binding_host_id = port.get('binding:host_id')
        binding_profile = port.get('binding:profile')

        if binding_host_id:
            # Unbind port before we update it's mac address, because you can't
            # change a bound port's mac address.
            msg = (_("Failed to remove the current binding from "
                     "Neutron port %s, while updating its MAC "
                     "address.") % port_id)
            unbind_neutron_port(port_id, client=client)
            port_req_body['port']['binding:host_id'] = binding_host_id
            port_req_body['port']['binding:profile'] = binding_profile

        msg = (_("Failed to update MAC address on Neutron port %s.") % port_id)
        client.update_port(port_id, port_req_body)
    except (neutron_exceptions.NeutronClientException, exception.NetworkError):
        LOG.exception(msg)
        raise exception.FailedToUpdateMacOnPort(port_id=port_id)
Пример #25
0
def _verify_security_groups(security_groups, client):
    """Verify that the security groups exist.

    :param security_groups: a list of security group UUIDs; may be None or
        empty
    :param client: Neutron client
    :raises: NetworkError
    """

    if not security_groups:
        return
    try:
        neutron_sec_groups = (
            client.list_security_groups().get('security_groups', []))
    except neutron_exceptions.NeutronClientException as e:
        msg = (_("Could not retrieve security groups from neutron: %(exc)s") %
               {'exc': e})
        LOG.exception(msg)
        raise exception.NetworkError(msg)

    existing_sec_groups = [sec_group['id'] for sec_group in neutron_sec_groups]
    missing_sec_groups = set(security_groups) - set(existing_sec_groups)
    if missing_sec_groups:
        msg = (_('Could not find these security groups (specified via ironic '
                 'config) in neutron: %(ir-sg)s')
               % {'ir-sg': list(missing_sec_groups)})
        LOG.error(msg)
        raise exception.NetworkError(msg)
Пример #26
0
def add_command_parsers(subparsers):
    command_object = DBCommand()

    parser = subparsers.add_parser(
        "upgrade",
        help=_(
            "Upgrade the database schema to the latest version. "
            "Optionally, use --revision to specify an alembic revision "
            "string to upgrade to."
        ),
    )
    parser.set_defaults(func=command_object.upgrade)
    parser.add_argument("--revision", nargs="?")

    parser = subparsers.add_parser("stamp")
    parser.add_argument("--revision", nargs="?")
    parser.set_defaults(func=command_object.stamp)

    parser = subparsers.add_parser(
        "revision", help=_("Create a new alembic revision. " "Use --message to set the message string.")
    )
    parser.add_argument("-m", "--message")
    parser.add_argument("--autogenerate", action="store_true")
    parser.set_defaults(func=command_object.revision)

    parser = subparsers.add_parser("version", help=_("Print the current version information and exit."))
    parser.set_defaults(func=command_object.version)

    parser = subparsers.add_parser("create_schema", help=_("Create the database schema."))
    parser.set_defaults(func=command_object.create_schema)
Пример #27
0
def _set_power_state(task, target_state):
    """Turns the server power on/off or do a reboot.

    :param task: a TaskManager instance containing the node to act on.
    :param target_state: target state of the node.
    :raises: InvalidParameterValue if an invalid power state was specified.
    :raises: MissingParameterValue if some mandatory information
        is missing on the node
    :raises: IRMCOperationError on an error from SCCI
    """

    node = task.node
    irmc_client = irmc_common.get_irmc_client(node)

    if target_state in (states.POWER_ON, states.REBOOT):
        _attach_boot_iso_if_needed(task)

    try:
        irmc_client(STATES_MAP[target_state])

    except KeyError:
        msg = _("_set_power_state called with invalid power state "
                "'%s'") % target_state
        raise exception.InvalidParameterValue(msg)

    except scci.SCCIClientError as irmc_exception:
        LOG.error(_LE("iRMC set_power_state failed to set state to %(tstate)s "
                      " for node %(node_id)s with error: %(error)s"),
                  {'tstate': target_state, 'node_id': node.uuid,
                   'error': irmc_exception})
        operation = _('iRMC set_power_state')
        raise exception.IRMCOperationError(operation=operation,
                                           error=irmc_exception)
Пример #28
0
    def add_state(self, state, on_enter=None, on_exit=None,
            target=None, terminal=None):
        """Adds a given state to the state machine.

        The on_enter and on_exit callbacks, if provided will be expected to
        take two positional parameters, these being the state being exited (for
        on_exit) or the state being entered (for on_enter) and a second
        parameter which is the event that is being processed that caused the
        state transition.
        """
        if state in self._states:
            raise excp.Duplicate(_("State '%s' already defined") % state)
        if on_enter is not None:
            if not six.callable(on_enter):
                raise ValueError(_("On enter callback must be callable"))
        if on_exit is not None:
            if not six.callable(on_exit):
                raise ValueError(_("On exit callback must be callable"))
        if target is not None and target not in self._states:
            raise excp.InvalidState(_("Target state '%s' does not exist")
                    % target)

        self._states[state] = {
            'terminal': bool(terminal),
            'reactions': {},
            'on_enter': on_enter,
            'on_exit': on_exit,
            'target': target,
        }
        self._transitions[state] = OrderedDict()
Пример #29
0
    def _wait(node_uuid, popen_obj):
        wait_state['returncode'] = popen_obj.poll()

        # socat runs in non-daemon mode, so it should not return now
        if wait_state['returncode'] is None:
            # If the pid file is created and the process is running,
            # we stop checking it periodically.
            if (os.path.exists(pid_file) and
                    psutil.pid_exists(_get_console_pid(node_uuid))):
                raise loopingcall.LoopingCallDone()
        else:
            # socat returned, it failed to start.
            # We get the error (out should be None in this case).
            (_out, err) = popen_obj.communicate()
            wait_state['errstr'] = _(
                "Command: %(command)s.\n"
                "Exit code: %(return_code)s.\n"
                "Stderr: %(error)r") % {
                    'command': ' '.join(args),
                    'return_code': wait_state['returncode'],
                    'error': err}
            LOG.error(wait_state['errstr'])
            raise loopingcall.LoopingCallDone()

        if time.time() > expiration:
            wait_state['errstr'] = (_("Timeout while waiting for console "
                                      "subprocess to start for node %s.") %
                                    node_uuid)
            LOG.error(wait_state['errstr'])
            raise loopingcall.LoopingCallDone()
Пример #30
0
def _parse_driver_info(node):
    """Gets the bmc access info for the given node.

    :raises: MissingParameterValue when required ipmi credentials
            are missing.
    :raises: InvalidParameterValue when the IPMI terminal port is not an
            integer.
    """

    info = node.driver_info or {}
    missing_info = [key for key in REQUIRED_PROPERTIES if not info.get(key)]
    if missing_info:
        raise exception.MissingParameterValue(_(
            "Missing the following IPMI credentials in node's"
            " driver_info: %s.") % missing_info)

    bmc_info = {}
    bmc_info['address'] = info.get('ipmi_address')
    bmc_info['username'] = info.get('ipmi_username')
    bmc_info['password'] = info.get('ipmi_password')

    # get additional info
    bmc_info['uuid'] = node.uuid

    # terminal port must be an integer
    port = info.get('ipmi_terminal_port')
    if port is not None:
        try:
            port = int(port)
        except ValueError:
            raise exception.InvalidParameterValue(_(
                "IPMI terminal port is not an integer."))
    bmc_info['port'] = port

    return bmc_info
Пример #31
0
class IBMCError(DriverOperationError):
    _msg_fmt = _("IBMC exception occurred on node %(node)s. Error: %(error)s")
Пример #32
0
 def faultstring(self):
     error = _("Unknown attribute for argument %(argn)s: %(attrs)s")
     if len(self.attributes) > 1:
         error = _("Unknown attributes for argument %(argn)s: %(attrs)s")
     str_attrs = ", ".join(self.attributes)
     return error % {'argn': self.fieldname, 'attrs': str_attrs}
Пример #33
0
class PortgroupAlreadyExists(Conflict):
    _msg_fmt = _("A portgroup with UUID %(uuid)s already exists.")
Пример #34
0
 def faultstring(self):
     return _('Missing argument: "%(argname)s"%(msg)s') % {
         'argname': self.argname,
         'msg': self.msg and ": " + self.msg or ""
     }
Пример #35
0
class NoFreeIPMITerminalPorts(TemporaryFailure):
    _msg_fmt = _("Unable to allocate a free port on host %(host)s for IPMI "
                 "terminal, not enough free ports.")
Пример #36
0
class NodeIsRetired(Invalid):
    _msg_fmt = _("The %(op)s operation can't be performed on node "
                 "%(node)s because it is retired.")
Пример #37
0
class IBMCConnectionError(IBMCError):
    _msg_fmt = _("IBMC connection failed for node %(node)s: %(error)s")
Пример #38
0
class InvalidDeployTemplate(Invalid):
    _msg_fmt = _("Deploy template invalid: %(err)s.")
Пример #39
0
class DeployTemplateAlreadyExists(Conflict):
    _msg_fmt = _("A deploy template with UUID %(uuid)s already exists.")
Пример #40
0
class ChassisAlreadyExists(Conflict):
    _msg_fmt = _("A chassis with UUID %(uuid)s already exists.")
Пример #41
0
class AllocationFailed(IronicException):
    _msg_fmt = _("Failed to process allocation %(uuid)s: %(error)s.")
Пример #42
0
class DeployTemplateNotFound(NotFound):
    _msg_fmt = _("Deploy template %(template)s could not be found.")
Пример #43
0
class AllocationDuplicateName(Conflict):
    _msg_fmt = _("An allocation with name %(name)s already exists.")
Пример #44
0
class DeployTemplateDuplicateName(Conflict):
    _msg_fmt = _("A deploy template with name %(name)s already exists.")
Пример #45
0
class NodeProtected(HTTPForbidden):
    _msg_fmt = _("Node %(node)s is protected and cannot be undeployed, "
                 "rebuilt or deleted")
Пример #46
0
class AllocationAlreadyExists(Conflict):
    _msg_fmt = _("An allocation with UUID %(uuid)s already exists.")
Пример #47
0
class AgentCommandTimeout(IronicException):
    _msg_fmt = _("Timeout executing command %(command)s on node %(node)s")
Пример #48
0
class AllocationNotFound(NotFound):
    _msg_fmt = _("Allocation %(allocation)s could not be found.")
Пример #49
0
class DatabaseVersionTooOld(IronicException):
    _msg_fmt = _("Database version is too old")
Пример #50
0
class MACAlreadyExists(Conflict):
    _msg_fmt = _("A port with MAC address %(mac)s already exists.")
Пример #51
0
class BIOSSettingNotFound(NotFound):
    _msg_fmt = _("Node %(node)s doesn't have a BIOS setting '%(name)s'")
Пример #52
0
class AgentConnectionFailed(IronicException):
    _msg_fmt = _("Connection to agent failed: %(reason)s")
Пример #53
0
class XClarityError(IronicException):
    _msg_fmt = _("XClarity exception occurred. Error: %(error)s")
Пример #54
0
class BIOSSettingListNotFound(NotFound):
    _msg_fmt = _("Node %(node)s doesn't have BIOS settings '%(names)s'")
Пример #55
0
class NodeTraitNotFound(NotFound):
    _msg_fmt = _("Node %(node_id)s doesn't have a trait '%(trait)s'")
Пример #56
0
class BIOSSettingAlreadyExists(Conflict):
    _msg_fmt = _('A BIOS setting %(name)s for node %(node)s already exists.')
Пример #57
0
class AgentAPIError(IronicException):
    _msg_fmt = _('Agent API for node %(node)s returned HTTP status code '
                 '%(status)s with error: %(error)s')
Пример #58
0
class InstanceUnrescueFailure(IronicException):
    _msg_fmt = _('Failed to unrescue instance %(instance)s for node '
                 '%(node)s: %(reason)s')
Пример #59
0
class VifInvalidForAttach(Conflict):
    _msg_fmt = _("Unable to attach VIF %(vif)s to node %(node)s. Reason: "
                 "%(reason)s")
Пример #60
0
class NodeAlreadyExists(Conflict):
    _msg_fmt = _("A node with UUID %(uuid)s already exists.")