def delete(self, portgroup_ident): """Delete a portgroup. :param portgroup_ident: UUID or logical name of a portgroup. """ if not api_utils.allow_portgroups(): raise exception.NotFound() context = pecan.request.context cdict = context.to_policy_values() policy.authorize('baremetal:portgroup:delete', cdict, cdict) if self.parent_node_ident: raise exception.OperationNotPermitted() rpc_portgroup = api_utils.get_rpc_portgroup(portgroup_ident) rpc_node = objects.Node.get_by_id(pecan.request.context, rpc_portgroup.node_id) notify.emit_start_notification(context, rpc_portgroup, 'delete', node_uuid=rpc_node.uuid) with notify.handle_error_notification(context, rpc_portgroup, 'delete', node_uuid=rpc_node.uuid): topic = pecan.request.rpcapi.get_topic_for(rpc_node) pecan.request.rpcapi.destroy_portgroup(context, rpc_portgroup, topic) notify.emit_end_notification(context, rpc_portgroup, 'delete', node_uuid=rpc_node.uuid)
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() cdict = pecan.request.context.to_dict() policy.authorize('baremetal:portgroup:update', cdict, cdict) if self.parent_node_ident: raise exception.OperationNotPermitted() 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(pecan.request.context, rpc_portgroup.node_id) topic = pecan.request.rpcapi.get_topic_for(rpc_node) new_portgroup = pecan.request.rpcapi.update_portgroup( pecan.request.context, rpc_portgroup, topic) return Portgroup.convert_with_links(new_portgroup)
def delete(self, portgroup_ident): """Delete a portgroup. :param portgroup_ident: UUID or logical name of a portgroup. """ if not api_utils.allow_portgroups(): raise exception.NotFound() rpc_portgroup, rpc_node = api_utils.check_port_policy_and_retrieve( 'baremetal:portgroup:delete', portgroup_ident, portgroup=True) context = api.request.context if self.parent_node_ident: raise exception.OperationNotPermitted() notify.emit_start_notification(context, rpc_portgroup, 'delete', node_uuid=rpc_node.uuid) with notify.handle_error_notification(context, rpc_portgroup, 'delete', node_uuid=rpc_node.uuid): topic = api.request.rpcapi.get_topic_for(rpc_node) api.request.rpcapi.destroy_portgroup(context, rpc_portgroup, topic) notify.emit_end_notification(context, rpc_portgroup, 'delete', node_uuid=rpc_node.uuid)
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() cdict = pecan.request.context.to_dict() policy.authorize('baremetal:portgroup:update', cdict, cdict) if self.parent_node_ident: raise exception.OperationNotPermitted() 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(pecan.request.context, rpc_portgroup.node_id) topic = pecan.request.rpcapi.get_topic_for(rpc_node) new_portgroup = pecan.request.rpcapi.update_portgroup( pecan.request.context, rpc_portgroup, topic) return Portgroup.convert_with_links(new_portgroup)
def detail(self, node=None, address=None, marker=None, limit=None, sort_key='id', sort_dir='asc'): """Retrieve a list of portgroups with detail. :param node: UUID or name of a node, to get only portgroups for that node. :param address: MAC address of a portgroup, to get the portgroup 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. """ if not api_utils.allow_portgroups(): raise exception.NotFound() cdict = pecan.request.context.to_policy_values() policy.authorize('baremetal:portgroup:get', cdict, cdict) api_utils.check_allowed_portgroup_fields([sort_key]) # NOTE: /detail should only work against collections parent = pecan.request.path.split('/')[:-1][-1] if parent != "portgroups": raise exception.HTTPNotFound() resource_url = '/'.join(['portgroups', 'detail']) return self._get_portgroups_collection( node, address, marker, limit, sort_key, sort_dir, resource_url=resource_url)
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_dict() policy.authorize('baremetal:portgroup:create', cdict, cdict) if self.parent_node_ident: raise exception.OperationNotPermitted() 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)
def get_all(self, node=None, address=None, marker=None, limit=None, sort_key='id', sort_dir='asc', fields=None): """Retrieve a list of portgroups. :param node: UUID or name of a node, to get only portgroups for that node. :param address: MAC address of a portgroup, to get the portgroup 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. """ if not api_utils.allow_portgroups(): raise exception.NotFound() cdict = pecan.request.context.to_policy_values() policy.authorize('baremetal:portgroup:get', cdict, cdict) api_utils.check_allowed_portgroup_fields(fields) api_utils.check_allowed_portgroup_fields([sort_key]) if fields is None: fields = _DEFAULT_RETURN_FIELDS return self._get_portgroups_collection(node, address, marker, limit, sort_key, sort_dir, fields=fields)
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_dict() policy.authorize('baremetal:portgroup:create', cdict, cdict) if self.parent_node_ident: raise exception.OperationNotPermitted() 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)
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)
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)
def get_all(self, node=None, address=None, marker=None, limit=None, sort_key='id', sort_dir='asc', fields=None, detail=None): """Retrieve a list of portgroups. :param node: UUID or name of a node, to get only portgroups for that node. :param address: MAC address of a portgroup, to get the portgroup 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. """ if not api_utils.allow_portgroups(): raise exception.NotFound() if self.parent_node_ident: # Override the node, since this is being called by another # controller with a linked view. node = self.parent_node_ident project = api_utils.check_port_list_policy( portgroup=True, parent_node=self.parent_node_ident) api_utils.check_allowed_portgroup_fields(fields) api_utils.check_allowed_portgroup_fields([sort_key]) fields = api_utils.get_request_return_fields(fields, detail, _DEFAULT_RETURN_FIELDS) return self._get_portgroups_collection(node, address, marker, limit, sort_key, sort_dir, fields=fields, detail=detail, project=project)
def _lookup(self, ident, subres, *remainder): if not api_utils.allow_portgroups(): pecan.abort(http_client.NOT_FOUND) try: ident = types.uuid_or_name.validate(ident) except exception.InvalidUuidOrName as e: pecan.abort(http_client.BAD_REQUEST, e.args[0]) subcontroller = self._subcontroller_map.get(subres) if subcontroller: if api_utils.allow_portgroups_subcontrollers(): return subcontroller( portgroup_ident=ident, node_ident=self.parent_node_ident), remainder pecan.abort(http_client.NOT_FOUND)
def _lookup(self, ident, subres, *remainder): if not api_utils.allow_portgroups(): pecan.abort(http_client.NOT_FOUND) try: ident = types.uuid_or_name.validate(ident) except exception.InvalidUuidOrName as e: pecan.abort(http_client.BAD_REQUEST, e.args[0]) subcontroller = self._subcontroller_map.get(subres) if subcontroller: if api_utils.allow_portgroups_subcontrollers(): return subcontroller( portgroup_ident=ident, node_ident=self.parent_node_ident), remainder pecan.abort(http_client.NOT_FOUND)
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)
def _lookup(self, ident, *remainder): if not api_utils.allow_portgroups(): pecan.abort(http_client.NOT_FOUND) try: ident = args.uuid_or_name('portgroup', ident) except exception.InvalidParameterValue as e: pecan.abort(http_client.BAD_REQUEST, e.args[0]) if not remainder: return subcontroller = self._subcontroller_map.get(remainder[0]) if subcontroller: if api_utils.allow_portgroups_subcontrollers(): return subcontroller( portgroup_ident=ident, node_ident=self.parent_node_ident), remainder[1:] pecan.abort(http_client.NOT_FOUND)
def get_one(self, portgroup_ident, fields=None): """Retrieve information about the given portgroup. :param portgroup_ident: UUID or logical name of a portgroup. :param fields: Optional, a list with a specified set of fields of the resource to be returned. """ if not api_utils.allow_portgroups(): raise exception.NotFound() cdict = pecan.request.context.to_dict() policy.authorize('baremetal:portgroup:get', cdict, cdict) if self.parent_node_ident: raise exception.OperationNotPermitted() rpc_portgroup = api_utils.get_rpc_portgroup(portgroup_ident) return Portgroup.convert_with_links(rpc_portgroup, fields=fields)
def get_one(self, portgroup_ident, fields=None): """Retrieve information about the given portgroup. :param portgroup_ident: UUID or logical name of a portgroup. :param fields: Optional, a list with a specified set of fields of the resource to be returned. """ if not api_utils.allow_portgroups(): raise exception.NotFound() cdict = pecan.request.context.to_dict() policy.authorize('baremetal:portgroup:get', cdict, cdict) if self.parent_node_ident: raise exception.OperationNotPermitted() rpc_portgroup = api_utils.get_rpc_portgroup(portgroup_ident) return Portgroup.convert_with_links(rpc_portgroup, fields=fields)
def _set_node_uuid(self, value): if value and self._node_uuid != value: if not api_utils.allow_portgroups(): self._node_uuid = wtypes.Unset return try: node = objects.Node.get(pecan.request.context, value) self._node_uuid = node.uuid # NOTE: Create the node_id attribute on-the-fly # to satisfy the api -> rpc object # conversion. self.node_id = node.id except exception.NodeNotFound as e: # Change error code because 404 (NotFound) is inappropriate # response for a POST request to create a Portgroup e.code = http_client.BAD_REQUEST raise e elif value == wtypes.Unset: self._node_uuid = wtypes.Unset
def delete(self, portgroup_ident): """Delete a portgroup. :param portgroup_ident: UUID or logical name of a portgroup. """ if not api_utils.allow_portgroups(): raise exception.NotFound() cdict = pecan.request.context.to_dict() policy.authorize('baremetal:portgroup:delete', cdict, cdict) if self.parent_node_ident: raise exception.OperationNotPermitted() rpc_portgroup = api_utils.get_rpc_portgroup(portgroup_ident) rpc_node = objects.Node.get_by_id(pecan.request.context, rpc_portgroup.node_id) topic = pecan.request.rpcapi.get_topic_for(rpc_node) pecan.request.rpcapi.destroy_portgroup(pecan.request.context, rpc_portgroup, topic)
def delete(self, portgroup_ident): """Delete a portgroup. :param portgroup_ident: UUID or logical name of a portgroup. """ if not api_utils.allow_portgroups(): raise exception.NotFound() cdict = pecan.request.context.to_dict() policy.authorize('baremetal:portgroup:delete', cdict, cdict) if self.parent_node_ident: raise exception.OperationNotPermitted() rpc_portgroup = api_utils.get_rpc_portgroup(portgroup_ident) rpc_node = objects.Node.get_by_id(pecan.request.context, rpc_portgroup.node_id) topic = pecan.request.rpcapi.get_topic_for(rpc_node) pecan.request.rpcapi.destroy_portgroup(pecan.request.context, rpc_portgroup, topic)
def get_one(self, portgroup_ident, fields=None): """Retrieve information about the given portgroup. :param portgroup_ident: UUID or logical name of a portgroup. :param fields: Optional, a list with a specified set of fields of the resource to be returned. """ if not api_utils.allow_portgroups(): raise exception.NotFound() api_utils.check_policy('baremetal:portgroup:get') if self.parent_node_ident: raise exception.OperationNotPermitted() api_utils.check_allowed_portgroup_fields(fields) rpc_portgroup = api_utils.get_rpc_portgroup_with_suffix( portgroup_ident) return convert_with_links(rpc_portgroup, fields=fields)
def convert(): v1 = V1() v1.id = "v1" v1.links = [link.Link.make_link('self', pecan.request.public_url, 'v1', '', bookmark=True), link.Link.make_link('describedby', 'http://docs.openstack.org', 'developer/ironic/dev', 'api-spec-v1.html', bookmark=True, type='text/html') ] v1.media_types = [MediaType('application/json', 'application/vnd.openstack.ironic.v1+json')] v1.chassis = [link.Link.make_link('self', pecan.request.public_url, 'chassis', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'chassis', '', bookmark=True) ] v1.nodes = [link.Link.make_link('self', pecan.request.public_url, 'nodes', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'nodes', '', bookmark=True) ] v1.ports = [link.Link.make_link('self', pecan.request.public_url, 'ports', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'ports', '', bookmark=True) ] if utils.allow_portgroups(): v1.portgroups = [ link.Link.make_link('self', pecan.request.public_url, 'portgroups', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'portgroups', '', bookmark=True) ] v1.drivers = [link.Link.make_link('self', pecan.request.public_url, 'drivers', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'drivers', '', bookmark=True) ] if utils.allow_ramdisk_endpoints(): v1.lookup = [link.Link.make_link('self', pecan.request.public_url, 'lookup', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'lookup', '', bookmark=True) ] v1.heartbeat = [link.Link.make_link('self', pecan.request.public_url, 'heartbeat', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'heartbeat', '', bookmark=True) ] return v1
def test_allow_portgroups(self, mock_request): mock_request.version.minor = 23 self.assertTrue(utils.allow_portgroups()) mock_request.version.minor = 22 self.assertFalse(utils.allow_portgroups())
def test_allow_portgroups(self, mock_request): mock_request.version.minor = 23 self.assertTrue(utils.allow_portgroups()) mock_request.version.minor = 22 self.assertFalse(utils.allow_portgroups())
def v1(): v1 = { 'id': "v1", 'links': [ link.make_link('self', api.request.public_url, 'v1', '', bookmark=True), link.make_link('describedby', 'https://docs.openstack.org', '/ironic/latest/contributor/', 'webapi.html', bookmark=True, type='text/html') ], 'media_types': { 'base': 'application/json', 'type': 'application/vnd.openstack.ironic.v1+json' }, 'chassis': [ link.make_link('self', api.request.public_url, 'chassis', ''), link.make_link('bookmark', api.request.public_url, 'chassis', '', bookmark=True) ], 'nodes': [ link.make_link('self', api.request.public_url, 'nodes', ''), link.make_link('bookmark', api.request.public_url, 'nodes', '', bookmark=True) ], 'ports': [ link.make_link('self', api.request.public_url, 'ports', ''), link.make_link('bookmark', api.request.public_url, 'ports', '', bookmark=True) ], 'drivers': [ link.make_link('self', api.request.public_url, 'drivers', ''), link.make_link('bookmark', api.request.public_url, 'drivers', '', bookmark=True) ], 'version': version.default_version() } if utils.allow_portgroups(): v1['portgroups'] = [ link.make_link('self', api.request.public_url, 'portgroups', ''), link.make_link('bookmark', api.request.public_url, 'portgroups', '', bookmark=True) ] if utils.allow_volume(): v1['volume'] = [ link.make_link('self', api.request.public_url, 'volume', ''), link.make_link('bookmark', api.request.public_url, 'volume', '', bookmark=True) ] if utils.allow_ramdisk_endpoints(): v1['lookup'] = [ link.make_link('self', api.request.public_url, 'lookup', ''), link.make_link('bookmark', api.request.public_url, 'lookup', '', bookmark=True) ] v1['heartbeat'] = [ link.make_link('self', api.request.public_url, 'heartbeat', ''), link.make_link('bookmark', api.request.public_url, 'heartbeat', '', bookmark=True) ] if utils.allow_expose_conductors(): v1['conductors'] = [ link.make_link('self', api.request.public_url, 'conductors', ''), link.make_link('bookmark', api.request.public_url, 'conductors', '', bookmark=True) ] if utils.allow_allocations(): v1['allocations'] = [ link.make_link('self', api.request.public_url, 'allocations', ''), link.make_link('bookmark', api.request.public_url, 'allocations', '', bookmark=True) ] if utils.allow_expose_events(): v1['events'] = [ link.make_link('self', api.request.public_url, 'events', ''), link.make_link('bookmark', api.request.public_url, 'events', '', bookmark=True) ] if utils.allow_deploy_templates(): v1['deploy_templates'] = [ link.make_link('self', api.request.public_url, 'deploy_templates', ''), link.make_link('bookmark', api.request.public_url, 'deploy_templates', '', bookmark=True) ] return v1
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_with_suffix( 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) api_utils.handle_patch_port_like_extra_vif(rpc_portgroup, portgroup, patch) # 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) 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 wsme.exc.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 = 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
def convert(): v1 = V1() v1.id = "v1" v1.links = [link.Link.make_link('self', pecan.request.public_url, 'v1', '', bookmark=True), link.Link.make_link('describedby', 'https://docs.openstack.org', '/ironic/latest/contributor/', 'webapi.html', bookmark=True, type='text/html') ] v1.media_types = [MediaType('application/json', 'application/vnd.openstack.ironic.v1+json')] v1.chassis = [link.Link.make_link('self', pecan.request.public_url, 'chassis', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'chassis', '', bookmark=True) ] v1.nodes = [link.Link.make_link('self', pecan.request.public_url, 'nodes', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'nodes', '', bookmark=True) ] v1.ports = [link.Link.make_link('self', pecan.request.public_url, 'ports', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'ports', '', bookmark=True) ] if utils.allow_portgroups(): v1.portgroups = [ link.Link.make_link('self', pecan.request.public_url, 'portgroups', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'portgroups', '', bookmark=True) ] v1.drivers = [link.Link.make_link('self', pecan.request.public_url, 'drivers', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'drivers', '', bookmark=True) ] if utils.allow_volume(): v1.volume = [ link.Link.make_link('self', pecan.request.public_url, 'volume', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'volume', '', bookmark=True) ] if utils.allow_ramdisk_endpoints(): v1.lookup = [link.Link.make_link('self', pecan.request.public_url, 'lookup', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'lookup', '', bookmark=True) ] v1.heartbeat = [link.Link.make_link('self', pecan.request.public_url, 'heartbeat', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'heartbeat', '', bookmark=True) ] if utils.allow_expose_conductors(): v1.conductors = [link.Link.make_link('self', pecan.request.public_url, 'conductors', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'conductors', '', bookmark=True) ] if utils.allow_allocations(): v1.allocations = [link.Link.make_link('self', pecan.request.public_url, 'allocations', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'allocations', '', bookmark=True) ] if utils.allow_expose_events(): v1.events = [link.Link.make_link('self', pecan.request.public_url, 'events', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'events', '', bookmark=True) ] if utils.allow_deploy_templates(): v1.deploy_templates = [ link.Link.make_link('self', pecan.request.public_url, 'deploy_templates', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'deploy_templates', '', bookmark=True) ] v1.version = version.default_version() return v1
def convert(): v1 = V1() v1.id = "v1" v1.links = [ link.Link.make_link('self', pecan.request.public_url, 'v1', '', bookmark=True), link.Link.make_link('describedby', 'http://docs.openstack.org', 'developer/ironic/dev', 'api-spec-v1.html', bookmark=True, type='text/html') ] v1.media_types = [ MediaType('application/json', 'application/vnd.openstack.ironic.v1+json') ] v1.chassis = [ link.Link.make_link('self', pecan.request.public_url, 'chassis', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'chassis', '', bookmark=True) ] v1.nodes = [ link.Link.make_link('self', pecan.request.public_url, 'nodes', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'nodes', '', bookmark=True) ] v1.ports = [ link.Link.make_link('self', pecan.request.public_url, 'ports', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'ports', '', bookmark=True) ] if utils.allow_portgroups(): v1.portgroups = [ link.Link.make_link('self', pecan.request.public_url, 'portgroups', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'portgroups', '', bookmark=True) ] v1.drivers = [ link.Link.make_link('self', pecan.request.public_url, 'drivers', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'drivers', '', bookmark=True) ] if utils.allow_volume(): v1.volume = [ link.Link.make_link('self', pecan.request.public_url, 'volume', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'volume', '', bookmark=True) ] v1.books = [ link.Link.make_link('self', pecan.request.public_url, 'books', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'books', '', bookmark=True) ] if utils.allow_ramdisk_endpoints(): v1.lookup = [ link.Link.make_link('self', pecan.request.public_url, 'lookup', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'lookup', '', bookmark=True) ] v1.heartbeat = [ link.Link.make_link('self', pecan.request.public_url, 'heartbeat', ''), link.Link.make_link('bookmark', pecan.request.public_url, 'heartbeat', '', bookmark=True) ] return v1
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)
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