Beispiel #1
0
 def _set_portgroup_uuid(self, value):
     if value and self._portgroup_uuid != value:
         if not api_utils.allow_portgroups_subcontrollers():
             self._portgroup_uuid = wtypes.Unset
             return
         try:
             portgroup = objects.Portgroup.get(pecan.request.context, value)
             if portgroup.node_id != self.node_id:
                 raise exception.BadRequest(
                     _('Port can not be added to a '
                       'portgroup belonging to a '
                       'different node.'))
             self._portgroup_uuid = portgroup.uuid
             # NOTE(lucasagomes): Create the portgroup_id attribute
             #                    on-the-fly to satisfy the api ->
             #                    rpc object conversion.
             self.portgroup_id = portgroup.id
         except exception.PortgroupNotFound as e:
             # Change error code because 404 (NotFound) is inappropriate
             # response for a POST request to create a Port
             e.code = http_client.BAD_REQUEST  # BadRequest
             raise e
     elif value == wtypes.Unset:
         self._portgroup_uuid = wtypes.Unset
     elif value is None and api_utils.allow_portgroups_subcontrollers():
         # This is to output portgroup_uuid field if API version allows this
         self._portgroup_uuid = None
Beispiel #2
0
    def _update_node_object(self, node):
        """Update the given node object with the changes here."""
        changes = self.obj_get_changes()
        try:
            new_instance_uuid = changes.pop('uuid')
        except KeyError:
            pass
        else:
            node.instance_uuid = new_instance_uuid

        changes.pop('node_uuid', None)
        instance_info = node.instance_info

        for field, value in changes.items():
            # NOTE(dtantsur): only instance_info fields can be updated here.
            try:
                dest = self.instance_info_mapping_rev[field]
            except KeyError:
                # NOTE(dtantsur): this should not happen because of API-level
                # validations, but checking just in case.
                raise exception.BadRequest(
                    'Field %s cannot be set or updated' % changes)
            instance_info[dest] = value

        node.instance_info = instance_info
        return node
Beispiel #3
0
    def list(self, filters=None, marker=None, limit=30):
        if marker is None:
            index = 0
        else:
            for index, image in enumerate(self._images):
                if image.id == str(marker):
                    index += 1
                    break
            else:
                raise exception.BadRequest('Marker not found')

        return self._images[index:index + limit]
Beispiel #4
0
    def _validate_and_remove_traits(fields):
        """Validate traits in fields for create or update, remove if present.

        :param fields: a dict of Node fields for create or update.
        :raises: BadRequest if fields contains a traits that are not None.
        """
        if 'traits' in fields:
            # NOTE(mgoddard): Traits should be updated via the node
            # object's traits field, which is itself an object. We shouldn't
            # get here with changes to traits, as this should be handled by the
            # API. When services are pinned to Pike, we can get here with
            # traits set to None in updates, due to changes made to the object
            # in _convert_to_version.
            if fields['traits']:
                # NOTE(mgoddard): We shouldn't get here as this should be
                # handled by the API.
                raise exception.BadRequest()
            fields.pop('traits')
Beispiel #5
0
    def post(self, port):
        """Create a new port.

        :param port: a port within the request body.
        :raises: NotAcceptable, HTTPNotFound, Conflict
        """
        if self.parent_node_ident or self.parent_portgroup_ident:
            raise exception.OperationNotPermitted()

        context = api.request.context
        api_utils.check_policy('baremetal:port:create')

        # NOTE(lucasagomes): Create the node_id attribute on-the-fly
        #                    to satisfy the api -> rpc object
        #                    conversion.
        node = api_utils.replace_node_uuid_with_id(port)

        self._check_allowed_port_fields(port)

        portgroup = None
        if port.get('portgroup_uuid'):
            try:
                portgroup = objects.Portgroup.get(api.request.context,
                                                  port.pop('portgroup_uuid'))
                if portgroup.node_id != node.id:
                    raise exception.BadRequest(_('Port can not be added to a '
                                                 'portgroup belonging to a '
                                                 'different node.'))
                # NOTE(lucasagomes): Create the portgroup_id attribute
                #                    on-the-fly to satisfy the api ->
                #                    rpc object conversion.
                port['portgroup_id'] = portgroup.id
            except exception.PortgroupNotFound as e:
                # Change error code because 404 (NotFound) is inappropriate
                # response for a POST request to create a Port
                e.code = http_client.BAD_REQUEST  # BadRequest
                raise e

        if port.get('is_smartnic'):
            try:
                api_utils.LOCAL_LINK_SMART_NIC_VALIDATOR(
                    'local_link_connection',
                    port.get('local_link_connection'))
            except exception.Invalid:
                raise exception.Invalid(
                    "Smart NIC port must have port_id "
                    "and hostname in local_link_connection")

        physical_network = port.get('physical_network')
        if physical_network is not None and not physical_network:
            raise exception.Invalid('A non-empty value is required when '
                                    'setting physical_network')

        vif = api_utils.handle_post_port_like_extra_vif(port)

        if (portgroup and (port.get('pxe_enabled') or vif)):
            if not portgroup.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 % portgroup.uuid)

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

        rpc_port = objects.Port(context, **port)

        notify_extra = {
            'node_uuid': node.uuid,
            'portgroup_uuid': portgroup and portgroup.uuid or None
        }
        notify.emit_start_notification(context, rpc_port, 'create',
                                       **notify_extra)
        with notify.handle_error_notification(context, rpc_port, 'create',
                                              **notify_extra):
            topic = api.request.rpcapi.get_topic_for(node)
            new_port = api.request.rpcapi.create_port(context, rpc_port,
                                                      topic)
        notify.emit_end_notification(context, new_port, 'create',
                                     **notify_extra)
        # Set the HTTP Location Header
        api.response.location = link.build_url('ports', new_port.uuid)
        return convert_with_links(new_port)
