def delete(self, port_uuid): """Delete a port. :param port_uuid: UUID of a port. :raises: OperationNotPermitted, HTTPNotFound """ context = pecan.request.context cdict = context.to_policy_values() policy.authorize('baremetal:port:delete', cdict, cdict) if self.parent_node_ident or self.parent_portgroup_ident: raise exception.OperationNotPermitted() rpc_port = objects.Port.get_by_uuid(context, port_uuid) rpc_node = objects.Node.get_by_id(context, rpc_port.node_id) portgroup_uuid = None if rpc_port.portgroup_id: portgroup = objects.Portgroup.get_by_id(context, rpc_port.portgroup_id) portgroup_uuid = portgroup.uuid notify_extra = {'node_uuid': rpc_node.uuid, 'portgroup_uuid': portgroup_uuid} notify.emit_start_notification(context, rpc_port, 'delete', **notify_extra) with notify.handle_error_notification(context, rpc_port, 'delete', **notify_extra): topic = pecan.request.rpcapi.get_topic_for(rpc_node) pecan.request.rpcapi.destroy_port(context, rpc_port, topic) notify.emit_end_notification(context, rpc_port, 'delete', **notify_extra)
def logical_disk_properties(self, driver_name): """Returns the logical disk properties for the driver. :param driver_name: Name of the driver. :returns: A dictionary containing the properties that can be mentioned for logical disks and a textual description for them. :raises: UnsupportedDriverExtension if the driver doesn't support RAID configuration. :raises: NotAcceptable, if requested version of the API is less than 1.12. :raises: DriverNotFound, if driver is not loaded on any of the conductors. """ cdict = pecan.request.context.to_policy_values() policy.authorize('baremetal:driver:get_raid_logical_disk_properties', cdict, cdict) if not api_utils.allow_raid_config(): raise exception.NotAcceptable() if driver_name not in _RAID_PROPERTIES: topic = pecan.request.rpcapi.get_topic_for_driver(driver_name) try: info = pecan.request.rpcapi.get_raid_logical_disk_properties( pecan.request.context, driver_name, topic=topic) except exception.UnsupportedDriverExtension as e: # Change error code as 404 seems appropriate because RAID is a # standard interface and all drivers might not have it. e.code = http_client.NOT_FOUND raise _RAID_PROPERTIES[driver_name] = info return _RAID_PROPERTIES[driver_name]
def post(self, node_ident, callback_url): """Process a heartbeat from the deploy ramdisk. :param node_ident: the UUID or logical name of a node. :param callback_url: the URL to reach back to the ramdisk. :raises: NodeNotFound if node with provided UUID or name was not found. :raises: InvalidUuidOrName if node_ident is not valid name or UUID. :raises: NoValidHost if RPC topic for node could not be retrieved. :raises: NotFound if requested API version does not allow this endpoint. """ if not api_utils.allow_ramdisk_endpoints(): raise exception.NotFound() cdict = pecan.request.context.to_policy_values() policy.authorize('baremetal:node:ipa_heartbeat', cdict, cdict) rpc_node = api_utils.get_rpc_node(node_ident) try: topic = pecan.request.rpcapi.get_topic_for(rpc_node) except exception.NoValidHost as e: e.code = http_client.BAD_REQUEST raise pecan.request.rpcapi.heartbeat(pecan.request.context, rpc_node.uuid, callback_url, topic=topic)
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 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 get_all(self, node=None, resource_class=None, state=None, marker=None, limit=None, sort_key='id', sort_dir='asc', fields=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. """ if not api_utils.allow_allocations(): raise exception.NotFound() cdict = pecan.request.context.to_policy_values() policy.authorize('baremetal:allocation:get', cdict, cdict) return self._get_allocations_collection(node, resource_class, state, marker, limit, sort_key, sort_dir, fields=fields)
def post(self, port): """Create a new port. :param port: a port within the request body. :raises: NotAcceptable, HTTPNotFound """ 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() 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)
def delete(self, port_uuid): """Delete a port. :param port_uuid: UUID of a port. :raises: OperationNotPermitted, HTTPNotFound """ context = pecan.request.context cdict = context.to_policy_values() policy.authorize('baremetal:port:delete', cdict, cdict) if self.parent_node_ident or self.parent_portgroup_ident: raise exception.OperationNotPermitted() rpc_port = objects.Port.get_by_uuid(context, port_uuid) rpc_node = objects.Node.get_by_id(context, rpc_port.node_id) portgroup_uuid = None if rpc_port.portgroup_id: portgroup = objects.Portgroup.get_by_id(context, rpc_port.portgroup_id) portgroup_uuid = portgroup.uuid notify_extra = { 'node_uuid': rpc_node.uuid, 'portgroup_uuid': portgroup_uuid } notify.emit_start_notification(context, rpc_port, 'delete', **notify_extra) with notify.handle_error_notification(context, rpc_port, 'delete', **notify_extra): topic = pecan.request.rpcapi.get_topic_for(rpc_node) pecan.request.rpcapi.destroy_port(context, rpc_port, topic) notify.emit_end_notification(context, rpc_port, 'delete', **notify_extra)
def patch(self, chassis_uuid, patch): """Update an existing chassis. :param chassis_uuid: UUID of a chassis. :param patch: a json PATCH document to apply to this chassis. """ cdict = pecan.request.context.to_dict() policy.authorize('baremetal:chassis:update', cdict, cdict) rpc_chassis = objects.Chassis.get_by_uuid(pecan.request.context, chassis_uuid) try: chassis = Chassis( **api_utils.apply_jsonpatch(rpc_chassis.as_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.Chassis.fields: try: patch_val = getattr(chassis, field) except AttributeError: # Ignore fields that aren't exposed in the API continue if patch_val == wtypes.Unset: patch_val = None if rpc_chassis[field] != patch_val: rpc_chassis[field] = patch_val rpc_chassis.save() return Chassis.convert_with_links(rpc_chassis)
def get_all(self, marker=None, limit=None, sort_key='id', sort_dir='asc', fields=None, detail=None): """Retrieve a list of chassis. :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. """ cdict = api.request.context.to_policy_values() policy.authorize('baremetal:chassis:get', cdict, cdict) api_utils.check_allow_specify_fields(fields) fields = api_utils.get_request_return_fields(fields, detail, _DEFAULT_RETURN_FIELDS) return self._get_chassis_collection(marker, limit, sort_key, sort_dir, fields=fields, detail=detail)
def get_one(self, driver_name): """Retrieve a single driver.""" # NOTE(russell_h): There is no way to make this more efficient than # retrieving a list of drivers using the current sqlalchemy schema, but # this path must be exposed for Pecan to route any paths we might # choose to expose below it. cdict = pecan.request.context.to_policy_values() policy.authorize('baremetal:driver:get', cdict, cdict) def _find_driver(driver_dict, driver_type): for name, hosts in driver_dict.items(): if name == driver_name: return Driver.convert_with_links(name, list(hosts), driver_type, detail=True) hw_type_dict = pecan.request.dbapi.get_active_hardware_type_dict() driver = _find_driver(hw_type_dict, 'dynamic') if driver: return driver driver_dict = pecan.request.dbapi.get_active_driver_dict() driver = _find_driver(driver_dict, 'classic') if driver: return driver raise exception.DriverNotFound(driver_name=driver_name)
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, target_uuid): """Delete a volume target. :param target_uuid: UUID of a volume target. :raises: OperationNotPermitted if accessed with specifying a parent node. :raises: NodeLocked if node is locked by another conductor :raises: NodeNotFound if the node associated with the target does not exist :raises: VolumeTargetNotFound if the volume target cannot be found :raises: InvalidStateRequested If a node associated with the volume target is not powered off. """ context = pecan.request.context cdict = context.to_policy_values() policy.authorize('baremetal:volume:delete', cdict, cdict) if self.parent_node_ident: raise exception.OperationNotPermitted() rpc_target = objects.VolumeTarget.get_by_uuid(context, target_uuid) rpc_node = objects.Node.get_by_id(context, rpc_target.node_id) notify.emit_start_notification(context, rpc_target, 'delete', node_uuid=rpc_node.uuid) with notify.handle_error_notification(context, rpc_target, 'delete', node_uuid=rpc_node.uuid): topic = pecan.request.rpcapi.get_topic_for(rpc_node) pecan.request.rpcapi.destroy_volume_target(context, rpc_target, topic) notify.emit_end_notification(context, rpc_target, 'delete', node_uuid=rpc_node.uuid)
def delete(self, allocation_ident): """Delete an allocation. :param allocation_ident: UUID or logical name of an allocation. """ context = pecan.request.context cdict = context.to_policy_values() policy.authorize('baremetal:allocation:delete', cdict, cdict) rpc_allocation = api_utils.get_rpc_allocation_with_suffix( allocation_ident) if rpc_allocation.node_id: node_uuid = objects.Node.get_by_id(pecan.request.context, rpc_allocation.node_id).uuid else: node_uuid = None notify.emit_start_notification(context, rpc_allocation, 'delete', node_uuid=node_uuid) with notify.handle_error_notification(context, rpc_allocation, 'delete', node_uuid=node_uuid): topic = pecan.request.rpcapi.get_random_topic() pecan.request.rpcapi.destroy_allocation(context, rpc_allocation, topic) notify.emit_end_notification(context, rpc_allocation, 'delete', node_uuid=node_uuid)
def patch(self, chassis_uuid, patch): """Update an existing chassis. :param chassis_uuid: UUID of a chassis. :param patch: a json PATCH document to apply to this chassis. """ context = api.request.context cdict = context.to_policy_values() policy.authorize('baremetal:chassis:update', cdict, cdict) rpc_chassis = objects.Chassis.get_by_uuid(context, chassis_uuid) chassis = Chassis( **api_utils.apply_jsonpatch(rpc_chassis.as_dict(), patch)) # Update only the fields that have changed for field in objects.Chassis.fields: try: patch_val = getattr(chassis, field) except AttributeError: # Ignore fields that aren't exposed in the API continue if patch_val == atypes.Unset: patch_val = None if rpc_chassis[field] != patch_val: rpc_chassis[field] = patch_val notify.emit_start_notification(context, rpc_chassis, 'update') with notify.handle_error_notification(context, rpc_chassis, 'update'): rpc_chassis.save() notify.emit_end_notification(context, rpc_chassis, 'update') return Chassis.convert_with_links(rpc_chassis)
def delete(self): context = pecan.request.context cdict = context.to_policy_values() policy.authorize('baremetal:allocation:delete', cdict, cdict) rpc_node = api_utils.get_rpc_node_with_suffix(self.parent_node_ident) allocations = objects.Allocation.list( pecan.request.context, filters={'node_uuid': rpc_node.uuid}) try: rpc_allocation = allocations[0] except IndexError: raise exception.AllocationNotFound( _("Allocation for node %s was not found") % self.parent_node_ident) notify.emit_start_notification(context, rpc_allocation, 'delete', node_uuid=rpc_node.uuid) with notify.handle_error_notification(context, rpc_allocation, 'delete', node_uuid=rpc_node.uuid): topic = pecan.request.rpcapi.get_random_topic() pecan.request.rpcapi.destroy_allocation(context, rpc_allocation, topic) notify.emit_end_notification(context, rpc_allocation, 'delete', node_uuid=rpc_node.uuid)
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) 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): # TODO(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. Further consideration is # required determine how best to support rolling upgrades from a # release in which ports are created by the API service to one in # which they are created by the conductor service, while ensuring # that all required validation is performed. topic = pecan.request.rpcapi.get_topic_for(rpc_node) new_port = pecan.request.rpcapi.create_port( context, rpc_port, topic) 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)
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, 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) 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): # TODO(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. Further consideration is # required determine how best to support rolling upgrades from a # release in which ports are created by the API service to one in # which they are created by the conductor service, while ensuring # that all required validation is performed. topic = pecan.request.rpcapi.get_topic_for(rpc_node) new_port = pecan.request.rpcapi.create_port(context, rpc_port, topic) 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)
def check_port_policy_and_retrieve(policy_name, port_uuid): """Check if the specified policy authorizes this request on a port. :param: policy_name: Name of the policy to check. :param: port_uuid: the UUID of a port. :raises: HTTPForbidden if the policy forbids access. :raises: NodeNotFound if the node is not found. :return: RPC port identified by port_uuid and associated node """ context = api.request.context cdict = context.to_policy_values() try: rpc_port = objects.Port.get_by_uuid(context, port_uuid) except exception.PortNotFound: # don't expose non-existence of port unless requester # has generic access to policy policy.authorize(policy_name, cdict, cdict) raise rpc_node = objects.Node.get_by_id(context, rpc_port.node_id) target_dict = dict(cdict) target_dict['node.owner'] = rpc_node['owner'] target_dict['node.lessee'] = rpc_node['lessee'] policy.authorize(policy_name, target_dict, cdict) return rpc_port, rpc_node
def logical_disk_properties(self, driver_name): """Returns the logical disk properties for the driver. :param driver_name: Name of the driver. :returns: A dictionary containing the properties that can be mentioned for logical disks and a textual description for them. :raises: UnsupportedDriverExtension if the driver doesn't support RAID configuration. :raises: NotAcceptable, if requested version of the API is less than 1.12. :raises: DriverNotFound, if driver is not loaded on any of the conductors. """ cdict = api.request.context.to_policy_values() policy.authorize('baremetal:driver:get_raid_logical_disk_properties', cdict, cdict) if not api_utils.allow_raid_config(): raise exception.NotAcceptable() if driver_name not in _RAID_PROPERTIES: topic = api.request.rpcapi.get_topic_for_driver(driver_name) try: info = api.request.rpcapi.get_raid_logical_disk_properties( api.request.context, driver_name, topic=topic) except exception.UnsupportedDriverExtension as e: # Change error code as 404 seems appropriate because RAID is a # standard interface and all drivers might not have it. e.code = http_client.NOT_FOUND raise _RAID_PROPERTIES[driver_name] = info return _RAID_PROPERTIES[driver_name]
def delete(self): context = api.request.context cdict = context.to_policy_values() policy.authorize('baremetal:allocation:delete', cdict, cdict) rpc_node = api_utils.get_rpc_node_with_suffix(self.parent_node_ident) allocations = objects.Allocation.list( api.request.context, filters={'node_uuid': rpc_node.uuid}) try: rpc_allocation = allocations[0] except IndexError: raise exception.AllocationNotFound( _("Allocation for node %s was not found") % self.parent_node_ident) notify.emit_start_notification(context, rpc_allocation, 'delete', node_uuid=rpc_node.uuid) with notify.handle_error_notification(context, rpc_allocation, 'delete', node_uuid=rpc_node.uuid): topic = api.request.rpcapi.get_random_topic() api.request.rpcapi.destroy_allocation(context, rpc_allocation, topic) notify.emit_end_notification(context, rpc_allocation, 'delete', node_uuid=rpc_node.uuid)
def get_all(self, type=None, detail=None): """Retrieve a list of drivers.""" # FIXME(deva): formatting of the auto-generated REST API docs # will break from a single-line doc string. # This is a result of a bug in sphinxcontrib-pecanwsme # https://github.com/dreamhost/sphinxcontrib-pecanwsme/issues/8 cdict = pecan.request.context.to_policy_values() policy.authorize('baremetal:driver:get', cdict, cdict) api_utils.check_allow_driver_detail(detail) api_utils.check_allow_filter_driver_type(type) if type not in (None, 'classic', 'dynamic'): raise exception.Invalid( _('"type" filter must be one of "classic" or "dynamic", ' 'if specified.')) driver_list = {} hw_type_dict = {} if type is None or type == 'classic': driver_list = pecan.request.dbapi.get_active_driver_dict() if type is None or type == 'dynamic': hw_type_dict = pecan.request.dbapi.get_active_hardware_type_dict() return DriverList.convert_with_links(driver_list, hw_type_dict, detail=detail)
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 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 patch(self, chassis_uuid, patch): """Update an existing chassis. :param chassis_uuid: UUID of a chassis. :param patch: a json PATCH document to apply to this chassis. """ context = pecan.request.context cdict = context.to_policy_values() policy.authorize('baremetal:chassis:update', cdict, cdict) rpc_chassis = objects.Chassis.get_by_uuid(context, chassis_uuid) chassis = Chassis( **api_utils.apply_jsonpatch(rpc_chassis.as_dict(), patch)) # Update only the fields that have changed for field in objects.Chassis.fields: try: patch_val = getattr(chassis, field) except AttributeError: # Ignore fields that aren't exposed in the API continue if patch_val == wtypes.Unset: patch_val = None if rpc_chassis[field] != patch_val: rpc_chassis[field] = patch_val notify.emit_start_notification(context, rpc_chassis, 'update') with notify.handle_error_notification(context, rpc_chassis, 'update'): rpc_chassis.save() notify.emit_end_notification(context, rpc_chassis, 'update') return Chassis.convert_with_links(rpc_chassis)
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 delete(self, connector_uuid): """Delete a volume connector. :param connector_uuid: UUID of a volume connector. :raises: OperationNotPermitted if accessed with specifying a parent node. :raises: NodeLocked if node is locked by another conductor :raises: NodeNotFound if the node associated with the connector does not exist :raises: VolumeConnectorNotFound if the volume connector cannot be found :raises: InvalidStateRequested If a node associated with the volume connector is not powered off. """ context = pecan.request.context cdict = context.to_policy_values() policy.authorize('baremetal:volume:delete', cdict, cdict) if self.parent_node_ident: raise exception.OperationNotPermitted() rpc_connector = objects.VolumeConnector.get_by_uuid(context, connector_uuid) rpc_node = objects.Node.get_by_id(context, rpc_connector.node_id) notify.emit_start_notification(context, rpc_connector, 'delete', node_uuid=rpc_node.uuid) with notify.handle_error_notification(context, rpc_connector, 'delete', node_uuid=rpc_node.uuid): topic = pecan.request.rpcapi.get_topic_for(rpc_node) pecan.request.rpcapi.destroy_volume_connector(context, rpc_connector, topic) notify.emit_end_notification(context, rpc_connector, 'delete', node_uuid=rpc_node.uuid)
def post(self, evts): if not api_utils.allow_expose_events(): raise exception.NotFound() cdict = pecan.request.context.to_policy_values() policy.authorize('baremetal:events:post', cdict, cdict) for e in evts.events: LOG.debug("Received external event: %s", e)
def get_all(self, node=None, resource_class=None, state=None, marker=None, limit=None, sort_key='id', sort_dir='asc', fields=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. """ cdict = pecan.request.context.to_policy_values() policy.authorize('baremetal:allocation:get', cdict, cdict) return self._get_allocations_collection(node, resource_class, state, marker, limit, sort_key, sort_dir, fields=fields)
def check_node_policy_and_retrieve(policy_name, node_ident, with_suffix=False): """Check if the specified policy authorizes this request on a node. :param: policy_name: Name of the policy to check. :param: node_ident: the UUID or logical name of a node. :param: with_suffix: whether the RPC node should include the suffix :raises: HTTPForbidden if the policy forbids access. :raises: NodeNotFound if the node is not found. :return: RPC node identified by node_ident """ try: if with_suffix: rpc_node = get_rpc_node_with_suffix(node_ident) else: rpc_node = get_rpc_node(node_ident) except exception.NodeNotFound: # don't expose non-existence of node unless requester # has generic access to policy cdict = api.request.context.to_policy_values() policy.authorize(policy_name, cdict, cdict) raise check_owner_policy('node', policy_name, rpc_node['owner'], rpc_node['lessee']) return rpc_node
def post(self, node_ident, callback_url, agent_version=None, agent_token=None): """Process a heartbeat from the deploy ramdisk. :param node_ident: the UUID or logical name of a node. :param callback_url: the URL to reach back to the ramdisk. :param agent_version: The version of the agent that is heartbeating. ``None`` indicates that the agent that is heartbeating is a version before sending agent_version was introduced so agent v3.0.0 (the last release before sending agent_version was introduced) will be assumed. :param agent_token: randomly generated validation token. :raises: NodeNotFound if node with provided UUID or name was not found. :raises: InvalidUuidOrName if node_ident is not valid name or UUID. :raises: NoValidHost if RPC topic for node could not be retrieved. :raises: NotFound if requested API version does not allow this endpoint. """ if not api_utils.allow_ramdisk_endpoints(): raise exception.NotFound() if agent_version and not api_utils.allow_agent_version_in_heartbeat(): raise exception.InvalidParameterValue( _('Field "agent_version" not recognised')) cdict = api.request.context.to_policy_values() policy.authorize('baremetal:node:ipa_heartbeat', cdict, cdict) rpc_node = api_utils.get_rpc_node_with_suffix(node_ident) dii = rpc_node['driver_internal_info'] agent_url = dii.get('agent_url') # If we have an agent_url on file, and we get something different # we should fail because this is unexpected behavior of the agent. if agent_url is not None and agent_url != callback_url: LOG.error('Received heartbeat for node %(node)s with ' 'callback URL %(url)s. This is not expected, ' 'and the heartbeat will not be processed.', {'node': rpc_node.uuid, 'url': callback_url}) raise exception.Invalid( _('Detected change in ramdisk provided ' '"callback_url"')) # NOTE(TheJulia): If tokens are required, lets go ahead and fail the # heartbeat very early on. token_required = CONF.require_agent_token if token_required and agent_token is None: LOG.error('Agent heartbeat received for node %(node)s ' 'without an agent token.', {'node': node_ident}) raise exception.InvalidParameterValue( _('Agent token is required for heartbeat processing.')) try: topic = api.request.rpcapi.get_topic_for(rpc_node) except exception.NoValidHost as e: e.code = http_client.BAD_REQUEST raise api.request.rpcapi.heartbeat( api.request.context, rpc_node.uuid, callback_url, agent_version, agent_token, topic=topic)
def post(self, allocation): """Create a new allocation. :param allocation: an allocation within the request body. """ context = pecan.request.context cdict = context.to_policy_values() policy.authorize('baremetal:allocation:create', cdict, cdict) if allocation.node_uuid is not wtypes.Unset: msg = _("Cannot set node_uuid when creating an allocation") raise exception.Invalid(msg) if (allocation.name and not api_utils.is_valid_logical_name(allocation.name)): msg = _("Cannot create allocation with invalid name " "'%(name)s'") % { 'name': allocation.name } raise exception.Invalid(msg) if allocation.traits: for trait in allocation.traits: api_utils.validate_trait(trait) if allocation.candidate_nodes: # Convert nodes from names to UUIDs and check their validity try: converted = pecan.request.dbapi.check_node_list( allocation.candidate_nodes) except exception.NodeNotFound as exc: exc.code = http_client.BAD_REQUEST raise else: # Make sure we keep the ordering of candidate nodes. allocation.candidate_nodes = [ converted[ident] for ident in allocation.candidate_nodes ] all_dict = allocation.as_dict() # NOTE(yuriyz): UUID is mandatory for notifications payload if not all_dict.get('uuid'): all_dict['uuid'] = uuidutils.generate_uuid() new_allocation = objects.Allocation(context, **all_dict) topic = pecan.request.rpcapi.get_random_topic() notify.emit_start_notification(context, new_allocation, 'create') with notify.handle_error_notification(context, new_allocation, 'create'): new_allocation = pecan.request.rpcapi.create_allocation( context, new_allocation, topic) notify.emit_end_notification(context, new_allocation, 'create') # Set the HTTP Location Header pecan.response.location = link.build_url('allocations', new_allocation.uuid) return Allocation.convert_with_links(new_allocation)
def get(self): if not api_utils.allow_volume(): raise exception.NotFound() cdict = api.request.context.to_policy_values() policy.authorize('baremetal:volume:get', cdict, cdict) return Volume.convert(self.parent_node_ident)
def check_policy(policy_name): """Check if the specified policy is authorised for this request. :policy_name: Name of the policy to check. :raises: HTTPForbidden if the policy forbids access. """ cdict = api.request.context.to_policy_values() policy.authorize(policy_name, cdict, cdict)
def check_policy(policy_name): """Check if the specified policy is authorised for this request. :policy_name: Name of the policy to check. :raises: HTTPForbidden if the policy forbids access. """ cdict = pecan.request.context.to_policy_values() policy.authorize(policy_name, cdict, cdict)
def get(self): if not api_utils.allow_volume(): raise exception.NotFound() cdict = pecan.request.context.to_policy_values() policy.authorize('baremetal:volume:get', cdict, cdict) return Volume.convert(self.parent_node_ident)
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, 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() 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 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() new_port = objects.Port(context, **pdict) notify.emit_start_notification(context, new_port, 'create', node_uuid=port.node_uuid) with notify.handle_error_notification(context, new_port, 'create', node_uuid=port.node_uuid): new_port.create() notify.emit_end_notification(context, new_port, 'create', node_uuid=port.node_uuid) # Set the HTTP Location Header pecan.response.location = link.build_url('ports', new_port.uuid) return Port.convert_with_links(new_port)
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. 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. :raises: NotAcceptable """ cdict = pecan.request.context.to_dict() policy.authorize('baremetal:port:get', cdict, cdict) api_utils.check_allow_specify_fields(fields) if (fields and not api_utils.allow_port_advanced_net_fields() and set(fields).intersection(self.advanced_net_fields)): 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, marker, limit, sort_key, sort_dir, fields=fields)
def get_all(self, node=None, marker=None, limit=None, sort_key='id', sort_dir='asc', fields=None, detail=None): """Retrieve a list of volume connectors. :param node: UUID or name of a node, to get only volume connectors for that node. :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 detail: Optional, whether to retrieve with detail. :returns: a list of volume connectors, or an empty list if no volume connector is found. :raises: InvalidParameterValue if sort_key does not exist :raises: InvalidParameterValue if sort key is invalid for sorting. :raises: InvalidParameterValue if both fields and detail are specified. """ cdict = pecan.request.context.to_policy_values() policy.authorize('baremetal:volume:get', cdict, cdict) if fields is None and not detail: fields = _DEFAULT_RETURN_FIELDS if fields and detail: raise exception.InvalidParameterValue( _("Can't fetch a subset of fields with 'detail' set")) # cache node volume connection info if node and CONF.api.enable_data_volume_manage: rpc_node = api_utils.get_rpc_node(node) topic = pecan.request.rpcapi.get_topic_for(rpc_node) return pecan.request.rpcapi.do_node_data_volume_connection( rpc_node.uuid, topic=topic) resource_url = 'volume/connectors' return self._get_volume_connectors_collection( node, marker, limit, sort_key, sort_dir, resource_url=resource_url, fields=fields, detail=detail)
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_dict() policy.authorize('baremetal:port:get', cdict, cdict) api_utils.check_allow_specify_fields(fields) if fields: 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 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)
def post(self, allocation): """Create a new allocation. :param allocation: an allocation within the request body. """ context = pecan.request.context cdict = context.to_policy_values() policy.authorize('baremetal:allocation:create', cdict, cdict) if allocation.node_uuid is not wtypes.Unset: msg = _("Cannot set node_uuid when creating an allocation") raise exception.Invalid(msg) if (allocation.name and not api_utils.is_valid_logical_name(allocation.name)): msg = _("Cannot create allocation with invalid name " "'%(name)s'") % {'name': allocation.name} raise exception.Invalid(msg) if allocation.traits: for trait in allocation.traits: api_utils.validate_trait(trait) if allocation.candidate_nodes: # Convert nodes from names to UUIDs and check their validity try: converted = pecan.request.dbapi.check_node_list( allocation.candidate_nodes) except exception.NodeNotFound as exc: exc.code = http_client.BAD_REQUEST raise else: # Make sure we keep the ordering of candidate nodes. allocation.candidate_nodes = [ converted[ident] for ident in allocation.candidate_nodes] all_dict = allocation.as_dict() # NOTE(yuriyz): UUID is mandatory for notifications payload if not all_dict.get('uuid'): all_dict['uuid'] = uuidutils.generate_uuid() new_allocation = objects.Allocation(context, **all_dict) topic = pecan.request.rpcapi.get_random_topic() notify.emit_start_notification(context, new_allocation, 'create') with notify.handle_error_notification(context, new_allocation, 'create'): new_allocation = pecan.request.rpcapi.create_allocation( context, new_allocation, topic) notify.emit_end_notification(context, new_allocation, 'create') # Set the HTTP Location Header pecan.response.location = link.build_url('allocations', new_allocation.uuid) return Allocation.convert_with_links(new_allocation)
def delete(self, chassis_uuid): """Delete a chassis. :param chassis_uuid: UUID of a chassis. """ cdict = pecan.request.context.to_dict() policy.authorize('baremetal:chassis:delete', cdict, cdict) rpc_chassis = objects.Chassis.get_by_uuid(pecan.request.context, chassis_uuid) rpc_chassis.destroy()
def get_all(self): """Retrieve a list of drivers.""" # FIXME(deva): formatting of the auto-generated REST API docs # will break from a single-line doc string. # This is a result of a bug in sphinxcontrib-pecanwsme # https://github.com/dreamhost/sphinxcontrib-pecanwsme/issues/8 cdict = pecan.request.context.to_dict() policy.authorize('baremetal:driver:get', cdict, cdict) driver_list = pecan.request.dbapi.get_active_driver_dict() return DriverList.convert_with_links(driver_list)
def get_all(self, fields=None): cdict = pecan.request.context.to_policy_values() policy.authorize('baremetal:allocation:get', cdict, cdict) result = self.inner._get_allocations_collection(self.parent_node_ident, fields=fields) try: return result.allocations[0] except IndexError: raise exception.AllocationNotFound( _("Allocation for node %s was not found") % self.parent_node_ident)
def get_one(self, allocation_ident, fields=None): """Retrieve information about the given allocation. :param allocation_ident: UUID or logical name of an allocation. :param fields: Optional, a list with a specified set of fields of the resource to be returned. """ cdict = pecan.request.context.to_policy_values() policy.authorize('baremetal:allocation:get', cdict, cdict) rpc_allocation = api_utils.get_rpc_allocation_with_suffix( allocation_ident) return Allocation.convert_with_links(rpc_allocation, fields=fields)
def post(self, chassis): """Create a new chassis. :param chassis: a chassis within the request body. """ cdict = pecan.request.context.to_dict() policy.authorize('baremetal:chassis:create', cdict, cdict) new_chassis = objects.Chassis(pecan.request.context, **chassis.as_dict()) new_chassis.create() # Set the HTTP Location Header pecan.response.location = link.build_url('chassis', new_chassis.uuid) return Chassis.convert_with_links(new_chassis)
def _default(self, driver_name, method, data=None): """Call a driver API extension. :param driver_name: name of the driver to call. :param method: name of the method, to be passed to the vendor implementation. :param data: body of data to supply to the specified method. """ cdict = pecan.request.context.to_policy_values() policy.authorize('baremetal:driver:vendor_passthru', cdict, cdict) topic = pecan.request.rpcapi.get_topic_for_driver(driver_name) return api_utils.vendor_passthru(driver_name, method, topic, data=data, driver_passthru=True)
def get_one(self, chassis_uuid, fields=None): """Retrieve information about the given chassis. :param chassis_uuid: UUID of a chassis. :param fields: Optional, a list with a specified set of fields of the resource to be returned. """ cdict = pecan.request.context.to_policy_values() policy.authorize('baremetal:chassis:get', cdict, cdict) api_utils.check_allow_specify_fields(fields) rpc_chassis = objects.Chassis.get_by_uuid(pecan.request.context, chassis_uuid) return Chassis.convert_with_links(rpc_chassis, 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() 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 delete(self, chassis_uuid): """Delete a chassis. :param chassis_uuid: UUID of a chassis. """ context = pecan.request.context cdict = context.to_policy_values() policy.authorize('baremetal:chassis:delete', cdict, cdict) rpc_chassis = objects.Chassis.get_by_uuid(context, chassis_uuid) notify.emit_start_notification(context, rpc_chassis, 'delete') with notify.handle_error_notification(context, rpc_chassis, 'delete'): rpc_chassis.destroy() notify.emit_end_notification(context, rpc_chassis, 'delete')