Merge "Add a new 'category' field to the Port object"
This commit is contained in:
@@ -37,6 +37,9 @@ Response to include only the specified fields, rather than the default set.
|
||||
.. versionadded:: 1.100
|
||||
Added the ``vendor`` field.
|
||||
|
||||
.. versionadded:: 1.101
|
||||
Added the ``category`` field.
|
||||
|
||||
Normal response code: 200
|
||||
|
||||
Error codes: 400,401,403,404
|
||||
@@ -90,6 +93,9 @@ Return a detailed list of bare metal Ports associated with ``portgroup_ident``.
|
||||
.. versionadded:: 1.100
|
||||
Added the ``vendor`` field.
|
||||
|
||||
.. versionadded:: 1.101
|
||||
Added the ``category`` field.
|
||||
|
||||
Normal response code: 200
|
||||
|
||||
Error codes: 400,401,403,404
|
||||
@@ -127,6 +133,7 @@ Response
|
||||
- name: port_name
|
||||
- description: port_description
|
||||
- vendor: port_vendor
|
||||
- category: port_category
|
||||
|
||||
**Example details of a Portgroup's Ports:**
|
||||
|
||||
|
@@ -59,6 +59,9 @@ By default, this query will return the uuid and address for each Port.
|
||||
.. versionadded:: 1.100
|
||||
Added the ``vendor`` field.
|
||||
|
||||
.. versionadded:: 1.101
|
||||
Added the ``category`` field.
|
||||
|
||||
Normal response code: 200
|
||||
|
||||
Request
|
||||
@@ -134,6 +137,9 @@ This method requires a Node UUID and the physical hardware address for the Port
|
||||
.. versionadded:: 1.100
|
||||
Added the ``vendor`` field.
|
||||
|
||||
.. versionadded:: 1.101
|
||||
Added the ``category`` field.
|
||||
|
||||
Normal response code: 201
|
||||
|
||||
Request
|
||||
@@ -153,6 +159,7 @@ Request
|
||||
- uuid: req_uuid
|
||||
- description: req_port_description
|
||||
- vendor: req_port_vendor
|
||||
- category: req_port_category
|
||||
|
||||
.. note::
|
||||
Either `node_ident` or `node_uuid` is a valid parameter.
|
||||
@@ -183,6 +190,7 @@ Response
|
||||
- is_smartnic: is_smartnic
|
||||
- description: port_description
|
||||
- vendor: port_vendor
|
||||
- category: port_category
|
||||
|
||||
**Example Port creation response:**
|
||||
|
||||
@@ -227,6 +235,9 @@ Return a list of bare metal Ports, with detailed information.
|
||||
.. versionadded:: 1.100
|
||||
Added the ``vendor`` field.
|
||||
|
||||
.. versionadded:: 1.101
|
||||
Added the ``category`` field.
|
||||
|
||||
Normal response code: 200
|
||||
|
||||
Request
|
||||
@@ -266,6 +277,7 @@ Response
|
||||
- is_smartnic: is_smartnic
|
||||
- description: port_description
|
||||
- vendor: port_vendor
|
||||
- category: port_category
|
||||
|
||||
**Example detailed Port list response:**
|
||||
|
||||
|
@@ -1570,6 +1570,12 @@ port_address:
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
port_category:
|
||||
description: |
|
||||
Category of the network Port. Helps to further differentiate the Port.
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
port_description:
|
||||
description: |
|
||||
Descriptive text about the network Port.
|
||||
@@ -1977,6 +1983,12 @@ req_port_address:
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
req_port_category:
|
||||
description: |
|
||||
Category of the network Port. Helps to further differentiate the Port.
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
req_port_description:
|
||||
description: |
|
||||
Descriptive text about the network Port.
|
||||
|
@@ -24,6 +24,7 @@
|
||||
"node_uuid": "6d85703a-565d-469a-96ce-30b6de53079d",
|
||||
"physical_network": "physnet1",
|
||||
"vendor": "splitrock",
|
||||
"category": "hupernet",
|
||||
"portgroup_uuid": "e43c722c-248e-4c6e-8ce8-0d8ff129387a",
|
||||
"pxe_enabled": true,
|
||||
"updated_at": "2016-08-18T22:28:49.653974+00:00",
|
||||
|
@@ -4,6 +4,7 @@
|
||||
"name": "port1",
|
||||
"description": "Physical Network",
|
||||
"vendor": "splitrock",
|
||||
"category": "hypernet",
|
||||
"address": "11:11:11:11:11:11",
|
||||
"is_smartnic": true,
|
||||
"local_link_connection": {
|
||||
|
@@ -22,6 +22,7 @@
|
||||
"name": "port1",
|
||||
"description": "Physical Network",
|
||||
"vendor": "splitrock",
|
||||
"category": "hypernet",
|
||||
"node_uuid": "6d85703a-565d-469a-96ce-30b6de53079d",
|
||||
"physical_network": "physnet1",
|
||||
"portgroup_uuid": "e43c722c-248e-4c6e-8ce8-0d8ff129387a",
|
||||
|
@@ -24,6 +24,7 @@
|
||||
"name": "port1",
|
||||
"description": "Physical Network",
|
||||
"vendor": "splitrock",
|
||||
"category": "hypernet",
|
||||
"node_uuid": "6d85703a-565d-469a-96ce-30b6de53079d",
|
||||
"physical_network": "physnet1",
|
||||
"portgroup_uuid": "e43c722c-248e-4c6e-8ce8-0d8ff129387a",
|
||||
|
@@ -22,6 +22,7 @@
|
||||
"name": "port1",
|
||||
"description": "Physical Network",
|
||||
"vendor": "splitrock",
|
||||
"category": "hypernet",
|
||||
"node_uuid": "6d85703a-565d-469a-96ce-30b6de53079d",
|
||||
"physical_network": "physnet1",
|
||||
"portgroup_uuid": "e43c722c-248e-4c6e-8ce8-0d8ff129387a",
|
||||
|
@@ -2,6 +2,11 @@
|
||||
REST API Version History
|
||||
========================
|
||||
|
||||
1.101 (Flamingo)
|
||||
-----------------------
|
||||
|
||||
Add a 'category' field to the Port object.
|
||||
|
||||
1.100 (Flamingo)
|
||||
-----------------------
|
||||
|
||||
|
@@ -55,6 +55,7 @@ PORT_SCHEMA = {
|
||||
'name': {'type': ['string', 'null']},
|
||||
'description': {'type': ['string', 'null'], 'maxLength': 255},
|
||||
'vendor': {'type': ['string', 'null'], 'maxLength': 32},
|
||||
'category': {'type': ['string', 'null'], 'maxLength': 80},
|
||||
},
|
||||
'required': ['address'],
|
||||
'oneOf': [
|
||||
@@ -80,6 +81,7 @@ PATCH_ALLOWED_FIELDS = [
|
||||
'name',
|
||||
'description',
|
||||
'vendor',
|
||||
'category',
|
||||
]
|
||||
|
||||
PORT_VALIDATOR_EXTRA = args.dict_valid(
|
||||
@@ -144,6 +146,9 @@ def hide_fields_in_newer_versions(port):
|
||||
# if requested version is < 1.100, hide vendor field.
|
||||
if not api_utils.allow_port_vendor():
|
||||
port.pop('vendor', None)
|
||||
# if requested version is < 1.101, hide category field.
|
||||
if not api_utils.allow_port_category():
|
||||
port.pop('category', None)
|
||||
|
||||
|
||||
def convert_with_links(rpc_port, fields=None, sanitize=True):
|
||||
@@ -413,6 +418,9 @@ class PortsController(rest.RestController):
|
||||
if ('vendor' in fields
|
||||
and not api_utils.allow_port_vendor()):
|
||||
raise exception.NotAcceptable()
|
||||
if ('category' in fields
|
||||
and not api_utils.allow_port_category()):
|
||||
raise exception.NotAcceptable()
|
||||
|
||||
@METRICS.timer('PortsController.get_all')
|
||||
@method.expose()
|
||||
|
@@ -2248,6 +2248,14 @@ def allow_port_description():
|
||||
def allow_port_vendor():
|
||||
"""Check if vendor is allowed for ports.
|
||||
|
||||
Version 1.100 of the API added description field to the port object.
|
||||
Version 1.100 of the API added vendor field to the port object.
|
||||
"""
|
||||
return api.request.version.minor >= versions.MINOR_100_PORT_VENDOR
|
||||
|
||||
|
||||
def allow_port_category():
|
||||
"""Check if category is allowed for ports.
|
||||
|
||||
Version 1.101 of the API added category field to the port object.
|
||||
"""
|
||||
return api.request.version.minor >= versions.MINOR_101_PORT_CATEGORY
|
||||
|
@@ -138,6 +138,7 @@ BASE_VERSION = 1
|
||||
# v1.98: Add support for object attributes with keys containing ~ or /.
|
||||
# v1.99: Add conductor group filtering to port and portgroup list
|
||||
# v1.100: Add vendor field to port.
|
||||
# v1.101: Add category field to port.
|
||||
|
||||
MINOR_0_JUNO = 0
|
||||
MINOR_1_INITIAL_VERSION = 1
|
||||
@@ -240,6 +241,7 @@ MINOR_97_PORT_DESCRIPTION = 97
|
||||
MINOR_98_SUPPORT_SPECIAL_CHAR_IN_ATTRIBUTES = 98
|
||||
MINOR_99_PORT_PORTGROUP_CONDUCTOR_GROUP_FILTER = 99
|
||||
MINOR_100_PORT_VENDOR = 100
|
||||
MINOR_101_PORT_CATEGORY = 101
|
||||
|
||||
# When adding another version, update:
|
||||
# - MINOR_MAX_VERSION
|
||||
@@ -248,7 +250,7 @@ MINOR_100_PORT_VENDOR = 100
|
||||
# - common/release_mappings.py, RELEASE_MAPPING['master']['api']
|
||||
|
||||
|
||||
MINOR_MAX_VERSION = MINOR_100_PORT_VENDOR
|
||||
MINOR_MAX_VERSION = MINOR_101_PORT_CATEGORY
|
||||
|
||||
# String representations of the minor and maximum versions
|
||||
_MIN_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_1_INITIAL_VERSION)
|
||||
|
@@ -896,7 +896,7 @@ RELEASE_MAPPING = {
|
||||
# make it below. To release, we will preserve a version matching
|
||||
# the release as a separate block of text, like above.
|
||||
'master': {
|
||||
'api': '1.100',
|
||||
'api': '1.101',
|
||||
'rpc': '1.61',
|
||||
'objects': {
|
||||
'Allocation': ['1.3', '1.2', '1.1'],
|
||||
@@ -908,7 +908,7 @@ RELEASE_MAPPING = {
|
||||
'Chassis': ['1.4', '1.3'],
|
||||
'Deployment': ['1.1', '1.0'],
|
||||
'DeployTemplate': ['1.2', '1.1'],
|
||||
'Port': ['1.14', '1.13', '1.12'],
|
||||
'Port': ['1.15', '1.14', '1.13', '1.12'],
|
||||
'Portgroup': ['1.6', '1.5'],
|
||||
'Trait': ['1.1', '1.0'],
|
||||
'TraitList': ['1.1', '1.0'],
|
||||
|
@@ -0,0 +1,31 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""add category attribute to port object
|
||||
|
||||
Revision ID: 3ef27505c9fb
|
||||
Revises: e4827561979d
|
||||
Create Date: 2025-07-21 01:33:47.215396
|
||||
|
||||
"""
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '3ef27505c9fb'
|
||||
down_revision = 'e4827561979d'
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column('ports', sa.Column('category', sa.String(length=80),
|
||||
nullable=True))
|
@@ -271,6 +271,7 @@ class Port(Base):
|
||||
name = Column(String(255), nullable=True)
|
||||
description = Column(String(255), nullable=True)
|
||||
vendor = Column(String(32), nullable=True)
|
||||
category = Column(String(80), nullable=True)
|
||||
|
||||
_node_uuid = orm.relationship(
|
||||
"Node",
|
||||
|
@@ -48,7 +48,8 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
|
||||
# Version 1.12: Add description field
|
||||
# Version 1.13: Add vendor field
|
||||
# Version 1.14: Mark multiple methods as remotable methods.
|
||||
VERSION = '1.14'
|
||||
# Version 1.15: Add category field
|
||||
VERSION = '1.15'
|
||||
|
||||
dbapi = dbapi.get_instance()
|
||||
|
||||
@@ -70,6 +71,7 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
|
||||
'name': object_fields.StringField(nullable=True),
|
||||
'description': object_fields.StringField(nullable=True),
|
||||
'vendor': object_fields.StringField(nullable=True),
|
||||
'category': object_fields.StringField(nullable=True),
|
||||
}
|
||||
|
||||
def _convert_field_by_version(self, field_name, introduced_version,
|
||||
@@ -129,6 +131,9 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
|
||||
Version 1.13: remove vendor for unsupported versions if
|
||||
remove_unavailable_fields is True.
|
||||
|
||||
Version 1.15: remove category for unsupported versions if
|
||||
remove_unavailable_fields is True.
|
||||
|
||||
:param target_version: the desired version of the object
|
||||
:param remove_unavailable_fields: True to remove fields that are
|
||||
unavailable in the target version; set this to True when
|
||||
@@ -163,6 +168,9 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
|
||||
# Convert the vendor field.
|
||||
self._convert_field_by_version('vendor', (1, 13), target_version,
|
||||
remove_unavailable_fields)
|
||||
# Convert the category field.
|
||||
self._convert_field_by_version('category', (1, 15), target_version,
|
||||
remove_unavailable_fields)
|
||||
|
||||
@object_base.remotable_classmethod
|
||||
def get(cls, context, port_id):
|
||||
@@ -495,7 +503,8 @@ class PortCRUDPayload(notification.NotificationPayloadBase):
|
||||
# Version 1.4: Add "name" field
|
||||
# Version 1.5: Add "description" field
|
||||
# Version 1.6: Add "vendor" field
|
||||
VERSION = '1.6'
|
||||
# Version 1.7: Add "category" field
|
||||
VERSION = '1.7'
|
||||
|
||||
SCHEMA = {
|
||||
'address': ('port', 'address'),
|
||||
@@ -510,6 +519,7 @@ class PortCRUDPayload(notification.NotificationPayloadBase):
|
||||
'name': ('port', 'name'),
|
||||
'description': ('port', 'description'),
|
||||
'vendor': ('port', 'vendor'),
|
||||
'category': ('port', 'category'),
|
||||
}
|
||||
|
||||
fields = {
|
||||
@@ -529,6 +539,7 @@ class PortCRUDPayload(notification.NotificationPayloadBase):
|
||||
'name': object_fields.StringField(nullable=True),
|
||||
'description': object_fields.StringField(nullable=True),
|
||||
'vendor': object_fields.StringField(nullable=True),
|
||||
'category': object_fields.StringField(nullable=True),
|
||||
}
|
||||
|
||||
def __init__(self, port, node_uuid, portgroup_uuid):
|
||||
|
@@ -2001,6 +2001,7 @@ class TestPost(test_api_base.BaseApiTest):
|
||||
pdict.pop('name')
|
||||
pdict.pop('description')
|
||||
pdict.pop('vendor')
|
||||
pdict.pop('category')
|
||||
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)
|
||||
|
@@ -368,3 +368,29 @@ class DbPortTestCase(base.DbTestCase):
|
||||
|
||||
retrieved_port1 = self.dbapi.get_port_by_uuid(port1.uuid)
|
||||
self.assertEqual(new_vendor, retrieved_port1.vendor)
|
||||
|
||||
def test_create_port_with_category(self):
|
||||
category = 'hypernet'
|
||||
port1 = db_utils.create_test_port(
|
||||
uuid=uuidutils.generate_uuid(),
|
||||
node_id=self.node.id,
|
||||
address='52:54:00:cf:2d:42',
|
||||
category=category)
|
||||
|
||||
port2 = db_utils.create_test_port(
|
||||
uuid=uuidutils.generate_uuid(),
|
||||
node_id=self.node.id,
|
||||
address='52:54:00:cf:2d:45',
|
||||
category=category)
|
||||
|
||||
self.assertEqual(category, port1.category)
|
||||
self.assertEqual(category, port2.category)
|
||||
|
||||
new_category = 'ultranet'
|
||||
updated_port = self.dbapi.update_port(
|
||||
port1.id, {'category': new_category})
|
||||
|
||||
self.assertEqual(new_category, updated_port.category)
|
||||
|
||||
retrieved_port1 = self.dbapi.get_port_by_uuid(port1.uuid)
|
||||
self.assertEqual(new_category, retrieved_port1.category)
|
||||
|
@@ -290,6 +290,7 @@ def get_test_port(**kw):
|
||||
'name': kw.get('name'),
|
||||
'description': kw.get('description'),
|
||||
'vendor': kw.get('vendor'),
|
||||
'category': kw.get('category'),
|
||||
}
|
||||
|
||||
|
||||
|
@@ -678,7 +678,7 @@ expected_object_fingerprints = {
|
||||
'Node': '1.42-a1d3e6011e3cdb27aafa9353b7c0b6d4',
|
||||
'MyObj': '1.5-9459d30d6954bffc7a9afd347a807ca6',
|
||||
'Chassis': '1.4-fe427272d8bad232a8d46e996a5ca42a',
|
||||
'Port': '1.14-684faad7173c1d9e8a2d630381c51903',
|
||||
'Port': '1.15-013610c0fe2e370b14f4304e0d8aeb3a',
|
||||
'Portgroup': '1.6-ada5300518c2262766121a4333d92df3',
|
||||
'Conductor': '1.6-ed00540fae97aa1c9982f9017c6e8b68',
|
||||
'EventType': '1.1-aa2ba1afd38553e3880c267404e8d370',
|
||||
@@ -699,7 +699,7 @@ expected_object_fingerprints = {
|
||||
'NodeCRUDNotification': '1.0-59acc533c11d306f149846f922739c15',
|
||||
'NodeCRUDPayload': '1.15-9168946f843edd5859464aaa40ad70e0',
|
||||
'PortCRUDNotification': '1.0-59acc533c11d306f149846f922739c15',
|
||||
'PortCRUDPayload': '1.6-72323673fb8b869200d91bcd6886acae',
|
||||
'PortCRUDPayload': '1.7-aaefef8ba3a94030753c1e3b9a29741b',
|
||||
'NodeMaintenanceNotification': '1.0-59acc533c11d306f149846f922739c15',
|
||||
'NodeConsoleNotification': '1.0-59acc533c11d306f149846f922739c15',
|
||||
'PortgroupCRUDNotification': '1.0-59acc533c11d306f149846f922739c15',
|
||||
|
6
releasenotes/notes/port-category-9935c6006d243bc3.yaml
Normal file
6
releasenotes/notes/port-category-9935c6006d243bc3.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
A new "category" field has been added to the Port object. This field is meant
|
||||
to help distinguish between different types of Ports. Relevant to trait
|
||||
based port scheduling feature.
|
Reference in New Issue
Block a user