diff --git a/doc/source/contributor/webapi-version-history.rst b/doc/source/contributor/webapi-version-history.rst index e2f0a73b07..e9d0049613 100644 --- a/doc/source/contributor/webapi-version-history.rst +++ b/doc/source/contributor/webapi-version-history.rst @@ -2,6 +2,12 @@ REST API Version History ======================== +1.88 (Bobcat) +----------------------- + +Added the ``name`` field to the port API. It should be unique when set, +and can be used to identify a port resource. + 1.87 (Bobcat) ------------- diff --git a/ironic/api/controllers/v1/port.py b/ironic/api/controllers/v1/port.py index 74fc40a8fd..c3371b1857 100644 --- a/ironic/api/controllers/v1/port.py +++ b/ironic/api/controllers/v1/port.py @@ -51,6 +51,7 @@ PORT_SCHEMA = { 'portgroup_uuid': {'type': ['string', 'null']}, 'pxe_enabled': {'type': ['string', 'boolean', 'null']}, 'uuid': {'type': ['string', 'null']}, + 'name': {'type': ['string', 'null']}, }, 'required': ['address', 'node_uuid'], 'additionalProperties': False, @@ -67,7 +68,8 @@ PATCH_ALLOWED_FIELDS = [ 'node_uuid', 'physical_network', 'portgroup_uuid', - 'pxe_enabled' + 'pxe_enabled', + 'name', ] PORT_VALIDATOR_EXTRA = args.dict_valid( @@ -109,6 +111,9 @@ def hide_fields_in_newer_versions(port): # if requested version is < 1.53, hide is_smartnic field. if not api_utils.allow_port_is_smartnic(): port.pop('is_smartnic', None) + # if requested version is < 1.69, hide name field. + if not api_utils.allow_port_name(): + port.pop('name', None) def convert_with_links(rpc_port, fields=None, sanitize=True): @@ -124,6 +129,7 @@ def convert_with_links(rpc_port, fields=None, sanitize=True): 'physical_network', 'pxe_enabled', 'node_uuid', + 'name', ) ) if rpc_port.portgroup_id: @@ -344,6 +350,9 @@ class PortsController(rest.RestController): if (not api_utils.allow_local_link_connection_network_type() and 'network_type' in fields['local_link_connection']): raise exception.NotAcceptable() + if ('name' in fields + and not api_utils.allow_port_name()): + raise exception.NotAcceptable() @METRICS.timer('PortsController.get_all') @method.expose() @@ -484,11 +493,11 @@ class PortsController(rest.RestController): @METRICS.timer('PortsController.get_one') @method.expose() - @args.validate(port_uuid=args.uuid, fields=args.string_list) - def get_one(self, port_uuid, fields=None): + @args.validate(port_ident=args.uuid_or_name, fields=args.string_list) + def get_one(self, port_ident, fields=None): """Retrieve information about the given port. - :param port_uuid: UUID of a port. + :param port_ident: UUID or name of a port. :param fields: Optional, a list with a specified set of fields of the resource to be returned. :raises: NotAcceptable, HTTPNotFound @@ -497,7 +506,7 @@ class PortsController(rest.RestController): raise exception.OperationNotPermitted() rpc_port, rpc_node = api_utils.check_port_policy_and_retrieve( - 'baremetal:port:get', port_uuid) + 'baremetal:port:get', port_ident) api_utils.check_allow_specify_fields(fields) self._check_allowed_port_fields(fields) @@ -619,11 +628,11 @@ class PortsController(rest.RestController): @METRICS.timer('PortsController.patch') @method.expose() @method.body('patch') - @args.validate(port_uuid=args.uuid, patch=args.patch) - def patch(self, port_uuid, patch): + @args.validate(port_ident=args.uuid_or_name, patch=args.patch) + def patch(self, port_ident, patch): """Update an existing port. - :param port_uuid: UUID of a port. + :param port_ident: UUID or name of a port. :param patch: a json PATCH document to apply to this port. :raises: NotAcceptable, HTTPNotFound """ @@ -644,7 +653,7 @@ class PortsController(rest.RestController): self._check_allowed_port_fields(fields_to_check) rpc_port, rpc_node = api_utils.check_port_policy_and_retrieve( - 'baremetal:port:update', port_uuid) + 'baremetal:port:update', port_ident) port_dict = rpc_port.as_dict() # NOTE(lucasagomes): diff --git a/ironic/api/controllers/v1/utils.py b/ironic/api/controllers/v1/utils.py index 3a7806ecad..16ba0df7c4 100644 --- a/ironic/api/controllers/v1/utils.py +++ b/ironic/api/controllers/v1/utils.py @@ -1656,7 +1656,8 @@ def check_port_policy_and_retrieve(policy_name, port_ident, portgroup=False): a port or portgroup by. :raises: HTTPForbidden if the policy forbids access. - :raises: NodeNotFound if the node is not found. + :raises: PortNotFound if the port is not found. + :raises: PortgroupNotFound if the portgroup is not found. :return: RPC port identified by port_ident associated node """ context = api.request.context @@ -2021,3 +2022,11 @@ def allow_firmware_interface(): Version 1.86 of the API added support for firmware interface. """ return api.request.version.minor >= versions.MINOR_86_FIRMWARE_INTERFACE + + +def allow_port_name(): + """Check if name is allowed for ports. + + Version 1.88 of the API added name field to the port object. + """ + return api.request.version.minor >= versions.MINOR_88_PORT_NAME diff --git a/ironic/api/controllers/v1/versions.py b/ironic/api/controllers/v1/versions.py index bcdcd2e421..8fac078924 100644 --- a/ironic/api/controllers/v1/versions.py +++ b/ironic/api/controllers/v1/versions.py @@ -125,6 +125,8 @@ BASE_VERSION = 1 # v1.85: Add unhold verb # v1.86: Add firmware interface # v1.87: Add service verb +# v1.88: Add name field to port. + MINOR_0_JUNO = 0 MINOR_1_INITIAL_VERSION = 1 MINOR_2_AVAILABLE_STATE = 2 @@ -213,7 +215,7 @@ MINOR_84_CONTINUE_INSPECTION = 84 MINOR_85_UNHOLD_VERB = 85 MINOR_86_FIRMWARE_INTERFACE = 86 MINOR_87_SERVICE = 87 - +MINOR_88_PORT_NAME = 88 # When adding another version, update: # - MINOR_MAX_VERSION @@ -221,7 +223,7 @@ MINOR_87_SERVICE = 87 # explanation of what changed in the new version # - common/release_mappings.py, RELEASE_MAPPING['master']['api'] -MINOR_MAX_VERSION = MINOR_87_SERVICE +MINOR_MAX_VERSION = MINOR_88_PORT_NAME # String representations of the minor and maximum versions _MIN_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_1_INITIAL_VERSION) diff --git a/ironic/common/release_mappings.py b/ironic/common/release_mappings.py index 429d739d93..4a9bf257dd 100644 --- a/ironic/common/release_mappings.py +++ b/ironic/common/release_mappings.py @@ -617,7 +617,7 @@ RELEASE_MAPPING = { } }, 'master': { - 'api': '1.87', + 'api': '1.88', 'rpc': '1.58', 'objects': { 'Allocation': ['1.1'], diff --git a/ironic/tests/unit/api/controllers/v1/test_port.py b/ironic/tests/unit/api/controllers/v1/test_port.py index 088fe3cbea..d971e50c75 100644 --- a/ironic/tests/unit/api/controllers/v1/test_port.py +++ b/ironic/tests/unit/api/controllers/v1/test_port.py @@ -1891,6 +1891,7 @@ class TestPost(test_api_base.BaseApiTest): pdict.pop('physical_network') pdict.pop('is_smartnic') pdict.pop('portgroup_uuid') + pdict.pop('name') headers = {api_base.Version.string: str(api_v1.min_version())} response = self.post_json('/ports', pdict, headers=headers) self.assertEqual('application/json', response.content_type)