A new 'description' field to the port object
Adds a description field that allows users to add description to ports. Closes-Bug: #2099906 Change-Id: I1290c04698d50c7f01d74ef73296bf24f1b85152
This commit is contained in:
parent
b6f8fa969c
commit
5b372dd9ed
@ -2,6 +2,7 @@
|
|||||||
"node_ident": "6d85703a-565d-469a-96ce-30b6de53079d",
|
"node_ident": "6d85703a-565d-469a-96ce-30b6de53079d",
|
||||||
"portgroup_uuid": "e43c722c-248e-4c6e-8ce8-0d8ff129387a",
|
"portgroup_uuid": "e43c722c-248e-4c6e-8ce8-0d8ff129387a",
|
||||||
"name": "port1",
|
"name": "port1",
|
||||||
|
"description": "Physical Network",
|
||||||
"address": "11:11:11:11:11:11",
|
"address": "11:11:11:11:11:11",
|
||||||
"is_smartnic": true,
|
"is_smartnic": true,
|
||||||
"local_link_connection": {
|
"local_link_connection": {
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
"switch_info": "switch1"
|
"switch_info": "switch1"
|
||||||
},
|
},
|
||||||
"name": "port1",
|
"name": "port1",
|
||||||
|
"description": "Physical Network",
|
||||||
"node_uuid": "6d85703a-565d-469a-96ce-30b6de53079d",
|
"node_uuid": "6d85703a-565d-469a-96ce-30b6de53079d",
|
||||||
"physical_network": "physnet1",
|
"physical_network": "physnet1",
|
||||||
"portgroup_uuid": "e43c722c-248e-4c6e-8ce8-0d8ff129387a",
|
"portgroup_uuid": "e43c722c-248e-4c6e-8ce8-0d8ff129387a",
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
"switch_info": "switch1"
|
"switch_info": "switch1"
|
||||||
},
|
},
|
||||||
"name": "port1",
|
"name": "port1",
|
||||||
|
"description": "Physical Network",
|
||||||
"node_uuid": "6d85703a-565d-469a-96ce-30b6de53079d",
|
"node_uuid": "6d85703a-565d-469a-96ce-30b6de53079d",
|
||||||
"physical_network": "physnet1",
|
"physical_network": "physnet1",
|
||||||
"portgroup_uuid": "e43c722c-248e-4c6e-8ce8-0d8ff129387a",
|
"portgroup_uuid": "e43c722c-248e-4c6e-8ce8-0d8ff129387a",
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
"switch_info": "switch1"
|
"switch_info": "switch1"
|
||||||
},
|
},
|
||||||
"name": "port1",
|
"name": "port1",
|
||||||
|
"description": "Physical Network",
|
||||||
"node_uuid": "6d85703a-565d-469a-96ce-30b6de53079d",
|
"node_uuid": "6d85703a-565d-469a-96ce-30b6de53079d",
|
||||||
"physical_network": "physnet1",
|
"physical_network": "physnet1",
|
||||||
"portgroup_uuid": "e43c722c-248e-4c6e-8ce8-0d8ff129387a",
|
"portgroup_uuid": "e43c722c-248e-4c6e-8ce8-0d8ff129387a",
|
||||||
|
@ -2,6 +2,11 @@
|
|||||||
REST API Version History
|
REST API Version History
|
||||||
========================
|
========================
|
||||||
|
|
||||||
|
1.97 (Flamingo)
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Add a 'description' field to the Port object.
|
||||||
|
|
||||||
1.95 (Epoxy)
|
1.95 (Epoxy)
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
|
@ -53,6 +53,7 @@ PORT_SCHEMA = {
|
|||||||
'pxe_enabled': {'type': ['string', 'boolean', 'null']},
|
'pxe_enabled': {'type': ['string', 'boolean', 'null']},
|
||||||
'uuid': {'type': ['string', 'null']},
|
'uuid': {'type': ['string', 'null']},
|
||||||
'name': {'type': ['string', 'null']},
|
'name': {'type': ['string', 'null']},
|
||||||
|
'description': {'type': ['string', 'null'], 'maxLength': 255},
|
||||||
},
|
},
|
||||||
'required': ['address'],
|
'required': ['address'],
|
||||||
'oneOf': [
|
'oneOf': [
|
||||||
@ -76,6 +77,7 @@ PATCH_ALLOWED_FIELDS = [
|
|||||||
'portgroup_uuid',
|
'portgroup_uuid',
|
||||||
'pxe_enabled',
|
'pxe_enabled',
|
||||||
'name',
|
'name',
|
||||||
|
'description',
|
||||||
]
|
]
|
||||||
|
|
||||||
PORT_VALIDATOR_EXTRA = args.dict_valid(
|
PORT_VALIDATOR_EXTRA = args.dict_valid(
|
||||||
@ -134,6 +136,9 @@ def hide_fields_in_newer_versions(port):
|
|||||||
# expect the key port.local_link_connection to exist even if we
|
# expect the key port.local_link_connection to exist even if we
|
||||||
# cannot set a valid value
|
# cannot set a valid value
|
||||||
port['local_link_connection'] = {}
|
port['local_link_connection'] = {}
|
||||||
|
# if requested version is < 1.97, hide description field.
|
||||||
|
if not api_utils.allow_port_description():
|
||||||
|
port.pop('description', None)
|
||||||
|
|
||||||
|
|
||||||
def convert_with_links(rpc_port, fields=None, sanitize=True):
|
def convert_with_links(rpc_port, fields=None, sanitize=True):
|
||||||
@ -150,6 +155,7 @@ def convert_with_links(rpc_port, fields=None, sanitize=True):
|
|||||||
'pxe_enabled',
|
'pxe_enabled',
|
||||||
'node_uuid',
|
'node_uuid',
|
||||||
'name',
|
'name',
|
||||||
|
'description',
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if rpc_port.portgroup_id:
|
if rpc_port.portgroup_id:
|
||||||
@ -227,7 +233,7 @@ class PortsController(rest.RestController):
|
|||||||
def _get_ports_collection(self, node_ident, address, portgroup_ident,
|
def _get_ports_collection(self, node_ident, address, portgroup_ident,
|
||||||
shard, marker, limit, sort_key, sort_dir,
|
shard, marker, limit, sort_key, sort_dir,
|
||||||
resource_url=None, fields=None, detail=None,
|
resource_url=None, fields=None, detail=None,
|
||||||
project=None):
|
project=None, description_contains=None):
|
||||||
"""Retrieve a collection of ports.
|
"""Retrieve a collection of ports.
|
||||||
|
|
||||||
:param node_ident: UUID or name of a node, to get only ports for that
|
:param node_ident: UUID or name of a node, to get only ports for that
|
||||||
@ -250,6 +256,9 @@ class PortsController(rest.RestController):
|
|||||||
of the resource to be returned.
|
of the resource to be returned.
|
||||||
:param detail: Optional, show detailed list of ports
|
:param detail: Optional, show detailed list of ports
|
||||||
:param project: Optional, filter by project
|
:param project: Optional, filter by project
|
||||||
|
:param description_contains: Optional string value to get only ports
|
||||||
|
with description field contains matching
|
||||||
|
value.
|
||||||
:returns: a list of ports.
|
:returns: a list of ports.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -277,6 +286,10 @@ class PortsController(rest.RestController):
|
|||||||
if exclusive_filters > 1:
|
if exclusive_filters > 1:
|
||||||
raise exception.OperationNotPermitted()
|
raise exception.OperationNotPermitted()
|
||||||
|
|
||||||
|
filters = {}
|
||||||
|
if description_contains:
|
||||||
|
filters['description_contains'] = description_contains
|
||||||
|
|
||||||
if portgroup_ident:
|
if portgroup_ident:
|
||||||
# FIXME: Since all we need is the portgroup ID, we can
|
# FIXME: Since all we need is the portgroup ID, we can
|
||||||
# make this more efficient by only querying
|
# make this more efficient by only querying
|
||||||
@ -288,7 +301,8 @@ class PortsController(rest.RestController):
|
|||||||
marker_obj,
|
marker_obj,
|
||||||
sort_key=sort_key,
|
sort_key=sort_key,
|
||||||
sort_dir=sort_dir,
|
sort_dir=sort_dir,
|
||||||
project=project)
|
project=project,
|
||||||
|
filters=filters)
|
||||||
elif node_ident:
|
elif node_ident:
|
||||||
# FIXME(comstud): Since all we need is the node ID, we can
|
# FIXME(comstud): Since all we need is the node ID, we can
|
||||||
# make this more efficient by only querying
|
# make this more efficient by only querying
|
||||||
@ -299,18 +313,21 @@ class PortsController(rest.RestController):
|
|||||||
node.id, limit, marker_obj,
|
node.id, limit, marker_obj,
|
||||||
sort_key=sort_key,
|
sort_key=sort_key,
|
||||||
sort_dir=sort_dir,
|
sort_dir=sort_dir,
|
||||||
project=project)
|
project=project,
|
||||||
|
filters=filters)
|
||||||
elif address:
|
elif address:
|
||||||
ports = self._get_ports_by_address(address, project=project)
|
ports = self._get_ports_by_address(address, project=project)
|
||||||
elif shard:
|
elif shard:
|
||||||
ports = objects.Port.list_by_node_shards(api.request.context,
|
ports = objects.Port.list_by_node_shards(api.request.context,
|
||||||
shard, limit,
|
shard, limit,
|
||||||
marker_obj, sort_key,
|
marker_obj, sort_key,
|
||||||
sort_dir, project=project)
|
sort_dir, project=project,
|
||||||
|
filters=filters)
|
||||||
else:
|
else:
|
||||||
ports = objects.Port.list(api.request.context, limit,
|
ports = objects.Port.list(api.request.context, limit,
|
||||||
marker_obj, sort_key=sort_key,
|
marker_obj, sort_key=sort_key,
|
||||||
sort_dir=sort_dir, project=project)
|
sort_dir=sort_dir, project=project,
|
||||||
|
filters=filters)
|
||||||
parameters = {}
|
parameters = {}
|
||||||
|
|
||||||
if detail is not None:
|
if detail is not None:
|
||||||
@ -377,6 +394,9 @@ class PortsController(rest.RestController):
|
|||||||
if ('name' in fields
|
if ('name' in fields
|
||||||
and not api_utils.allow_port_name()):
|
and not api_utils.allow_port_name()):
|
||||||
raise exception.NotAcceptable()
|
raise exception.NotAcceptable()
|
||||||
|
if ('description' in fields
|
||||||
|
and not api_utils.allow_port_description()):
|
||||||
|
raise exception.NotAcceptable()
|
||||||
|
|
||||||
@METRICS.timer('PortsController.get_all')
|
@METRICS.timer('PortsController.get_all')
|
||||||
@method.expose()
|
@method.expose()
|
||||||
@ -385,10 +405,11 @@ class PortsController(rest.RestController):
|
|||||||
limit=args.integer, sort_key=args.string,
|
limit=args.integer, sort_key=args.string,
|
||||||
sort_dir=args.string, fields=args.string_list,
|
sort_dir=args.string, fields=args.string_list,
|
||||||
portgroup=args.uuid_or_name, detail=args.boolean,
|
portgroup=args.uuid_or_name, detail=args.boolean,
|
||||||
shard=args.string_list)
|
shard=args.string_list, description_contains=args.string)
|
||||||
def get_all(self, node=None, node_uuid=None, address=None, marker=None,
|
def get_all(self, node=None, node_uuid=None, address=None, marker=None,
|
||||||
limit=None, sort_key='id', sort_dir='asc', fields=None,
|
limit=None, sort_key='id', sort_dir='asc', fields=None,
|
||||||
portgroup=None, detail=None, shard=None):
|
portgroup=None, detail=None, shard=None,
|
||||||
|
description_contains=None):
|
||||||
"""Retrieve a list of ports.
|
"""Retrieve a list of ports.
|
||||||
|
|
||||||
Note that the 'node_uuid' interface is deprecated in favour
|
Note that the 'node_uuid' interface is deprecated in favour
|
||||||
@ -413,6 +434,9 @@ class PortsController(rest.RestController):
|
|||||||
for that portgroup.
|
for that portgroup.
|
||||||
:param shard: Optional, a list of shard ids to filter by, only ports
|
:param shard: Optional, a list of shard ids to filter by, only ports
|
||||||
associated with nodes in these shards will be returned.
|
associated with nodes in these shards will be returned.
|
||||||
|
:param description_contains: Optional string value to get only ports
|
||||||
|
with description field contains matching
|
||||||
|
value.
|
||||||
:raises: NotAcceptable, HTTPNotFound
|
:raises: NotAcceptable, HTTPNotFound
|
||||||
"""
|
"""
|
||||||
project = api_utils.check_port_list_policy(
|
project = api_utils.check_port_list_policy(
|
||||||
@ -437,6 +461,8 @@ class PortsController(rest.RestController):
|
|||||||
fields = api_utils.get_request_return_fields(fields, detail,
|
fields = api_utils.get_request_return_fields(fields, detail,
|
||||||
_DEFAULT_RETURN_FIELDS)
|
_DEFAULT_RETURN_FIELDS)
|
||||||
|
|
||||||
|
extra_args = {'description_contains': description_contains}
|
||||||
|
|
||||||
if not node_uuid and node:
|
if not node_uuid and node:
|
||||||
# We're invoking this interface using positional notation, or
|
# We're invoking this interface using positional notation, or
|
||||||
# explicitly using 'node'. Try and determine which one.
|
# explicitly using 'node'. Try and determine which one.
|
||||||
@ -450,7 +476,7 @@ class PortsController(rest.RestController):
|
|||||||
sort_key, sort_dir,
|
sort_key, sort_dir,
|
||||||
resource_url='ports',
|
resource_url='ports',
|
||||||
fields=fields, detail=detail,
|
fields=fields, detail=detail,
|
||||||
project=project)
|
project=project, **extra_args)
|
||||||
|
|
||||||
@METRICS.timer('PortsController.detail')
|
@METRICS.timer('PortsController.detail')
|
||||||
@method.expose()
|
@method.expose()
|
||||||
@ -458,10 +484,10 @@ class PortsController(rest.RestController):
|
|||||||
address=args.mac_address, marker=args.uuid,
|
address=args.mac_address, marker=args.uuid,
|
||||||
limit=args.integer, sort_key=args.string,
|
limit=args.integer, sort_key=args.string,
|
||||||
sort_dir=args.string, portgroup=args.uuid_or_name,
|
sort_dir=args.string, portgroup=args.uuid_or_name,
|
||||||
shard=args.string_list)
|
shard=args.string_list, description_contains=args.string)
|
||||||
def detail(self, node=None, node_uuid=None, address=None, marker=None,
|
def detail(self, node=None, node_uuid=None, address=None, marker=None,
|
||||||
limit=None, sort_key='id', sort_dir='asc', portgroup=None,
|
limit=None, sort_key='id', sort_dir='asc', portgroup=None,
|
||||||
shard=None):
|
shard=None, description_contains=None):
|
||||||
"""Retrieve a list of ports with detail.
|
"""Retrieve a list of ports with detail.
|
||||||
|
|
||||||
Note that the 'node_uuid' interface is deprecated in favour
|
Note that the 'node_uuid' interface is deprecated in favour
|
||||||
@ -484,6 +510,9 @@ class PortsController(rest.RestController):
|
|||||||
max_limit resources will be returned.
|
max_limit resources will be returned.
|
||||||
:param sort_key: column to sort results by. Default: id.
|
:param sort_key: column to sort results by. Default: id.
|
||||||
:param sort_dir: direction to sort. "asc" or "desc". Default: asc.
|
:param sort_dir: direction to sort. "asc" or "desc". Default: asc.
|
||||||
|
:param description_contains: Optional string value to get only ports
|
||||||
|
with description field contains matching
|
||||||
|
value.
|
||||||
:raises: NotAcceptable, HTTPNotFound
|
:raises: NotAcceptable, HTTPNotFound
|
||||||
"""
|
"""
|
||||||
project = api_utils.check_port_list_policy(
|
project = api_utils.check_port_list_policy(
|
||||||
@ -509,11 +538,12 @@ class PortsController(rest.RestController):
|
|||||||
if parent != "ports":
|
if parent != "ports":
|
||||||
raise exception.HTTPNotFound()
|
raise exception.HTTPNotFound()
|
||||||
|
|
||||||
|
extra_args = {'description_contains': description_contains}
|
||||||
return self._get_ports_collection(node_uuid or node, address,
|
return self._get_ports_collection(node_uuid or node, address,
|
||||||
portgroup, shard, marker, limit,
|
portgroup, shard, marker, limit,
|
||||||
sort_key, sort_dir,
|
sort_key, sort_dir,
|
||||||
resource_url='ports/detail',
|
resource_url='ports/detail',
|
||||||
project=project)
|
project=project, **extra_args)
|
||||||
|
|
||||||
@METRICS.timer('PortsController.get_one')
|
@METRICS.timer('PortsController.get_one')
|
||||||
@method.expose()
|
@method.expose()
|
||||||
|
@ -2228,3 +2228,11 @@ def allow_get_vmedia():
|
|||||||
def allow_node_ident_as_param_for_port_creation():
|
def allow_node_ident_as_param_for_port_creation():
|
||||||
"""Check if 'node_ident' parameter is allowed for port creation."""
|
"""Check if 'node_ident' parameter is allowed for port creation."""
|
||||||
return api.request.version.minor >= versions.MINOR_94_PORT_NODENAME
|
return api.request.version.minor >= versions.MINOR_94_PORT_NODENAME
|
||||||
|
|
||||||
|
|
||||||
|
def allow_port_description():
|
||||||
|
"""Check if description is allowed for ports.
|
||||||
|
|
||||||
|
Version 1.97 of the API added description field to the port object.
|
||||||
|
"""
|
||||||
|
return api.request.version.minor >= versions.MINOR_97_PORT_DESCRIPTION
|
||||||
|
@ -134,6 +134,7 @@ BASE_VERSION = 1
|
|||||||
# v1.94: Add node name support for port creation
|
# v1.94: Add node name support for port creation
|
||||||
# v1.95: Add node support for disable_power_off
|
# v1.95: Add node support for disable_power_off
|
||||||
# v1.96: Migrate inspection rules from Inspector
|
# v1.96: Migrate inspection rules from Inspector
|
||||||
|
# v1.97: Add description field to port.
|
||||||
|
|
||||||
MINOR_0_JUNO = 0
|
MINOR_0_JUNO = 0
|
||||||
MINOR_1_INITIAL_VERSION = 1
|
MINOR_1_INITIAL_VERSION = 1
|
||||||
@ -232,6 +233,7 @@ MINOR_93_GET_VMEDIA = 93
|
|||||||
MINOR_94_PORT_NODENAME = 94
|
MINOR_94_PORT_NODENAME = 94
|
||||||
MINOR_95_DISABLE_POWER_OFF = 95
|
MINOR_95_DISABLE_POWER_OFF = 95
|
||||||
MINOR_96_INSPECTION_RULES = 96
|
MINOR_96_INSPECTION_RULES = 96
|
||||||
|
MINOR_97_PORT_DESCRIPTION = 97
|
||||||
|
|
||||||
# When adding another version, update:
|
# When adding another version, update:
|
||||||
# - MINOR_MAX_VERSION
|
# - MINOR_MAX_VERSION
|
||||||
@ -239,7 +241,7 @@ MINOR_96_INSPECTION_RULES = 96
|
|||||||
# explanation of what changed in the new version
|
# explanation of what changed in the new version
|
||||||
# - common/release_mappings.py, RELEASE_MAPPING['master']['api']
|
# - common/release_mappings.py, RELEASE_MAPPING['master']['api']
|
||||||
|
|
||||||
MINOR_MAX_VERSION = MINOR_96_INSPECTION_RULES
|
MINOR_MAX_VERSION = MINOR_97_PORT_DESCRIPTION
|
||||||
|
|
||||||
# String representations of the minor and maximum versions
|
# String representations of the minor and maximum versions
|
||||||
_MIN_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_1_INITIAL_VERSION)
|
_MIN_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_1_INITIAL_VERSION)
|
||||||
|
@ -848,7 +848,7 @@ RELEASE_MAPPING = {
|
|||||||
# make it below. To release, we will preserve a version matching
|
# make it below. To release, we will preserve a version matching
|
||||||
# the release as a separate block of text, like above.
|
# the release as a separate block of text, like above.
|
||||||
'master': {
|
'master': {
|
||||||
'api': '1.96',
|
'api': '1.97',
|
||||||
'rpc': '1.61',
|
'rpc': '1.61',
|
||||||
'objects': {
|
'objects': {
|
||||||
'Allocation': ['1.1'],
|
'Allocation': ['1.1'],
|
||||||
@ -860,7 +860,7 @@ RELEASE_MAPPING = {
|
|||||||
'Chassis': ['1.3'],
|
'Chassis': ['1.3'],
|
||||||
'Deployment': ['1.0'],
|
'Deployment': ['1.0'],
|
||||||
'DeployTemplate': ['1.1'],
|
'DeployTemplate': ['1.1'],
|
||||||
'Port': ['1.11'],
|
'Port': ['1.12'],
|
||||||
'Portgroup': ['1.5'],
|
'Portgroup': ['1.5'],
|
||||||
'Trait': ['1.0'],
|
'Trait': ['1.0'],
|
||||||
'TraitList': ['1.0'],
|
'TraitList': ['1.0'],
|
||||||
|
@ -285,7 +285,7 @@ class Connection(object, metaclass=abc.ABCMeta):
|
|||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def get_port_list(self, limit=None, marker=None,
|
def get_port_list(self, limit=None, marker=None,
|
||||||
sort_key=None, sort_dir=None):
|
sort_key=None, sort_dir=None, filters=None):
|
||||||
"""Return a list of ports.
|
"""Return a list of ports.
|
||||||
|
|
||||||
:param limit: Maximum number of ports to return.
|
:param limit: Maximum number of ports to return.
|
||||||
@ -294,11 +294,12 @@ class Connection(object, metaclass=abc.ABCMeta):
|
|||||||
:param sort_key: Attribute by which results should be sorted.
|
:param sort_key: Attribute by which results should be sorted.
|
||||||
:param sort_dir: direction in which results should be sorted.
|
:param sort_dir: direction in which results should be sorted.
|
||||||
(asc, desc)
|
(asc, desc)
|
||||||
|
:param filters: Filters to apply, defaults to None
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def get_ports_by_shards(self, shards, limit=None, marker=None,
|
def get_ports_by_shards(self, shards, limit=None, marker=None,
|
||||||
sort_key=None, sort_dir=None):
|
sort_key=None, sort_dir=None, filters=None):
|
||||||
"""Return a list of ports contained in the provided shards.
|
"""Return a list of ports contained in the provided shards.
|
||||||
|
|
||||||
:param shard_ids: A list of shards to filter ports by.
|
:param shard_ids: A list of shards to filter ports by.
|
||||||
@ -306,7 +307,7 @@ class Connection(object, metaclass=abc.ABCMeta):
|
|||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def get_ports_by_node_id(self, node_id, limit=None, marker=None,
|
def get_ports_by_node_id(self, node_id, limit=None, marker=None,
|
||||||
sort_key=None, sort_dir=None):
|
sort_key=None, sort_dir=None, filters=None):
|
||||||
"""List all the ports for a given node.
|
"""List all the ports for a given node.
|
||||||
|
|
||||||
:param node_id: The integer node ID.
|
:param node_id: The integer node ID.
|
||||||
@ -316,12 +317,13 @@ class Connection(object, metaclass=abc.ABCMeta):
|
|||||||
:param sort_key: Attribute by which results should be sorted
|
:param sort_key: Attribute by which results should be sorted
|
||||||
:param sort_dir: direction in which results should be sorted
|
:param sort_dir: direction in which results should be sorted
|
||||||
(asc, desc)
|
(asc, desc)
|
||||||
|
:param filters: Filters to apply, defaults to None
|
||||||
:returns: A list of ports.
|
:returns: A list of ports.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def get_ports_by_portgroup_id(self, portgroup_id, limit=None, marker=None,
|
def get_ports_by_portgroup_id(self, portgroup_id, limit=None, marker=None,
|
||||||
sort_key=None, sort_dir=None):
|
sort_key=None, sort_dir=None, filters=None):
|
||||||
"""List all the ports for a given portgroup.
|
"""List all the ports for a given portgroup.
|
||||||
|
|
||||||
:param portgroup_id: The integer portgroup ID.
|
:param portgroup_id: The integer portgroup ID.
|
||||||
@ -331,6 +333,7 @@ class Connection(object, metaclass=abc.ABCMeta):
|
|||||||
:param sort_key: Attribute by which results should be sorted
|
:param sort_key: Attribute by which results should be sorted
|
||||||
:param sort_dir: Direction in which results should be sorted
|
:param sort_dir: Direction in which results should be sorted
|
||||||
(asc, desc)
|
(asc, desc)
|
||||||
|
:param filters: Filters to apply, defaults to None
|
||||||
:returns: A list of ports.
|
:returns: A list of ports.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
"""port description
|
||||||
|
|
||||||
|
Revision ID: 1c14278d6e33
|
||||||
|
Revises: 21c48150dea9
|
||||||
|
Create Date: 2025-03-17 17:12:27.160796
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '1c14278d6e33'
|
||||||
|
down_revision = '21c48150dea9'
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.add_column('ports', sa.Column('description', sa.String(length=255),
|
||||||
|
nullable=True))
|
@ -250,6 +250,16 @@ def add_port_filter(query, value):
|
|||||||
return add_identity_filter(query, value)
|
return add_identity_filter(query, value)
|
||||||
|
|
||||||
|
|
||||||
|
def add_port_filter_description_contains(query, filters):
|
||||||
|
filters = filters or {}
|
||||||
|
if 'description_contains' in filters:
|
||||||
|
keyword = filters['description_contains']
|
||||||
|
if keyword is not None:
|
||||||
|
query = query.filter(
|
||||||
|
models.Port.description.like(r'%{}%'.format(keyword)))
|
||||||
|
return query
|
||||||
|
|
||||||
|
|
||||||
def add_port_filter_by_node(query, value):
|
def add_port_filter_by_node(query, value):
|
||||||
if strutils.is_int_like(value):
|
if strutils.is_int_like(value):
|
||||||
return query.filter_by(node_id=value)
|
return query.filter_by(node_id=value)
|
||||||
@ -1070,45 +1080,49 @@ class Connection(api.Connection):
|
|||||||
|
|
||||||
def get_port_list(self, limit=None, marker=None,
|
def get_port_list(self, limit=None, marker=None,
|
||||||
sort_key=None, sort_dir=None, owner=None,
|
sort_key=None, sort_dir=None, owner=None,
|
||||||
project=None):
|
project=None, filters=None):
|
||||||
query = sa.select(models.Port)
|
query = sa.select(models.Port)
|
||||||
if owner:
|
if owner:
|
||||||
query = add_port_filter_by_node_owner(query, owner)
|
query = add_port_filter_by_node_owner(query, owner)
|
||||||
elif project:
|
elif project:
|
||||||
query = add_port_filter_by_node_project(query, project)
|
query = add_port_filter_by_node_project(query, project)
|
||||||
|
query = add_port_filter_description_contains(query, filters)
|
||||||
return _paginate_query(models.Port, limit, marker,
|
return _paginate_query(models.Port, limit, marker,
|
||||||
sort_key, sort_dir, query)
|
sort_key, sort_dir, query)
|
||||||
|
|
||||||
def get_ports_by_shards(self, shards, limit=None, marker=None,
|
def get_ports_by_shards(self, shards, limit=None, marker=None,
|
||||||
sort_key=None, sort_dir=None):
|
sort_key=None, sort_dir=None, filters=None):
|
||||||
shard_node_ids = sa.select(models.Node) \
|
shard_node_ids = sa.select(models.Node) \
|
||||||
.where(models.Node.shard.in_(shards)) \
|
.where(models.Node.shard.in_(shards)) \
|
||||||
.with_only_columns(models.Node.id)
|
.with_only_columns(models.Node.id)
|
||||||
query = sa.select(models.Port) \
|
query = sa.select(models.Port) \
|
||||||
.where(models.Port.node_id.in_(shard_node_ids))
|
.where(models.Port.node_id.in_(shard_node_ids))
|
||||||
|
query = add_port_filter_description_contains(query, filters)
|
||||||
return _paginate_query(
|
return _paginate_query(
|
||||||
models.Port, limit, marker, sort_key, sort_dir, query)
|
models.Port, limit, marker, sort_key, sort_dir, query)
|
||||||
|
|
||||||
def get_ports_by_node_id(self, node_id, limit=None, marker=None,
|
def get_ports_by_node_id(self, node_id, limit=None, marker=None,
|
||||||
sort_key=None, sort_dir=None, owner=None,
|
sort_key=None, sort_dir=None, owner=None,
|
||||||
project=None):
|
project=None, filters=None):
|
||||||
query = sa.select(models.Port).where(models.Port.node_id == node_id)
|
query = sa.select(models.Port).where(models.Port.node_id == node_id)
|
||||||
if owner:
|
if owner:
|
||||||
query = add_port_filter_by_node_owner(query, owner)
|
query = add_port_filter_by_node_owner(query, owner)
|
||||||
elif project:
|
elif project:
|
||||||
query = add_port_filter_by_node_project(query, project)
|
query = add_port_filter_by_node_project(query, project)
|
||||||
|
query = add_port_filter_description_contains(query, filters)
|
||||||
return _paginate_query(models.Port, limit, marker,
|
return _paginate_query(models.Port, limit, marker,
|
||||||
sort_key, sort_dir, query)
|
sort_key, sort_dir, query)
|
||||||
|
|
||||||
def get_ports_by_portgroup_id(self, portgroup_id, limit=None, marker=None,
|
def get_ports_by_portgroup_id(self, portgroup_id, limit=None, marker=None,
|
||||||
sort_key=None, sort_dir=None, owner=None,
|
sort_key=None, sort_dir=None, owner=None,
|
||||||
project=None):
|
project=None, filters=None):
|
||||||
query = sa.select(models.Port).where(
|
query = sa.select(models.Port).where(
|
||||||
models.Port.portgroup_id == portgroup_id)
|
models.Port.portgroup_id == portgroup_id)
|
||||||
if owner:
|
if owner:
|
||||||
query = add_port_filter_by_node_owner(query, owner)
|
query = add_port_filter_by_node_owner(query, owner)
|
||||||
elif project:
|
elif project:
|
||||||
query = add_port_filter_by_node_project(query, project)
|
query = add_port_filter_by_node_project(query, project)
|
||||||
|
query = add_port_filter_description_contains(query, filters)
|
||||||
return _paginate_query(models.Port, limit, marker,
|
return _paginate_query(models.Port, limit, marker,
|
||||||
sort_key, sort_dir, query)
|
sort_key, sort_dir, query)
|
||||||
|
|
||||||
|
@ -269,6 +269,7 @@ class Port(Base):
|
|||||||
physical_network = Column(String(64), nullable=True)
|
physical_network = Column(String(64), nullable=True)
|
||||||
is_smartnic = Column(Boolean, nullable=True, default=False)
|
is_smartnic = Column(Boolean, nullable=True, default=False)
|
||||||
name = Column(String(255), nullable=True)
|
name = Column(String(255), nullable=True)
|
||||||
|
description = Column(String(255), nullable=True)
|
||||||
|
|
||||||
_node_uuid = orm.relationship(
|
_node_uuid = orm.relationship(
|
||||||
"Node",
|
"Node",
|
||||||
|
@ -45,7 +45,8 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
|
|||||||
# Version 1.9: Add support for Smart NIC port
|
# Version 1.9: Add support for Smart NIC port
|
||||||
# Version 1.10: Add name field
|
# Version 1.10: Add name field
|
||||||
# Version 1.11: Add node_uuid field
|
# Version 1.11: Add node_uuid field
|
||||||
VERSION = '1.11'
|
# Version 1.12: Add description field
|
||||||
|
VERSION = '1.12'
|
||||||
|
|
||||||
dbapi = dbapi.get_instance()
|
dbapi = dbapi.get_instance()
|
||||||
|
|
||||||
@ -65,24 +66,36 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
|
|||||||
'is_smartnic': object_fields.BooleanField(nullable=True,
|
'is_smartnic': object_fields.BooleanField(nullable=True,
|
||||||
default=False),
|
default=False),
|
||||||
'name': object_fields.StringField(nullable=True),
|
'name': object_fields.StringField(nullable=True),
|
||||||
|
'description': object_fields.StringField(nullable=True),
|
||||||
}
|
}
|
||||||
|
|
||||||
def _convert_name_field(self, target_version,
|
def _convert_field_by_version(self, field_name, introduced_version,
|
||||||
remove_unavailable_fields=True):
|
target_version,
|
||||||
name_is_set = self.obj_attr_is_set('name')
|
remove_unavailable_fields=True,
|
||||||
if target_version >= (1, 10):
|
default_value=None):
|
||||||
# Target version supports name. Set it to its default
|
"""Convert a field based on version compatibility.
|
||||||
|
|
||||||
|
:param field_name: Name of the field to convert
|
||||||
|
:param introduced_version: Version tuple when the field was introduced
|
||||||
|
:param target_version: Target version to convert to
|
||||||
|
:param remove_unavailable_fields: Whether to remove fields not in
|
||||||
|
target version
|
||||||
|
:param default_value: Default value to set if field is not set
|
||||||
|
"""
|
||||||
|
field_is_set = self.obj_attr_is_set(field_name)
|
||||||
|
if target_version >= introduced_version:
|
||||||
|
# Target version supports this field. Set it to its default
|
||||||
# value if it is not set.
|
# value if it is not set.
|
||||||
if not name_is_set:
|
if not field_is_set:
|
||||||
self.name = None
|
setattr(self, field_name, default_value)
|
||||||
elif name_is_set:
|
elif field_is_set:
|
||||||
# Target version does not support name, and it is set.
|
# Target version does not support this field, and it is set.
|
||||||
if remove_unavailable_fields:
|
if remove_unavailable_fields:
|
||||||
# (De)serialising: remove unavailable fields.
|
# (De)serialising: remove unavailable fields.
|
||||||
delattr(self, 'name')
|
delattr(self, field_name)
|
||||||
elif self.name is not None:
|
elif getattr(self, field_name) is not default_value:
|
||||||
# DB: set unavailable fields to their default.
|
# DB: set unavailable fields to their default.
|
||||||
self.name = None
|
setattr(self, field_name, default_value)
|
||||||
|
|
||||||
def _convert_to_version(self, target_version,
|
def _convert_to_version(self, target_version,
|
||||||
remove_unavailable_fields=True):
|
remove_unavailable_fields=True):
|
||||||
@ -126,41 +139,18 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
|
|||||||
self.internal_info = internal_info
|
self.internal_info = internal_info
|
||||||
|
|
||||||
# Convert the physical_network field.
|
# Convert the physical_network field.
|
||||||
physnet_is_set = self.obj_attr_is_set('physical_network')
|
self._convert_field_by_version('physical_network', (1, 7),
|
||||||
if target_version >= (1, 7):
|
target_version,
|
||||||
# Target version supports physical_network. Set it to its default
|
remove_unavailable_fields)
|
||||||
# value if it is not set.
|
|
||||||
if not physnet_is_set:
|
|
||||||
self.physical_network = None
|
|
||||||
elif physnet_is_set:
|
|
||||||
# Target version does not support physical_network, and it is set.
|
|
||||||
if remove_unavailable_fields:
|
|
||||||
# (De)serialising: remove unavailable fields.
|
|
||||||
delattr(self, 'physical_network')
|
|
||||||
elif self.physical_network is not None:
|
|
||||||
# DB: set unavailable fields to their default.
|
|
||||||
self.physical_network = None
|
|
||||||
|
|
||||||
# Convert is_smartnic field.
|
# Convert is_smartnic field.
|
||||||
is_smartnic_set = self.obj_attr_is_set('is_smartnic')
|
self._convert_field_by_version('is_smartnic', (1, 9), target_version,
|
||||||
if target_version >= (1, 9):
|
remove_unavailable_fields, False)
|
||||||
# Target version supports is_smartnic. Set it to its default
|
|
||||||
# value if it is not set.
|
|
||||||
if not is_smartnic_set:
|
|
||||||
self.is_smartnic = False
|
|
||||||
|
|
||||||
# handle is_smartnic field in older version
|
|
||||||
elif is_smartnic_set:
|
|
||||||
# Target version does not support is_smartnic, and it is set.
|
|
||||||
if remove_unavailable_fields:
|
|
||||||
# (De)serialising: remove unavailable fields.
|
|
||||||
delattr(self, 'is_smartnic')
|
|
||||||
elif self.is_smartnic is not False:
|
|
||||||
# DB: set unavailable fields to their default.
|
|
||||||
self.is_smartnic = False
|
|
||||||
|
|
||||||
# Convert the name field.
|
# Convert the name field.
|
||||||
self._convert_name_field(target_version, remove_unavailable_fields)
|
self._convert_field_by_version('name', (1, 10), target_version,
|
||||||
|
remove_unavailable_fields)
|
||||||
|
# Convert the description field.
|
||||||
|
self._convert_field_by_version('description', (1, 12), target_version,
|
||||||
|
remove_unavailable_fields)
|
||||||
|
|
||||||
# NOTE(xek): We don't want to enable RPC on this call just yet. Remotable
|
# NOTE(xek): We don't want to enable RPC on this call just yet. Remotable
|
||||||
# methods can be used in the future to replace current explicit RPC calls.
|
# methods can be used in the future to replace current explicit RPC calls.
|
||||||
@ -275,8 +265,8 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
|
|||||||
# Implications of calling new remote procedures should be thought through.
|
# Implications of calling new remote procedures should be thought through.
|
||||||
# @object_base.remotable_classmethod
|
# @object_base.remotable_classmethod
|
||||||
@classmethod
|
@classmethod
|
||||||
def list(cls, context, limit=None, marker=None,
|
def list(cls, context, limit=None, marker=None, sort_key=None,
|
||||||
sort_key=None, sort_dir=None, owner=None, project=None):
|
sort_dir=None, owner=None, project=None, filters=None):
|
||||||
"""Return a list of Port objects.
|
"""Return a list of Port objects.
|
||||||
|
|
||||||
:param context: Security context.
|
:param context: Security context.
|
||||||
@ -286,6 +276,7 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
|
|||||||
:param sort_dir: direction to sort. "asc" or "desc".
|
:param sort_dir: direction to sort. "asc" or "desc".
|
||||||
:param owner: DEPRECATED a node owner to match against
|
:param owner: DEPRECATED a node owner to match against
|
||||||
:param project: a node owner or lessee to match against
|
:param project: a node owner or lessee to match against
|
||||||
|
:param filters: Filters to apply, defaults to None
|
||||||
:returns: a list of :class:`Port` object.
|
:returns: a list of :class:`Port` object.
|
||||||
:raises: InvalidParameterValue
|
:raises: InvalidParameterValue
|
||||||
|
|
||||||
@ -296,12 +287,14 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
|
|||||||
marker=marker,
|
marker=marker,
|
||||||
sort_key=sort_key,
|
sort_key=sort_key,
|
||||||
sort_dir=sort_dir,
|
sort_dir=sort_dir,
|
||||||
project=project)
|
project=project,
|
||||||
|
filters=filters)
|
||||||
return cls._from_db_object_list(context, db_ports)
|
return cls._from_db_object_list(context, db_ports)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def list_by_node_shards(cls, context, shards, limit=None, marker=None,
|
def list_by_node_shards(cls, context, shards, limit=None, marker=None,
|
||||||
sort_key=None, sort_dir=None, project=None):
|
sort_key=None, sort_dir=None, project=None,
|
||||||
|
filters=None):
|
||||||
"""Return a list of Port objects associated with nodes in shards
|
"""Return a list of Port objects associated with nodes in shards
|
||||||
|
|
||||||
:param context: Security context.
|
:param context: Security context.
|
||||||
@ -311,13 +304,15 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
|
|||||||
:param sort_key: column to sort results by.
|
:param sort_key: column to sort results by.
|
||||||
:param sort_dir: direction to sort. "asc" or "desc".
|
:param sort_dir: direction to sort. "asc" or "desc".
|
||||||
:param project: a node owner or lessee to match against
|
:param project: a node owner or lessee to match against
|
||||||
|
:param filters: Filters to apply, defaults to None
|
||||||
:returns: a list of :class:`Port` object.
|
:returns: a list of :class:`Port` object.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
db_ports = cls.dbapi.get_ports_by_shards(shards, limit=limit,
|
db_ports = cls.dbapi.get_ports_by_shards(shards, limit=limit,
|
||||||
marker=marker,
|
marker=marker,
|
||||||
sort_key=sort_key,
|
sort_key=sort_key,
|
||||||
sort_dir=sort_dir)
|
sort_dir=sort_dir,
|
||||||
|
filters=filters)
|
||||||
return cls._from_db_object_list(context, db_ports)
|
return cls._from_db_object_list(context, db_ports)
|
||||||
|
|
||||||
# NOTE(xek): We don't want to enable RPC on this call just yet. Remotable
|
# NOTE(xek): We don't want to enable RPC on this call just yet. Remotable
|
||||||
@ -327,7 +322,7 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def list_by_node_id(cls, context, node_id, limit=None, marker=None,
|
def list_by_node_id(cls, context, node_id, limit=None, marker=None,
|
||||||
sort_key=None, sort_dir=None, owner=None,
|
sort_key=None, sort_dir=None, owner=None,
|
||||||
project=None):
|
project=None, filters=None):
|
||||||
"""Return a list of Port objects associated with a given node ID.
|
"""Return a list of Port objects associated with a given node ID.
|
||||||
|
|
||||||
:param context: Security context.
|
:param context: Security context.
|
||||||
@ -338,6 +333,7 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
|
|||||||
:param sort_dir: direction to sort. "asc" or "desc".
|
:param sort_dir: direction to sort. "asc" or "desc".
|
||||||
:param owner: DEPRECATED a node owner to match against
|
:param owner: DEPRECATED a node owner to match against
|
||||||
:param project: a node owner or lessee to match against
|
:param project: a node owner or lessee to match against
|
||||||
|
:param filters: Filters to apply, defaults to None
|
||||||
:returns: a list of :class:`Port` object.
|
:returns: a list of :class:`Port` object.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -347,7 +343,8 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
|
|||||||
marker=marker,
|
marker=marker,
|
||||||
sort_key=sort_key,
|
sort_key=sort_key,
|
||||||
sort_dir=sort_dir,
|
sort_dir=sort_dir,
|
||||||
project=project)
|
project=project,
|
||||||
|
filters=filters)
|
||||||
return cls._from_db_object_list(context, db_ports)
|
return cls._from_db_object_list(context, db_ports)
|
||||||
|
|
||||||
# NOTE(xek): We don't want to enable RPC on this call just yet. Remotable
|
# NOTE(xek): We don't want to enable RPC on this call just yet. Remotable
|
||||||
@ -357,7 +354,7 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def list_by_portgroup_id(cls, context, portgroup_id, limit=None,
|
def list_by_portgroup_id(cls, context, portgroup_id, limit=None,
|
||||||
marker=None, sort_key=None, sort_dir=None,
|
marker=None, sort_key=None, sort_dir=None,
|
||||||
owner=None, project=None):
|
owner=None, project=None, filters=None):
|
||||||
"""Return a list of Port objects associated with a given portgroup ID.
|
"""Return a list of Port objects associated with a given portgroup ID.
|
||||||
|
|
||||||
:param context: Security context.
|
:param context: Security context.
|
||||||
@ -368,6 +365,7 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
|
|||||||
:param sort_dir: direction to sort. "asc" or "desc".
|
:param sort_dir: direction to sort. "asc" or "desc".
|
||||||
:param owner: DEPRECATED a node owner to match against
|
:param owner: DEPRECATED a node owner to match against
|
||||||
:param project: a node owner or lessee to match against
|
:param project: a node owner or lessee to match against
|
||||||
|
:param filters: Filters to apply, defaults to None
|
||||||
:returns: a list of :class:`Port` object.
|
:returns: a list of :class:`Port` object.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -378,7 +376,8 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
|
|||||||
marker=marker,
|
marker=marker,
|
||||||
sort_key=sort_key,
|
sort_key=sort_key,
|
||||||
sort_dir=sort_dir,
|
sort_dir=sort_dir,
|
||||||
project=project)
|
project=project,
|
||||||
|
filters=filters)
|
||||||
return cls._from_db_object_list(context, db_ports)
|
return cls._from_db_object_list(context, db_ports)
|
||||||
|
|
||||||
# NOTE(xek): We don't want to enable RPC on this call just yet. Remotable
|
# NOTE(xek): We don't want to enable RPC on this call just yet. Remotable
|
||||||
@ -522,7 +521,8 @@ class PortCRUDPayload(notification.NotificationPayloadBase):
|
|||||||
# Version 1.2: Add "physical_network" field
|
# Version 1.2: Add "physical_network" field
|
||||||
# Version 1.3: Add "is_smartnic" field
|
# Version 1.3: Add "is_smartnic" field
|
||||||
# Version 1.4: Add "name" field
|
# Version 1.4: Add "name" field
|
||||||
VERSION = '1.4'
|
# Version 1.5: Add "description" field
|
||||||
|
VERSION = '1.5'
|
||||||
|
|
||||||
SCHEMA = {
|
SCHEMA = {
|
||||||
'address': ('port', 'address'),
|
'address': ('port', 'address'),
|
||||||
@ -535,6 +535,7 @@ class PortCRUDPayload(notification.NotificationPayloadBase):
|
|||||||
'uuid': ('port', 'uuid'),
|
'uuid': ('port', 'uuid'),
|
||||||
'is_smartnic': ('port', 'is_smartnic'),
|
'is_smartnic': ('port', 'is_smartnic'),
|
||||||
'name': ('port', 'name'),
|
'name': ('port', 'name'),
|
||||||
|
'description': ('port', 'description'),
|
||||||
}
|
}
|
||||||
|
|
||||||
fields = {
|
fields = {
|
||||||
@ -552,6 +553,7 @@ class PortCRUDPayload(notification.NotificationPayloadBase):
|
|||||||
'is_smartnic': object_fields.BooleanField(nullable=True,
|
'is_smartnic': object_fields.BooleanField(nullable=True,
|
||||||
default=False),
|
default=False),
|
||||||
'name': object_fields.StringField(nullable=True),
|
'name': object_fields.StringField(nullable=True),
|
||||||
|
'description': object_fields.StringField(nullable=True),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, port, node_uuid, portgroup_uuid):
|
def __init__(self, port, node_uuid, portgroup_uuid):
|
||||||
|
@ -197,7 +197,7 @@ class TestPortsController__GetPortsCollection(base.TestCase):
|
|||||||
resource_url='ports')
|
resource_url='ports')
|
||||||
mock_list.assert_called_once_with('fake-context', 1000, None,
|
mock_list.assert_called_once_with('fake-context', 1000, None,
|
||||||
project=None, sort_dir='asc',
|
project=None, sort_dir='asc',
|
||||||
sort_key=None)
|
sort_key=None, filters={})
|
||||||
|
|
||||||
|
|
||||||
@mock.patch.object(objects.Port, 'get_by_address', autospec=True)
|
@mock.patch.object(objects.Port, 'get_by_address', autospec=True)
|
||||||
@ -298,12 +298,13 @@ class TestListPorts(test_api_base.BaseApiTest):
|
|||||||
|
|
||||||
def test_get_one_custom_fields(self):
|
def test_get_one_custom_fields(self):
|
||||||
port = obj_utils.create_test_port(self.context, node_id=self.node.id)
|
port = obj_utils.create_test_port(self.context, node_id=self.node.id)
|
||||||
fields = 'address,extra'
|
fields = 'address,extra,description'
|
||||||
data = self.get_json(
|
data = self.get_json(
|
||||||
'/ports/%s?fields=%s' % (port.uuid, fields),
|
'/ports/%s?fields=%s' % (port.uuid, fields),
|
||||||
headers={api_base.Version.string: str(api_v1.max_version())})
|
headers={api_base.Version.string: str(api_v1.max_version())})
|
||||||
# We always append "links"
|
# We always append "links"
|
||||||
self.assertCountEqual(['address', 'extra', 'links'], data)
|
self.assertCountEqual(['address', 'extra', 'description', 'links'],
|
||||||
|
data)
|
||||||
|
|
||||||
def test_hide_fields_in_newer_versions_internal_info(self):
|
def test_hide_fields_in_newer_versions_internal_info(self):
|
||||||
port = obj_utils.create_test_port(self.context, node_id=self.node.id,
|
port = obj_utils.create_test_port(self.context, node_id=self.node.id,
|
||||||
@ -1108,6 +1109,31 @@ class TestListPorts(test_api_base.BaseApiTest):
|
|||||||
self.assertIn('Expected UUID or name for portgroup',
|
self.assertIn('Expected UUID or name for portgroup',
|
||||||
response.json['error_message'])
|
response.json['error_message'])
|
||||||
|
|
||||||
|
def test_get_ports_by_description(self):
|
||||||
|
port1 = obj_utils.create_test_port(self.context,
|
||||||
|
address='52:54:00:cf:2d:31',
|
||||||
|
node_id=self.node.id,
|
||||||
|
uuid=uuidutils.generate_uuid(),
|
||||||
|
description='some cats here')
|
||||||
|
port2 = obj_utils.create_test_port(self.context,
|
||||||
|
node_id=self.node.id,
|
||||||
|
address='52:54:00:cf:2d:32',
|
||||||
|
uuid=uuidutils.generate_uuid(),
|
||||||
|
description='some dogs there')
|
||||||
|
data = self.get_json(
|
||||||
|
'/ports?description_contains=cat',
|
||||||
|
headers={api_base.Version.string: str(api_v1.max_version())})
|
||||||
|
uuids = [n['uuid'] for n in data['ports']]
|
||||||
|
self.assertIn(port1.uuid, uuids)
|
||||||
|
self.assertNotIn(port2.uuid, uuids)
|
||||||
|
|
||||||
|
data = self.get_json(
|
||||||
|
'/ports?description_contains=dog',
|
||||||
|
headers={api_base.Version.string: str(api_v1.max_version())})
|
||||||
|
uuids = [n['uuid'] for n in data['ports']]
|
||||||
|
self.assertIn(port2.uuid, uuids)
|
||||||
|
self.assertNotIn(port1.uuid, uuids)
|
||||||
|
|
||||||
|
|
||||||
class TestListPortsByShard(test_api_base.BaseApiTest):
|
class TestListPortsByShard(test_api_base.BaseApiTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -1920,6 +1946,7 @@ class TestPost(test_api_base.BaseApiTest):
|
|||||||
pdict.pop('is_smartnic')
|
pdict.pop('is_smartnic')
|
||||||
pdict.pop('portgroup_uuid')
|
pdict.pop('portgroup_uuid')
|
||||||
pdict.pop('name')
|
pdict.pop('name')
|
||||||
|
pdict.pop('description')
|
||||||
headers = {api_base.Version.string: str(api_v1.min_version())}
|
headers = {api_base.Version.string: str(api_v1.min_version())}
|
||||||
response = self.post_json('/ports', pdict, headers=headers)
|
response = self.post_json('/ports', pdict, headers=headers)
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
|
@ -283,3 +283,29 @@ class DbPortTestCase(base.DbTestCase):
|
|||||||
uuid=self.port.uuid,
|
uuid=self.port.uuid,
|
||||||
node_id=self.node.id,
|
node_id=self.node.id,
|
||||||
address='aa-bb-cc-33-11-22')
|
address='aa-bb-cc-33-11-22')
|
||||||
|
|
||||||
|
def test_create_port_with_description(self):
|
||||||
|
description = 'Management Port'
|
||||||
|
port1 = db_utils.create_test_port(
|
||||||
|
uuid=uuidutils.generate_uuid(),
|
||||||
|
node_id=self.node.id,
|
||||||
|
address='52:54:00:cf:2d:42',
|
||||||
|
description=description)
|
||||||
|
|
||||||
|
port2 = db_utils.create_test_port(
|
||||||
|
uuid=uuidutils.generate_uuid(),
|
||||||
|
node_id=self.node.id,
|
||||||
|
address='52:54:00:cf:2d:45',
|
||||||
|
description=description)
|
||||||
|
|
||||||
|
self.assertEqual(description, port1.description)
|
||||||
|
self.assertEqual(description, port2.description)
|
||||||
|
|
||||||
|
new_description = 'Updated Description'
|
||||||
|
updated_port = self.dbapi.update_port(
|
||||||
|
port1.id, {'description': new_description})
|
||||||
|
|
||||||
|
self.assertEqual(new_description, updated_port.description)
|
||||||
|
|
||||||
|
retrieved_port1 = self.dbapi.get_port_by_uuid(port1.uuid)
|
||||||
|
self.assertEqual(new_description, retrieved_port1.description)
|
||||||
|
@ -288,6 +288,7 @@ def get_test_port(**kw):
|
|||||||
'physical_network': kw.get('physical_network'),
|
'physical_network': kw.get('physical_network'),
|
||||||
'is_smartnic': kw.get('is_smartnic', False),
|
'is_smartnic': kw.get('is_smartnic', False),
|
||||||
'name': kw.get('name'),
|
'name': kw.get('name'),
|
||||||
|
'description': kw.get('description'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -678,7 +678,7 @@ expected_object_fingerprints = {
|
|||||||
'Node': '1.41-baff7b2b06243d97448b720030b2e612',
|
'Node': '1.41-baff7b2b06243d97448b720030b2e612',
|
||||||
'MyObj': '1.5-9459d30d6954bffc7a9afd347a807ca6',
|
'MyObj': '1.5-9459d30d6954bffc7a9afd347a807ca6',
|
||||||
'Chassis': '1.3-d656e039fd8ae9f34efc232ab3980905',
|
'Chassis': '1.3-d656e039fd8ae9f34efc232ab3980905',
|
||||||
'Port': '1.11-97bf15b61224f26c65e90f007d78bfd2',
|
'Port': '1.12-49ecc658f87df43ba1bb65543a5987e0',
|
||||||
'Portgroup': '1.5-df4dc15967f67114d51176a98a901a83',
|
'Portgroup': '1.5-df4dc15967f67114d51176a98a901a83',
|
||||||
'Conductor': '1.4-a9703208fdab5fab8f1cec420be1b4a7',
|
'Conductor': '1.4-a9703208fdab5fab8f1cec420be1b4a7',
|
||||||
'EventType': '1.1-aa2ba1afd38553e3880c267404e8d370',
|
'EventType': '1.1-aa2ba1afd38553e3880c267404e8d370',
|
||||||
@ -699,7 +699,7 @@ expected_object_fingerprints = {
|
|||||||
'NodeCRUDNotification': '1.0-59acc533c11d306f149846f922739c15',
|
'NodeCRUDNotification': '1.0-59acc533c11d306f149846f922739c15',
|
||||||
'NodeCRUDPayload': '1.15-9168946f843edd5859464aaa40ad70e0',
|
'NodeCRUDPayload': '1.15-9168946f843edd5859464aaa40ad70e0',
|
||||||
'PortCRUDNotification': '1.0-59acc533c11d306f149846f922739c15',
|
'PortCRUDNotification': '1.0-59acc533c11d306f149846f922739c15',
|
||||||
'PortCRUDPayload': '1.4-9411a1701077ae9dc0aea27d6bf586fc',
|
'PortCRUDPayload': '1.5-174b559bcc8e472cbe4c0afac2b40e66',
|
||||||
'NodeMaintenanceNotification': '1.0-59acc533c11d306f149846f922739c15',
|
'NodeMaintenanceNotification': '1.0-59acc533c11d306f149846f922739c15',
|
||||||
'NodeConsoleNotification': '1.0-59acc533c11d306f149846f922739c15',
|
'NodeConsoleNotification': '1.0-59acc533c11d306f149846f922739c15',
|
||||||
'PortgroupCRUDNotification': '1.0-59acc533c11d306f149846f922739c15',
|
'PortgroupCRUDNotification': '1.0-59acc533c11d306f149846f922739c15',
|
||||||
|
@ -35,7 +35,8 @@ class TestPortObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestPortObject, self).setUp()
|
super(TestPortObject, self).setUp()
|
||||||
self.fake_port = db_utils.get_test_port(name='port-name')
|
self.fake_port = db_utils.get_test_port(
|
||||||
|
name='port-name', description='port-description')
|
||||||
|
|
||||||
def test_get_by_id(self):
|
def test_get_by_id(self):
|
||||||
port_id = self.fake_port['id']
|
port_id = self.fake_port['id']
|
||||||
@ -166,7 +167,7 @@ class TestPortObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
|
|||||||
self.assertEqual(self.context, ports[0]._context)
|
self.assertEqual(self.context, ports[0]._context)
|
||||||
mock_get_list.assert_called_once_with(
|
mock_get_list.assert_called_once_with(
|
||||||
limit=None, marker=None, project=None, sort_dir=None,
|
limit=None, marker=None, project=None, sort_dir=None,
|
||||||
sort_key=None)
|
sort_key=None, filters=None)
|
||||||
|
|
||||||
def test_list_deprecated_owner(self):
|
def test_list_deprecated_owner(self):
|
||||||
with mock.patch.object(self.dbapi, 'get_port_list',
|
with mock.patch.object(self.dbapi, 'get_port_list',
|
||||||
@ -179,7 +180,7 @@ class TestPortObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
|
|||||||
self.assertEqual(self.context, ports[0]._context)
|
self.assertEqual(self.context, ports[0]._context)
|
||||||
mock_get_list.assert_called_once_with(
|
mock_get_list.assert_called_once_with(
|
||||||
limit=None, marker=None, project='12345', sort_dir=None,
|
limit=None, marker=None, project='12345', sort_dir=None,
|
||||||
sort_key=None)
|
sort_key=None, filters=None)
|
||||||
|
|
||||||
@mock.patch.object(obj_base.IronicObject, 'supports_version',
|
@mock.patch.object(obj_base.IronicObject, 'supports_version',
|
||||||
spec_set=types.FunctionType)
|
spec_set=types.FunctionType)
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
A new "description" field has been added to the Port object. This field
|
||||||
|
allows operators to provide human-readable descriptions to easily identify
|
||||||
|
physical ports on bare metal hosts.
|
Loading…
x
Reference in New Issue
Block a user