Ejemplo n.º 1
0
def check_allowed_portgroup_fields(fields):
    """Check if fetching a particular field of a portgroup is allowed.

    This method checks if the required version is being requested for fields
    that are only allowed to be fetched in a particular API version.
    """
    if fields is None:
        return
    if (('mode' in fields or 'properties' in fields)
            and not allow_portgroup_mode_properties()):
        raise exception.NotAcceptable()
Ejemplo n.º 2
0
def check_allow_driver_detail(detail):
    """Check if getting detailed driver info is allowed.

    Version 1.30 of the API allows this.
    """
    if detail is not None and not allow_dynamic_drivers():
        raise exception.NotAcceptable(_(
            "Request not acceptable. The minimal required API version "
            "should be %(base)s.%(opr)s") %
            {'base': versions.BASE_VERSION,
             'opr': versions.MINOR_30_DYNAMIC_DRIVERS})
Ejemplo n.º 3
0
def check_allowed_fields(fields):
    """Check if fetching a particular field is allowed.

    This method checks if the required version is being requested for fields
    that are only allowed to be fetched in a particular API version.
    """
    if fields is None:
        return
    for field in disallowed_fields():
        if field in fields:
            raise exception.NotAcceptable()
Ejemplo n.º 4
0
def check_allow_filter_driver_type(driver_type):
    """Check if filtering drivers by classic/dynamic is allowed.

    Version 1.30 of the API allows this.
    """
    if driver_type is not None and not allow_dynamic_drivers():
        raise exception.NotAcceptable(_(
            "Request not acceptable. The minimal required API version "
            "should be %(base)s.%(opr)s") %
            {'base': versions.BASE_VERSION,
             'opr': versions.MINOR_30_DYNAMIC_DRIVERS})
Ejemplo n.º 5
0
def check_allow_filter_by_conductor(conductor):
    """Check if filtering nodes by conductor is allowed.

    Version 1.48 of the API allows filtering nodes by conductor.
    """
    if conductor is not None and not allow_expose_conductors():
        raise exception.NotAcceptable(_(
            "Request not acceptable. The minimal required API version "
            "should be %(base)s.%(opr)s") %
            {'base': versions.BASE_VERSION,
             'opr': versions.MINOR_49_CONDUCTORS})
Ejemplo n.º 6
0
    def _check_allowed_port_fields(self, fields):
        """Check if fetching a particular field of a port is allowed.

        Check if the required version is being requested for fields
        that are only allowed to be fetched in a particular API version.

        :param fields: list or set of fields to check
        :raises: NotAcceptable if a field is not allowed
        """
        if fields is None:
            return
        if (not api_utils.allow_port_advanced_net_fields()
                and set(fields).intersection(self.advanced_net_fields)):
            raise exception.NotAcceptable()
        if ('portgroup_uuid' in fields
                and not api_utils.allow_portgroups_subcontrollers()):
            raise exception.NotAcceptable()
        if ('physical_network' in fields
                and not api_utils.allow_port_physical_network()):
            raise exception.NotAcceptable()
Ejemplo n.º 7
0
    def post(self, port):
        """Create a new port.

        :param port: a port within the request body.
        :raises: NotAcceptable, HTTPNotFound, Conflict
        """
        cdict = pecan.request.context.to_dict()
        policy.authorize('baremetal:port:create', cdict, cdict)

        if self.parent_node_ident or self.parent_portgroup_ident:
            raise exception.OperationNotPermitted()

        pdict = port.as_dict()
        if (not api_utils.allow_port_advanced_net_fields() and
                set(pdict).intersection(self.advanced_net_fields)):
            raise exception.NotAcceptable()
        if (not api_utils.allow_portgroups_subcontrollers() and
            'portgroup_uuid' in pdict):
            raise exception.NotAcceptable()

        extra = pdict.get('extra')
        vif = extra.get('vif_port_id') if extra else None
        if (pdict.get('portgroup_uuid') and
                (pdict.get('pxe_enabled') or vif)):
            rpc_pg = objects.Portgroup.get_by_uuid(pecan.request.context,
                                                   pdict['portgroup_uuid'])
            if not rpc_pg.standalone_ports_supported:
                msg = _("Port group %s doesn't support standalone ports. "
                        "This port cannot be created as a member of that "
                        "port group because either 'extra/vif_port_id' "
                        "was specified or 'pxe_enabled' was set to True.")
                raise exception.Conflict(
                    msg % pdict['portgroup_uuid'])

        new_port = objects.Port(pecan.request.context,
                                **pdict)

        new_port.create()
        # Set the HTTP Location Header
        pecan.response.location = link.build_url('ports', new_port.uuid)
        return Port.convert_with_links(new_port)
