summaryrefslogtreecommitdiff
path: root/ironic/api/controllers
diff options
context:
space:
mode:
authorHamdy Khader <hamdyk@mellanox.com>2019-01-13 15:40:30 +0200
committerHamdy Khader <hamdyk@mellanox.com>2019-02-10 12:10:00 +0200
commit6325b6c13c82911cb144646a614b943bdf496518 (patch)
tree6aed938e0e69556403e0f1738ad3ff8b0d622678 /ironic/api/controllers
parent506cb121609b73a9174bf2676c32c8ac7421a441 (diff)
downloadironic-6325b6c13c82911cb144646a614b943bdf496518.tar.gz
Expose is_smartnic in port API
Changes are made to support ironic handling is_smarting port attribute that was added in this change Ic2ffbd6f1035907ea5a18bda6d2b21e617194195 This change expose is_smartnic port field in REST API, updated API reference to include is_smartnic field and relevent documentations. API version updated to 1.53. Story: #2003346 Change-Id: I89ce54a0c034f2a5f82ff961ab06cfcc6d853bd4
Diffstat (limited to 'ironic/api/controllers')
-rw-r--r--ironic/api/controllers/v1/port.py21
-rw-r--r--ironic/api/controllers/v1/types.py58
-rw-r--r--ironic/api/controllers/v1/utils.py10
-rw-r--r--ironic/api/controllers/v1/versions.py4
4 files changed, 82 insertions, 11 deletions
diff --git a/ironic/api/controllers/v1/port.py b/ironic/api/controllers/v1/port.py
index b72f0ddbf..c16ff7231 100644
--- a/ironic/api/controllers/v1/port.py
+++ b/ironic/api/controllers/v1/port.py
@@ -59,6 +59,9 @@ def hide_fields_in_newer_versions(obj):
# if requested version is < 1.34, hide physical_network field.
if not api_utils.allow_port_physical_network():
obj.physical_network = wsme.Unset
+ # if requested version is < 1.53, hide is_smartnic field.
+ if not api_utils.allow_port_is_smartnic():
+ obj.is_smartnic = wsme.Unset
class Port(base.APIBase):
@@ -156,6 +159,9 @@ class Port(base.APIBase):
links = wsme.wsattr([link.Link], readonly=True)
"""A list containing a self link and associated port links"""
+ is_smartnic = types.boolean
+ """Indicates whether this port is a Smart NIC port."""
+
def __init__(self, **kwargs):
self.fields = []
fields = list(objects.Port.fields)
@@ -245,7 +251,8 @@ class Port(base.APIBase):
local_link_connection={
'switch_info': 'host', 'port_id': 'Gig0/1',
'switch_id': 'aa:bb:cc:dd:ee:ff'},
- physical_network='physnet1')
+ physical_network='physnet1',
+ is_smartnic=False)
# NOTE(lucasagomes): node_uuid getter() method look at the
# _node_uuid variable
sample._node_uuid = '7ae81bb3-dec3-4289-8d6c-da80bd8001ae'
@@ -425,6 +432,9 @@ class PortsController(rest.RestController):
if ('physical_network' in fields
and not api_utils.allow_port_physical_network()):
raise exception.NotAcceptable()
+ if ('is_smartnic' in fields
+ and not api_utils.allow_port_is_smartnic()):
+ raise exception.NotAcceptable()
@METRICS.timer('PortsController.get_all')
@expose.expose(PortCollection, types.uuid_or_name, types.uuid,
@@ -577,6 +587,12 @@ class PortsController(rest.RestController):
pdict = port.as_dict()
self._check_allowed_port_fields(pdict)
+ if (port.is_smartnic and not types.locallinkconnectiontype
+ .validate_for_smart_nic(port.local_link_connection)):
+ raise exception.Invalid(
+ "Smart NIC port must have port_id "
+ "and hostname in local_link_connection")
+
create_remotely = pecan.request.rpcapi.can_send_create_port()
if (not create_remotely and pdict.get('portgroup_uuid')):
# NOTE(mgoddard): In RPC API v1.41, port creation was moved to the
@@ -652,7 +668,8 @@ class PortsController(rest.RestController):
fields_to_check = set()
for field in (self.advanced_net_fields
- + ['portgroup_uuid', 'physical_network']):
+ + ['portgroup_uuid', 'physical_network',
+ 'is_smartnic']):
field_path = '/%s' % field
if (api_utils.get_patch_values(patch, field_path)
or api_utils.is_path_removed(patch, field_path)):
diff --git a/ironic/api/controllers/v1/types.py b/ironic/api/controllers/v1/types.py
index 87f574954..e2b04bd72 100644
--- a/ironic/api/controllers/v1/types.py
+++ b/ironic/api/controllers/v1/types.py
@@ -18,6 +18,7 @@
import inspect
import json
+from oslo_log import log
from oslo_utils import strutils
from oslo_utils import uuidutils
import six
@@ -30,6 +31,9 @@ from ironic.common.i18n import _
from ironic.common import utils
+LOG = log.getLogger(__name__)
+
+
class MacAddressType(wtypes.UserType):
"""A simple MAC address type."""
@@ -266,9 +270,12 @@ class LocalLinkConnectionType(wtypes.UserType):
basetype = wtypes.DictType
name = 'locallinkconnection'
- mandatory_fields = {'switch_id',
- 'port_id'}
- valid_fields = mandatory_fields.union({'switch_info'})
+ local_link_mandatory_fields = {'port_id', 'switch_id'}
+ smart_nic_mandatory_fields = {'port_id', 'hostname'}
+ mandatory_fields_list = [local_link_mandatory_fields,
+ smart_nic_mandatory_fields]
+ optional_field = {'switch_info'}
+ valid_fields = set.union(optional_field, *mandatory_fields_list)
@staticmethod
def validate(value):
@@ -276,7 +283,7 @@ class LocalLinkConnectionType(wtypes.UserType):
:param value: A dictionary of values to validate, switch_id is a MAC
address or an OpenFlow based datapath_id, switch_info is an
- optional field.
+ optional field. Required Smart NIC fields are port_id and hostname.
For example::
@@ -286,6 +293,13 @@ class LocalLinkConnectionType(wtypes.UserType):
'switch_info': 'switch1'
}
+ Or for Smart NIC::
+
+ {
+ 'port_id': 'rep0-0',
+ 'hostname': 'host1-bf'
+ }
+
:returns: A dictionary.
:raises: Invalid if some of the keys in the dictionary being validated
are unknown, invalid, or some required ones are missing.
@@ -304,10 +318,20 @@ class LocalLinkConnectionType(wtypes.UserType):
if invalid:
raise exception.Invalid(_('%s are invalid keys') % (invalid))
- # Check all mandatory fields are present
- missing = LocalLinkConnectionType.mandatory_fields - keys
- if missing:
- msg = _('Missing mandatory keys: %s') % missing
+ # Check any mandatory fields sets are present
+ for mandatory_set in LocalLinkConnectionType.mandatory_fields_list:
+ if mandatory_set <= keys:
+ break
+ else:
+ msg = _('Missing mandatory keys. Required keys are '
+ '%(required_fields)s. Or in case of Smart NIC '
+ '%(smart_nic_required_fields)s. '
+ 'Submitted keys are %(keys)s .') % {
+ 'required_fields':
+ LocalLinkConnectionType.local_link_mandatory_fields,
+ 'smart_nic_required_fields':
+ LocalLinkConnectionType.smart_nic_mandatory_fields,
+ 'keys': keys}
raise exception.Invalid(msg)
# Check switch_id is either a valid mac address or
@@ -321,6 +345,9 @@ class LocalLinkConnectionType(wtypes.UserType):
value['switch_id'])
except exception.InvalidDatapathID:
raise exception.InvalidSwitchID(switch_id=value['switch_id'])
+ except KeyError:
+ # In Smart NIC case 'switch_id' is optional.
+ pass
return value
@@ -330,6 +357,21 @@ class LocalLinkConnectionType(wtypes.UserType):
return None
return LocalLinkConnectionType.validate(value)
+ @staticmethod
+ def validate_for_smart_nic(value):
+ """Validates Smart NIC field are present 'port_id' and 'hostname'
+
+ :param value: local link information of type Dictionary.
+ :return: True if both fields 'port_id' and 'hostname' are present
+ in 'value', False otherwise.
+ """
+ wtypes.DictType(wtypes.text, wtypes.text).validate(value)
+ keys = set(value)
+
+ if LocalLinkConnectionType.smart_nic_mandatory_fields <= keys:
+ return True
+ return False
+
locallinkconnectiontype = LocalLinkConnectionType()
diff --git a/ironic/api/controllers/v1/utils.py b/ironic/api/controllers/v1/utils.py
index 770dec62d..f2c7a5ec9 100644
--- a/ironic/api/controllers/v1/utils.py
+++ b/ironic/api/controllers/v1/utils.py
@@ -1012,3 +1012,13 @@ def allow_allocations():
field for the node.
"""
return pecan.request.version.minor >= versions.MINOR_52_ALLOCATION
+
+
+def allow_port_is_smartnic():
+ """Check if port is_smartnic field is allowed.
+
+ Version 1.53 of the API added is_smartnic field to the port object.
+ """
+ return ((pecan.request.version.minor
+ >= versions.MINOR_53_PORT_SMARTNIC)
+ and objects.Port.supports_is_smartnic())
diff --git a/ironic/api/controllers/v1/versions.py b/ironic/api/controllers/v1/versions.py
index d456738de..5c5da878e 100644
--- a/ironic/api/controllers/v1/versions.py
+++ b/ironic/api/controllers/v1/versions.py
@@ -90,6 +90,7 @@ BASE_VERSION = 1
# v1.50: Add owner to the node object.
# v1.51: Add description to the node object.
# v1.52: Add allocation API.
+# v1.53: Add support for Smart NIC port
MINOR_0_JUNO = 0
MINOR_1_INITIAL_VERSION = 1
@@ -144,6 +145,7 @@ MINOR_49_CONDUCTORS = 49
MINOR_50_NODE_OWNER = 50
MINOR_51_NODE_DESCRIPTION = 51
MINOR_52_ALLOCATION = 52
+MINOR_53_PORT_SMARTNIC = 53
# When adding another version, update:
# - MINOR_MAX_VERSION
@@ -151,7 +153,7 @@ MINOR_52_ALLOCATION = 52
# explanation of what changed in the new version
# - common/release_mappings.py, RELEASE_MAPPING['master']['api']
-MINOR_MAX_VERSION = MINOR_52_ALLOCATION
+MINOR_MAX_VERSION = MINOR_53_PORT_SMARTNIC
# String representations of the minor and maximum versions
_MIN_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_1_INITIAL_VERSION)