Beispiel #6
0
    def post(self, port):
        """Create a new port.

        :param port: a port within the request body.
        :raises: NotAcceptable, HTTPNotFound, Conflict
        """
        if self.parent_node_ident or self.parent_portgroup_ident:
            raise exception.OperationNotPermitted()

        # NOTE(lucasagomes): Create the node_id attribute on-the-fly
        #                    to satisfy the api -> rpc object
        #                    conversion.
        # NOTE(TheJulia): The get of the node *does* check if the node
        # can be accessed. We need to be able to get the node regardless
        # in order to perform the actual policy check.
        raise_node_not_found = False
        node = None
        owner = None
        lessee = None
        node_uuid = port.get('node_uuid')
        try:
            node = api_utils.replace_node_uuid_with_id(port)
            owner = node.owner
            lessee = node.lessee
        except exception.NotFound:
            raise_node_not_found = True

        # While the rule is for the port, the base object that controls access
        # is the node.
        api_utils.check_owner_policy('node',
                                     'baremetal:port:create',
                                     owner,
                                     lessee=lessee,
                                     conceal_node=False)
        if raise_node_not_found:
            # Delayed raise of NodeNotFound because we want to check
            # the access policy first.
            raise exception.NodeNotFound(node=node_uuid,
                                         code=http_client.BAD_REQUEST)

        context = api.request.context

        self._check_allowed_port_fields(port)

        portgroup = None
        if port.get('portgroup_uuid'):
            try:
                portgroup = objects.Portgroup.get(api.request.context,
                                                  port.pop('portgroup_uuid'))
                if portgroup.node_id != node.id:
                    raise exception.BadRequest(
                        _('Port can not be added to a '
                          'portgroup belonging to a '
                          'different node.'))
                # NOTE(lucasagomes): Create the portgroup_id attribute
                #                    on-the-fly to satisfy the api ->
                #                    rpc object conversion.
                port['portgroup_id'] = portgroup.id
            except exception.PortgroupNotFound as e:
                # Change error code because 404 (NotFound) is inappropriate
                # response for a POST request to create a Port
                e.code = http_client.BAD_REQUEST  # BadRequest
                raise e

        if port.get('is_smartnic'):
            try:
                api_utils.LOCAL_LINK_SMART_NIC_VALIDATOR(
                    'local_link_connection', port.get('local_link_connection'))
            except exception.Invalid:
                raise exception.Invalid(
                    "Smart NIC port must have port_id "
                    "and hostname in local_link_connection")

        physical_network = port.get('physical_network')
        if physical_network is not None and not physical_network:
            raise exception.Invalid('A non-empty value is required when '
                                    'setting physical_network')

        if (portgroup and (port.get('pxe_enabled'))):
            if not portgroup.standalone_ports_supported:
                msg = _("Port group %s doesn't support standalone ports. "
                        "This port cannot be created as a member of that "
                        "portgroup as the port's 'pxe_enabled' field was "
                        "set to True.")
                raise exception.Conflict(msg % portgroup.uuid)

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

        rpc_port = objects.Port(context, **port)

        notify_extra = {
            'node_uuid': node.uuid,
            'portgroup_uuid': portgroup and portgroup.uuid or None
        }
        notify.emit_start_notification(context, rpc_port, 'create',
                                       **notify_extra)
        with notify.handle_error_notification(context, rpc_port, 'create',
                                              **notify_extra):
            topic = api.request.rpcapi.get_topic_for(node)
            new_port = api.request.rpcapi.create_port(context, rpc_port, topic)
        notify.emit_end_notification(context, new_port, 'create',
                                     **notify_extra)
        # Set the HTTP Location Header
        api.response.location = link.build_url('ports', new_port.uuid)
        return convert_with_links(new_port)