Ejemplo n.º 8
0
def check_allow_filter_by_owner(owner):
    """Check if filtering nodes by owner is allowed.

    Version 1.50 of the API allows filtering nodes by owner.
    """
    if (owner is not None and pecan.request.version.minor
            < versions.MINOR_50_NODE_OWNER):
        raise exception.NotAcceptable(_(
            "Request not acceptable. The minimal required API version "
            "should be %(base)s.%(opr)s") %
            {'base': versions.BASE_VERSION,
             'opr': versions.MINOR_50_NODE_OWNER})
Ejemplo n.º 9
0
def check_allow_specify_driver(driver):
    """Check if filtering nodes by driver is allowed.

    Version 1.16 of the API allows filter nodes by driver.
    """
    if (driver is not None and pecan.request.version.minor
            < versions.MINOR_16_DRIVER_FILTER):
        raise exception.NotAcceptable(_(
            "Request not acceptable. The minimal required API version "
            "should be %(base)s.%(opr)s") %
            {'base': versions.BASE_VERSION,
             'opr': versions.MINOR_16_DRIVER_FILTER})
Ejemplo n.º 10
0
def check_allow_specify_resource_class(resource_class):
    """Check if filtering nodes by resource_class is allowed.

    Version 1.21 of the API allows filtering nodes by resource_class.
    """
    if (resource_class is not None and pecan.request.version.minor
            < versions.MINOR_21_RESOURCE_CLASS):
        raise exception.NotAcceptable(_(
            "Request not acceptable. The minimal required API version "
            "should be %(base)s.%(opr)s") %
            {'base': versions.BASE_VERSION,
             'opr': versions.MINOR_21_RESOURCE_CLASS})
Ejemplo n.º 11
0
def check_allow_filter_by_conductor_group(conductor_group):
    """Check if filtering nodes by conductor_group is allowed.

    Version 1.46 of the API allows filtering nodes by conductor_group.
    """
    if (conductor_group is not None and pecan.request.version.minor
            < versions.MINOR_46_NODE_CONDUCTOR_GROUP):
        raise exception.NotAcceptable(_(
            "Request not acceptable. The minimal required API version "
            "should be %(base)s.%(opr)s") %
            {'base': versions.BASE_VERSION,
             'opr': versions.MINOR_46_NODE_CONDUCTOR_GROUP})
Ejemplo n.º 12
0
Archivo: utils.py Proyecto: Tan0/ironic
def check_for_invalid_state_and_allow_filter(provision_state):
    """Check if filtering nodes by provision state is allowed.

    Version 1.9 of the API allows filter nodes by provision state.
    """
    if provision_state is not None:
        if pecan.request.version.minor < 9:
            raise exception.NotAcceptable()
        valid_states = states.machine.states
        if provision_state not in valid_states:
            raise exception.InvalidParameterValue(
                _('Provision state "%s" is not valid') % provision_state)
