Esempio n. 1
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()

        cdict = pecan.request.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)

        new_portgroup = objects.Portgroup(pecan.request.context,
                                          **portgroup.as_dict())
        new_portgroup.create()
        # Set the HTTP Location Header
        pecan.response.location = link.build_url('portgroups',
                                                 new_portgroup.uuid)
        return Portgroup.convert_with_links(new_portgroup)
Esempio n. 2
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)
Esempio n. 3
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 = api.request.context
        api_utils.check_policy('baremetal:portgroup:create')

        if self.parent_node_ident:
            raise exception.OperationNotPermitted()

        if (not api_utils.allow_portgroup_mode_properties()
                and (portgroup.get('mode') or portgroup.get('properties'))):
            raise exception.NotAcceptable()

        if (portgroup.get('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 exception.ClientSideError(
                error_msg, status_code=http_client.BAD_REQUEST)

        api_utils.handle_post_port_like_extra_vif(portgroup)

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

        node = api_utils.replace_node_uuid_with_id(portgroup)

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

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

        # Set the HTTP Location Header
        api.response.location = link.build_url('portgroups',
                                               new_portgroup.uuid)
        return convert_with_links(new_portgroup)
Esempio n. 4
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)
Esempio n. 5
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
Esempio n. 6
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 = api.request.context

        rpc_portgroup, rpc_node = api_utils.check_port_policy_and_retrieve(
            'baremetal:portgroup:update', portgroup_ident, portgroup=True)

        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()

        api_utils.patch_validate_allowed_fields(patch, PATCH_ALLOWED_FIELDS)

        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 exception.ClientSideError(
                    error_msg, status_code=http_client.BAD_REQUEST)

        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.pop('node_id')
        portgroup_dict['node_uuid'] = rpc_node.uuid
        portgroup_dict = api_utils.apply_jsonpatch(portgroup_dict, patch)

        if 'mode' not in portgroup_dict:
            msg = _("'mode' is a mandatory attribute and can not be removed")
            raise exception.ClientSideError(msg)

        try:
            if portgroup_dict['node_uuid'] != rpc_node.uuid:
                rpc_node = objects.Node.get(api.request.context,
                                            portgroup_dict['node_uuid'])

        except exception.NodeNotFound as e:
            # Change error code because 404 (NotFound) is inappropriate
            # response for a POST request to patch a Portgroup
            e.code = http_client.BAD_REQUEST  # BadRequest
            raise

        api_utils.patched_validate_with_schema(portgroup_dict,
                                               PORTGROUP_PATCH_SCHEMA,
                                               PORTGROUP_PATCH_VALIDATOR)

        api_utils.patch_update_changed_fields(portgroup_dict,
                                              rpc_portgroup,
                                              fields=objects.Portgroup.fields,
                                              schema=PORTGROUP_PATCH_SCHEMA,
                                              id_map={'node_id': rpc_node.id})

        if (rpc_node.provision_state == ir_states.INSPECTING
                and api_utils.allow_inspect_wait_state()):
            msg = _('Cannot update portgroup "%(portgroup)s" on node '
                    '"%(node)s" while it is in state "%(state)s".') % {
                        'portgroup': rpc_portgroup.uuid,
                        'node': rpc_node.uuid,
                        'state': ir_states.INSPECTING
                    }
            raise exception.ClientSideError(msg,
                                            status_code=http_client.CONFLICT)

        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 = api.request.rpcapi.get_topic_for(rpc_node)
            new_portgroup = api.request.rpcapi.update_portgroup(
                context, rpc_portgroup, topic)

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

        return api_portgroup
Esempio n. 7
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()

        raise_node_not_found = False
        node = None
        owner = None
        lessee = None
        node_uuid = portgroup.get('node_uuid')
        try:
            # The replace_node_uuid_with_id also checks access to the node
            # and will raise an exception if access is not permitted.
            node = api_utils.replace_node_uuid_with_id(portgroup)
            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:portgroup: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

        if self.parent_node_ident:
            raise exception.OperationNotPermitted()

        if (not api_utils.allow_portgroup_mode_properties()
                and (portgroup.get('mode') or portgroup.get('properties'))):
            raise exception.NotAcceptable()

        if (portgroup.get('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 exception.ClientSideError(
                error_msg, status_code=http_client.BAD_REQUEST)

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

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

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

        # Set the HTTP Location Header
        api.response.location = link.build_url('portgroups',
                                               new_portgroup.uuid)
        return convert_with_links(new_portgroup)
Esempio n. 8
0
 def test_allow_portgroup_mode_properties(self, mock_request):
     mock_request.version.minor = 26
     self.assertTrue(utils.allow_portgroup_mode_properties())
     mock_request.version.minor = 25
     self.assertFalse(utils.allow_portgroup_mode_properties())
Esempio n. 9
0
 def test_allow_portgroup_mode_properties(self, mock_request):
     mock_request.version.minor = 26
     self.assertTrue(utils.allow_portgroup_mode_properties())
     mock_request.version.minor = 25
     self.assertFalse(utils.allow_portgroup_mode_properties())