Ejemplo n.º 13
0
    def _check_allowed_port_fields(self, fields):
        """Check if fetching a particular field of a port is allowed.

        Check if the required version is being requested for fields
        that are only allowed to be fetched in a particular API version.

        :param fields: list or set of fields to check
        :raises: NotAcceptable if a field is not allowed
        """
        if fields is None:
            return
        if (not api_utils.allow_port_advanced_net_fields()
                and set(fields).intersection(self.advanced_net_fields)):
            raise exception.NotAcceptable()
        if ('portgroup_uuid' in fields
                and not api_utils.allow_portgroups_subcontrollers()):
            raise exception.NotAcceptable()
        if ('physical_network' in fields
                and not api_utils.allow_port_physical_network()):
            raise exception.NotAcceptable()
        if ('is_smartnic' in fields
                and not api_utils.allow_port_is_smartnic()):
            raise exception.NotAcceptable()
        if ('local_link_connection/network_type' in fields
                and not api_utils.allow_local_link_connection_network_type()):
            raise exception.NotAcceptable()
        if (isinstance(fields, dict)
                and fields.get('local_link_connection') is not None):
            if (not api_utils.allow_local_link_connection_network_type()
                    and 'network_type' in fields['local_link_connection']):
                raise exception.NotAcceptable()
Ejemplo n.º 14
0
def check_allow_filter_by_fault(fault):
    """Check if filtering nodes by fault is allowed.

    Version 1.42 of the API allows filtering nodes by fault.
    """
    if (fault is not None
            and pecan.request.version.minor < versions.MINOR_42_FAULT):
        raise exception.NotAcceptable(
            _("Request not acceptable. The minimal required API version "
              "should be %(base)s.%(opr)s") % {
                  'base': versions.BASE_VERSION,
                  'opr': versions.MINOR_42_FAULT
              })
Ejemplo n.º 15
0
def check_allow_filter_by_lessee(lessee):
    """Check if filtering nodes by lessee is allowed.

    Version 1.62 of the API allows filtering nodes by lessee.
    """
    if (lessee is not None
            and api.request.version.minor < versions.MINOR_65_NODE_LESSEE):
        raise exception.NotAcceptable(
            _("Request not acceptable. The minimal required API version "
              "should be %(base)s.%(opr)s") % {
                  'base': versions.BASE_VERSION,
                  'opr': versions.MINOR_65_NODE_LESSEE
              })
Ejemplo n.º 16
0
    def _check_allowed_allocation_fields(self, fields):
        """Check if fetching a particular field of an allocation is allowed.

        Check if the required version is being requested for fields
        that are only allowed to be fetched in a particular API version.

        :param fields: list or set of fields to check
        :raises: NotAcceptable if a field is not allowed
        """
        if fields is None:
            return
        if 'owner' in fields and not api_utils.allow_allocation_owner():
            raise exception.NotAcceptable()
Ejemplo n.º 17
0
    def patch(self, port_uuid, patch):
        """Update an existing port.

        :param port_uuid: UUID of a port.
        :param patch: a json PATCH document to apply to this port.
        :raises: NotAcceptable
        """
        cdict = pecan.request.context.to_dict()
        policy.authorize('baremetal:port:update', cdict, cdict)

        if self.parent_node_ident:
            raise exception.OperationNotPermitted()
        if not api_utils.allow_port_advanced_net_fields():
            for field in self.advanced_net_fields:
                field_path = '/%s' % field
                if (api_utils.get_patch_values(patch, field_path)
                        or api_utils.is_path_removed(patch, field_path)):
                    raise exception.NotAcceptable()

        rpc_port = objects.Port.get_by_uuid(pecan.request.context, port_uuid)
        try:
            port_dict = rpc_port.as_dict()
            # NOTE(lucasagomes):
            # 1) Remove node_id because it's an internal value and
            #    not present in the API object
            # 2) Add node_uuid
            port_dict['node_uuid'] = port_dict.pop('node_id', None)
            port = Port(**api_utils.apply_jsonpatch(port_dict, 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.Port.fields:
            try:
                patch_val = getattr(port, field)
            except AttributeError:
                # Ignore fields that aren't exposed in the API
                continue
            if patch_val == wtypes.Unset:
                patch_val = None
            if rpc_port[field] != patch_val:
                rpc_port[field] = patch_val

        rpc_node = objects.Node.get_by_id(pecan.request.context,
                                          rpc_port.node_id)
        topic = pecan.request.rpcapi.get_topic_for(rpc_node)

        new_port = pecan.request.rpcapi.update_port(pecan.request.context,
                                                    rpc_port, topic)

        return Port.convert_with_links(new_port)
Ejemplo n.º 18
0
    def post(self, portgroup):
        """Create a new portgroup.

        :param portgroup: a portgroup within the request body.
        """
        if not api_utils.allow_portgroups():
            raise exception.NotFound()

        context = pecan.request.context
        cdict = context.to_policy_values()
        policy.authorize('baremetal:portgroup:create', cdict, cdict)

        if self.parent_node_ident:
            raise exception.OperationNotPermitted()

        if (not api_utils.allow_portgroup_mode_properties() and
                (portgroup.mode is not wtypes.Unset or
                 portgroup.properties is not wtypes.Unset)):
            raise exception.NotAcceptable()

        if (portgroup.name and
                not api_utils.is_valid_logical_name(portgroup.name)):
            error_msg = _("Cannot create portgroup with invalid name "
                          "'%(name)s'") % {'name': portgroup.name}
            raise wsme.exc.ClientSideError(
                error_msg, status_code=http_client.BAD_REQUEST)

        pg_dict = portgroup.as_dict()
        vif = pg_dict.get('extra', {}).get('vif_port_id')
        if vif:
            common_utils.warn_about_deprecated_extra_vif_port_id()

        # NOTE(yuriyz): UUID is mandatory for notifications payload
        if not pg_dict.get('uuid'):
            pg_dict['uuid'] = uuidutils.generate_uuid()

        new_portgroup = objects.Portgroup(context, **pg_dict)

        notify.emit_start_notification(context, new_portgroup, 'create',
                                       node_uuid=portgroup.node_uuid)
        with notify.handle_error_notification(context, new_portgroup, 'create',
                                              node_uuid=portgroup.node_uuid):
            new_portgroup.create()
        notify.emit_end_notification(context, new_portgroup, 'create',
                                     node_uuid=portgroup.node_uuid)

        # Set the HTTP Location Header
        pecan.response.location = link.build_url('portgroups',
                                                 new_portgroup.uuid)
        return Portgroup.convert_with_links(new_portgroup)
Ejemplo n.º 19
0
    def detail(self,
               node=None,
               node_uuid=None,
               address=None,
               marker=None,
               limit=None,
               sort_key='id',
               sort_dir='asc'):
        """Retrieve a list of ports with detail.

        Note that the 'node_uuid' interface is deprecated in favour
        of the 'node' interface

        :param node: UUID or name of a node, to get only ports for that
                     node.
        :param node_uuid: UUID of a node, to get only ports for that
                          node.
        :param address: MAC address of a port, to get the port which has
                        this MAC address.
        :param marker: pagination marker for large data sets.
        :param limit: maximum number of resources to return in a single result.
                      This value cannot be larger than the value of max_limit
                      in the [api] section of the ironic configuration, or only
                      max_limit resources will be returned.
        :param sort_key: column to sort results by. Default: id.
        :param sort_dir: direction to sort. "asc" or "desc". Default: asc.
        :raises: NotAcceptable, HTTPNotFound
        """
        cdict = pecan.request.context.to_dict()
        policy.authorize('baremetal:port:get', cdict, cdict)

        if not node_uuid and node:
            # We're invoking this interface using positional notation, or
            # explicitly using 'node'.  Try and determine which one.
            # Make sure only one interface, node or node_uuid is used
            if (not api_utils.allow_node_logical_names()
                    and not uuidutils.is_uuid_like(node)):
                raise exception.NotAcceptable()

        # NOTE(lucasagomes): /detail should only work against collections
        parent = pecan.request.path.split('/')[:-1][-1]
        if parent != "ports":
            raise exception.HTTPNotFound()

        resource_url = '/'.join(['ports', 'detail'])
        return self._get_ports_collection(node_uuid or node, address, marker,
                                          limit, sort_key, sort_dir,
                                          resource_url)
Ejemplo n.º 20
0
    def _check_name_acceptable(self, name, error_msg):
        """Checks if a node 'name' is acceptable, it does not return a value.

        This function will raise an exception for unacceptable names.

        :param name: node name
        :param error_msg: error message in case of wsme.exc.ClientSideError
        :raises: exception.NotAcceptable
        :raises: wsme.exc.ClientSideError
        """
        if name:
            if not api_utils.allow_node_logical_names():
                raise exception.NotAcceptable()
            if not api_utils.is_valid_node_name(name):
                raise wsme.exc.ClientSideError(
                    error_msg, status_code=http_client.BAD_REQUEST)
Ejemplo n.º 21
0
    def get_all(self,
                node=None,
                node_uuid=None,
                address=None,
                marker=None,
                limit=None,
                sort_key='id',
                sort_dir='asc',
                fields=None):
        """Retrieve a list of ports.

        Note that the 'node_uuid' interface is deprecated in favour
        of the 'node' interface

        :param node: UUID or name of a node, to get only ports for that
                           node.
        :param node_uuid: UUID of a node, to get only ports for that
                           node.
        :param address: MAC address of a port, to get the port which has
                        this MAC address.
        :param marker: pagination marker for large data sets.
        :param limit: maximum number of resources to return in a single result.
        :param sort_key: column to sort results by. Default: id.
        :param sort_dir: direction to sort. "asc" or "desc". Default: asc.
        :param fields: Optional, a list with a specified set of fields
            of the resource to be returned.
        """
        api_utils.check_allow_specify_fields(fields)
        if fields is None:
            fields = _DEFAULT_RETURN_FIELDS

        if not node_uuid and node:
            # We're invoking this interface using positional notation, or
            # explicitly using 'node'.  Try and determine which one.
            # Make sure only one interface, node or node_uuid is used
            if (not api_utils.allow_node_logical_names()
                    and not uuidutils.is_uuid_like(node)):
                raise exception.NotAcceptable()

        return self._get_ports_collection(node_uuid or node,
                                          address,
                                          marker,
                                          limit,
                                          sort_key,
                                          sort_dir,
                                          fields=fields)
Ejemplo n.º 22
0
def check_allow_filter_by_fault(fault):
    """Check if filtering nodes by fault is allowed.

    Version 1.42 of the API allows filtering nodes by fault.
    """
    if (fault is not None and pecan.request.version.minor
            < versions.MINOR_42_FAULT):
        raise exception.NotAcceptable(_(
            "Request not acceptable. The minimal required API version "
            "should be %(base)s.%(opr)s") % {'base': versions.BASE_VERSION,
                                             'opr': versions.MINOR_42_FAULT})

    if fault is not None and fault not in faults.VALID_FAULTS:
        msg = (_('Unrecognized fault "%(fault)s" is specified, allowed faults '
                 'are %(valid_faults)s') %
               {'fault': fault, 'valid_faults': faults.VALID_FAULTS})
        raise wsme.exc.ClientSideError(
            msg, status_code=http_client.BAD_REQUEST)
Ejemplo n.º 23
0
    def get_all(self,
                node=None,
                resource_class=None,
                state=None,
                marker=None,
                limit=None,
                sort_key='id',
                sort_dir='asc',
                fields=None,
                owner=None):
        """Retrieve a list of allocations.

        :param node: UUID or name of a node, to get only allocations for that
                     node.
        :param resource_class: Filter by requested resource class.
        :param state: Filter by allocation state.
        :param marker: pagination marker for large data sets.
        :param limit: maximum number of resources to return in a single result.
                      This value cannot be larger than the value of max_limit
                      in the [api] section of the ironic configuration, or only
                      max_limit resources will be returned.
        :param sort_key: column to sort results by. Default: id.
        :param sort_dir: direction to sort. "asc" or "desc". Default: asc.
        :param fields: Optional, a list with a specified set of fields
                       of the resource to be returned.
        :param owner: Filter by owner.
        """
        cdict = api.request.context.to_policy_values()
        policy.authorize('baremetal:allocation:get', cdict, cdict)

        self._check_allowed_allocation_fields(fields)
        if owner is not None and not api_utils.allow_allocation_owner():
            raise exception.NotAcceptable()

        return self._get_allocations_collection(node,
                                                resource_class,
                                                state,
                                                owner,
                                                marker,
                                                limit,
                                                sort_key,
                                                sort_dir,
                                                fields=fields)
Ejemplo n.º 24
0
    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 = uuidutils.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

        # Verify that if we're creating a new node with a 'name' set
        # that it is a valid name
        if node.name:
            if not api_utils.allow_node_logical_names():
                raise exception.NotAcceptable()
            if not api_utils.is_valid_node_name(node.name):
                msg = _("Cannot create node with invalid name %(name)s")
                raise wsme.exc.ClientSideError(msg % {'name': node.name},
                                               status_code=400)

        node.provision_state = api_utils.initial_node_provision_state()

        new_node = objects.Node(pecan.request.context,
                                **node.as_dict())
        new_node.create()
        # Set the HTTP Location Header
        pecan.response.location = link.build_url('nodes', new_node.uuid)
        return Node.convert_with_links(new_node)
Ejemplo n.º 25
0
    def validate(self, node=None, node_uuid=None):
        """Validate the driver interfaces, using the node's UUID or name.

        Note that the 'node_uuid' interface is deprecated in favour
        of the 'node' interface

        :param node: UUID or name of a node.
        :param node_uuid: UUID of a node.
        """
        if node:
            # We're invoking this interface using positional notation, or
            # explicitly using 'node'.  Try and determine which one.
            if not allow_logical_names() and not uuidutils.is_uuid_like(node):
                raise exception.NotAcceptable()

        rpc_node = _get_rpc_node(node_uuid or node)

        topic = pecan.request.rpcapi.get_topic_for(rpc_node)
        return pecan.request.rpcapi.validate_driver_interfaces(
            pecan.request.context, rpc_node.uuid, topic)
Ejemplo n.º 26
0
    def post(self, port):
        """Create a new port.

        :param port: a port within the request body.
        :raises: NotAcceptable
        """
        cdict = pecan.request.context.to_dict()
        policy.authorize('baremetal:port:create', cdict, cdict)

        if self.parent_node_ident:
            raise exception.OperationNotPermitted()

        pdict = port.as_dict()
        if not api_utils.allow_port_advanced_net_fields():
            if set(pdict).intersection(self.advanced_net_fields):
                raise exception.NotAcceptable()

        new_port = objects.Port(pecan.request.context, **pdict)

        new_port.create()
        # Set the HTTP Location Header
        pecan.response.location = link.build_url('ports', new_port.uuid)
        return Port.convert_with_links(new_port)
Ejemplo n.º 27
0
def check_allowed_fields(fields):
    """Check if fetching a particular field is allowed.

    This method checks if the required version is being requested for fields
    that are only allowed to be fetched in a particular API version.
    """
    if fields is None:
        return
    if 'bios_interface' in fields and not allow_bios_interface():
        raise exception.NotAcceptable()
    if 'network_interface' in fields and not allow_network_interface():
        raise exception.NotAcceptable()
    if 'resource_class' in fields and not allow_resource_class():
        raise exception.NotAcceptable()
    if not allow_dynamic_interfaces():
        if set(V31_FIELDS).intersection(set(fields)):
            raise exception.NotAcceptable()
    if 'storage_interface' in fields and not allow_storage_interface():
        raise exception.NotAcceptable()
    if 'traits' in fields and not allow_traits():
        raise exception.NotAcceptable()
    if 'rescue_interface' in fields and not allow_rescue_interface():
        raise exception.NotAcceptable()
Ejemplo n.º 28
0
    def post(self, port):
        """Create a new port.

        :param port: a port within the request body.
        :raises: NotAcceptable, HTTPNotFound, Conflict
        """
        context = pecan.request.context
        cdict = context.to_policy_values()
        policy.authorize('baremetal:port:create', cdict, cdict)

        if self.parent_node_ident or self.parent_portgroup_ident:
            raise exception.OperationNotPermitted()

        pdict = port.as_dict()
        self._check_allowed_port_fields(pdict)

        create_remotely = pecan.request.rpcapi.can_send_create_port()
        if (not create_remotely and pdict.get('portgroup_uuid')):
            # NOTE(mgoddard): In RPC API v1.41, port creation was moved to the
            # conductor service to facilitate validation of the physical
            # network field of ports in portgroups. During a rolling upgrade,
            # the RPCAPI will reject the create_port method, so we need to
            # create the port locally. If the port is a member of a portgroup,
            # we are unable to perform the validation and must reject the
            # request.
            raise exception.NotAcceptable()

        extra = pdict.get('extra')
        vif = extra.get('vif_port_id') if extra else None
        if vif:
            common_utils.warn_about_deprecated_extra_vif_port_id()

        if (pdict.get('portgroup_uuid') and (pdict.get('pxe_enabled') or vif)):
            rpc_pg = objects.Portgroup.get_by_uuid(context,
                                                   pdict['portgroup_uuid'])
            if not rpc_pg.standalone_ports_supported:
                msg = _("Port group %s doesn't support standalone ports. "
                        "This port cannot be created as a member of that "
                        "port group because either 'extra/vif_port_id' "
                        "was specified or 'pxe_enabled' was set to True.")
                raise exception.Conflict(msg % pdict['portgroup_uuid'])

        # NOTE(yuriyz): UUID is mandatory for notifications payload
        if not pdict.get('uuid'):
            pdict['uuid'] = uuidutils.generate_uuid()

        rpc_port = objects.Port(context, **pdict)
        rpc_node = objects.Node.get_by_id(context, rpc_port.node_id)

        notify_extra = {
            'node_uuid': port.node_uuid,
            'portgroup_uuid': port.portgroup_uuid
        }
        notify.emit_start_notification(context, rpc_port, 'create',
                                       **notify_extra)
        with notify.handle_error_notification(context, rpc_port, 'create',
                                              **notify_extra):
            # NOTE(mgoddard): In RPC API v1.41, port creation was moved to the
            # conductor service to facilitate validation of the physical
            # network field of ports in portgroups. During a rolling upgrade,
            # the RPCAPI will reject the create_port method, so we need to
            # create the port locally.
            if create_remotely:
                topic = pecan.request.rpcapi.get_topic_for(rpc_node)
                new_port = pecan.request.rpcapi.create_port(
                    context, rpc_port, topic)
            else:
                rpc_port.create()
                new_port = rpc_port
        notify.emit_end_notification(context, new_port, 'create',
                                     **notify_extra)
        # Set the HTTP Location Header
        pecan.response.location = link.build_url('ports', new_port.uuid)
        return Port.convert_with_links(new_port)
Ejemplo n.º 29
0
    def get_all(self,
                node=None,
                node_uuid=None,
                address=None,
                marker=None,
                limit=None,
                sort_key='id',
                sort_dir='asc',
                fields=None,
                portgroup=None):
        """Retrieve a list of ports.

        Note that the 'node_uuid' interface is deprecated in favour
        of the 'node' interface

        :param node: UUID or name of a node, to get only ports for that
                           node.
        :param node_uuid: UUID of a node, to get only ports for that
                           node.
        :param address: MAC address of a port, to get the port which has
                        this MAC address.
        :param marker: pagination marker for large data sets.
        :param limit: maximum number of resources to return in a single result.
                      This value cannot be larger than the value of max_limit
                      in the [api] section of the ironic configuration, or only
                      max_limit resources will be returned.
        :param sort_key: column to sort results by. Default: id.
        :param sort_dir: direction to sort. "asc" or "desc". Default: asc.
        :param fields: Optional, a list with a specified set of fields
            of the resource to be returned.
        :param portgroup: UUID or name of a portgroup, to get only ports
                                   for that portgroup.
        :raises: NotAcceptable, HTTPNotFound
        """
        cdict = pecan.request.context.to_policy_values()
        policy.authorize('baremetal:port:get', cdict, cdict)

        api_utils.check_allow_specify_fields(fields)
        self._check_allowed_port_fields(fields)
        self._check_allowed_port_fields([sort_key])
        if portgroup and not api_utils.allow_portgroups_subcontrollers():
            raise exception.NotAcceptable()

        if fields is None:
            fields = _DEFAULT_RETURN_FIELDS

        if not node_uuid and node:
            # We're invoking this interface using positional notation, or
            # explicitly using 'node'.  Try and determine which one.
            # Make sure only one interface, node or node_uuid is used
            if (not api_utils.allow_node_logical_names()
                    and not uuidutils.is_uuid_like(node)):
                raise exception.NotAcceptable()

        return self._get_ports_collection(node_uuid or node,
                                          address,
                                          portgroup,
                                          marker,
                                          limit,
                                          sort_key,
                                          sort_dir,
                                          fields=fields)
Ejemplo n.º 30
0
    def patch(self, portgroup_ident, patch):
        """Update an existing portgroup.

        :param portgroup_ident: UUID or logical name of a portgroup.
        :param patch: a json PATCH document to apply to this portgroup.
        """
        if not api_utils.allow_portgroups():
            raise exception.NotFound()

        context = pecan.request.context
        cdict = context.to_policy_values()
        policy.authorize('baremetal:portgroup:update', cdict, cdict)

        if self.parent_node_ident:
            raise exception.OperationNotPermitted()

        if (not api_utils.allow_portgroup_mode_properties() and
                (api_utils.is_path_updated(patch, '/mode') or
                 api_utils.is_path_updated(patch, '/properties'))):
            raise exception.NotAcceptable()

        rpc_portgroup = api_utils.get_rpc_portgroup(portgroup_ident)

        names = api_utils.get_patch_values(patch, '/name')
        for name in names:
            if (name and
                    not api_utils.is_valid_logical_name(name)):
                error_msg = _("Portgroup %(portgroup)s: Cannot change name to"
                              " invalid name '%(name)s'") % {'portgroup':
                                                             portgroup_ident,
                                                             'name': name}
                raise wsme.exc.ClientSideError(
                    error_msg, status_code=http_client.BAD_REQUEST)

        try:
            portgroup_dict = rpc_portgroup.as_dict()
            # NOTE:
            # 1) Remove node_id because it's an internal value and
            #    not present in the API object
            # 2) Add node_uuid
            portgroup_dict['node_uuid'] = portgroup_dict.pop('node_id', None)
            portgroup = Portgroup(**api_utils.apply_jsonpatch(portgroup_dict,
                                                              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.Portgroup.fields:
            try:
                patch_val = getattr(portgroup, field)
            except AttributeError:
                # Ignore fields that aren't exposed in the API
                continue
            if patch_val == wtypes.Unset:
                patch_val = None
            if rpc_portgroup[field] != patch_val:
                rpc_portgroup[field] = patch_val

        rpc_node = objects.Node.get_by_id(context, rpc_portgroup.node_id)

        notify.emit_start_notification(context, rpc_portgroup, 'update',
                                       node_uuid=rpc_node.uuid)
        with notify.handle_error_notification(context, rpc_portgroup, 'update',
                                              node_uuid=rpc_node.uuid):
            topic = pecan.request.rpcapi.get_topic_for(rpc_node)
            new_portgroup = pecan.request.rpcapi.update_portgroup(
                context, rpc_portgroup, topic)

        api_portgroup = Portgroup.convert_with_links(new_portgroup)
        notify.emit_end_notification(context, new_portgroup, 'update',
                                     node_uuid=api_portgroup.node_uuid)

        return api_portgroup