[PTP dual NIC config] 2nd review of PTP data model

In the original review of PTP data model:
https://review.opendev.org/c/starlingx/config/+/819391 the relationships
between ihost:PtpInstances and Interface:PtpInterfaces need to be many-
to-many like between PtpParameters:PtpParameterOwners, in order to allow
the same host run different PTP instances (services) as well for
interfaces.

Test Plan:

PASS: Fresh install shows all new tables and relationships while system
is responsive for other usual tasks (smoke test)

Regression:

PASS: All the previous test cases for PTP tables keep running with
success. New test cases are planned to support the new relationships.

Story: 2009248
Task: 44146
Signed-off-by: Douglas Henrique Koerich <douglashenrique.koerich@windriver.com>
Change-Id: Id03881cf354e77862a770fc9b71b6bb0ab14aa19
This commit is contained in:
Douglas Henrique Koerich 2021-12-07 14:57:54 -03:00
parent a291b5a4cc
commit 37aec5c439
22 changed files with 1083 additions and 69 deletions

View File

@ -70,7 +70,9 @@ from cgtsclient.v1 import pci_device
from cgtsclient.v1 import port from cgtsclient.v1 import port
from cgtsclient.v1 import ptp from cgtsclient.v1 import ptp
from cgtsclient.v1 import ptp_instance from cgtsclient.v1 import ptp_instance
from cgtsclient.v1 import ptp_instance_map
from cgtsclient.v1 import ptp_interface from cgtsclient.v1 import ptp_interface
from cgtsclient.v1 import ptp_interface_map
from cgtsclient.v1 import ptp_parameter from cgtsclient.v1 import ptp_parameter
from cgtsclient.v1 import ptp_paramownership from cgtsclient.v1 import ptp_paramownership
from cgtsclient.v1 import registry_image from cgtsclient.v1 import registry_image
@ -123,7 +125,9 @@ class Client(http.HTTPClient):
self.intp = intp.intpManager(self) self.intp = intp.intpManager(self)
self.ptp = ptp.ptpManager(self) self.ptp = ptp.ptpManager(self)
self.ptp_instance = ptp_instance.PtpInstanceManager(self) self.ptp_instance = ptp_instance.PtpInstanceManager(self)
self.ptp_instance_map = ptp_instance_map.PtpInstanceMapManager(self)
self.ptp_interface = ptp_interface.PtpInterfaceManager(self) self.ptp_interface = ptp_interface.PtpInterfaceManager(self)
self.ptp_interface_map = ptp_interface_map.PtpInterfaceMapManager(self)
self.ptp_parameter = ptp_parameter.PtpParameterManager(self) self.ptp_parameter = ptp_parameter.PtpParameterManager(self)
self.ptp_paramownership = \ self.ptp_paramownership = \
ptp_paramownership.PtpParameterOwnershipManager(self) ptp_paramownership.PtpParameterOwnershipManager(self)

View File

@ -0,0 +1,44 @@
########################################################################
#
# Copyright (c) 2021 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
########################################################################
from cgtsclient.common import base
from cgtsclient import exc
CREATION_ATTRIBUTES = ['host_id', 'ptp_instance_id']
class PtpInstanceMap(base.Resource):
def __repr__(self):
return "<PtpInstanceMap %s>" % self._info
class PtpInstanceMapManager(base.Manager):
resource_class = PtpInstanceMap
def _path(self, ptp_instance_map_id=None):
return '/v1/ptp_instance_maps/%s' % ptp_instance_map_id \
if ptp_instance_map_id else '/v1/ptp_instance_maps'
def get(self, ptp_instance_map_id):
try:
return self._list(self._path(ptp_instance_map_id))[0]
except IndexError:
return None
def create(self, **kwargs):
data = {}
for (key, value) in kwargs.items():
if key in CREATION_ATTRIBUTES:
data[key] = value
else:
raise exc.InvalidAttribute('%s' % key)
return self._create(self._path(), data)
def delete(self, ptp_instance_map_id):
return self._delete(self._path(ptp_instance_map_id))

View File

@ -0,0 +1,44 @@
########################################################################
#
# Copyright (c) 2021 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
########################################################################
from cgtsclient.common import base
from cgtsclient import exc
CREATION_ATTRIBUTES = ['interface_id', 'ptp_interface_id']
class PtpInterfaceMap(base.Resource):
def __repr__(self):
return "<PtpInterfaceMap %s>" % self._info
class PtpInterfaceMapManager(base.Manager):
resource_class = PtpInterfaceMap
def _path(self, ptp_interface_map_id=None):
return '/v1/ptp_interface_maps/%s' % ptp_interface_map_id \
if ptp_interface_map_id else '/v1/ptp_interface_maps'
def get(self, ptp_interface_map_id):
try:
return self._list(self._path(ptp_interface_map_id))[0]
except IndexError:
return None
def create(self, **kwargs):
data = {}
for (key, value) in kwargs.items():
if key in CREATION_ATTRIBUTES:
data[key] = value
else:
raise exc.InvalidAttribute('%s' % key)
return self._create(self._path(), data)
def delete(self, ptp_interface_map_id):
return self._delete(self._path(ptp_interface_map_id))

View File

@ -66,7 +66,9 @@ from sysinv.api.controllers.v1 import pci_device
from sysinv.api.controllers.v1 import port from sysinv.api.controllers.v1 import port
from sysinv.api.controllers.v1 import ptp from sysinv.api.controllers.v1 import ptp
from sysinv.api.controllers.v1 import ptp_instance from sysinv.api.controllers.v1 import ptp_instance
from sysinv.api.controllers.v1 import ptp_instance_map
from sysinv.api.controllers.v1 import ptp_interface from sysinv.api.controllers.v1 import ptp_interface
from sysinv.api.controllers.v1 import ptp_interface_map
from sysinv.api.controllers.v1 import ptp_parameter from sysinv.api.controllers.v1 import ptp_parameter
from sysinv.api.controllers.v1 import ptp_paramownership from sysinv.api.controllers.v1 import ptp_paramownership
from sysinv.api.controllers.v1 import pv from sysinv.api.controllers.v1 import pv
@ -153,9 +155,15 @@ class V1(base.APIBase):
ptp_instances = [link.Link] ptp_instances = [link.Link]
"Links to the ptp_instances resource" "Links to the ptp_instances resource"
ptp_instance_maps = [link.Link]
"Links to the ptp_instance_maps resource"
ptp_interfaces = [link.Link] ptp_interfaces = [link.Link]
"Links to the ptp_interfaces resource" "Links to the ptp_interfaces resource"
ptp_interface_maps = [link.Link]
"Links to the ptp_interface_maps resource"
ptp_parameters = [link.Link] ptp_parameters = [link.Link]
"Links to the ptp_parameters resource" "Links to the ptp_parameters resource"
@ -469,6 +477,14 @@ class V1(base.APIBase):
'ptp_instances', '', 'ptp_instances', '',
bookmark=True)] bookmark=True)]
v1.ptp_instance_maps = [link.Link.make_link('self',
pecan.request.host_url,
'ptp_instance_maps', ''),
link.Link.make_link('bookmark',
pecan.request.host_url,
'ptp_instance_maps', '',
bookmark=True)]
v1.ptp_interfaces = [link.Link.make_link('self', pecan.request.host_url, v1.ptp_interfaces = [link.Link.make_link('self', pecan.request.host_url,
'ptp_interfaces', ''), 'ptp_interfaces', ''),
link.Link.make_link('bookmark', link.Link.make_link('bookmark',
@ -477,6 +493,14 @@ class V1(base.APIBase):
bookmark=True) bookmark=True)
] ]
v1.ptp_interface_maps = [link.Link.make_link('self',
pecan.request.host_url,
'ptp_instance_maps', ''),
link.Link.make_link('bookmark',
pecan.request.host_url,
'ptp_instance_maps', '',
bookmark=True)]
v1.ptp_parameters = [link.Link.make_link('self', pecan.request.host_url, v1.ptp_parameters = [link.Link.make_link('self', pecan.request.host_url,
'ptp_parameters', ''), 'ptp_parameters', ''),
link.Link.make_link('bookmark', link.Link.make_link('bookmark',
@ -935,7 +959,9 @@ class Controller(rest.RestController):
intp = ntp.NTPController() intp = ntp.NTPController()
ptp = ptp.PTPController() ptp = ptp.PTPController()
ptp_instances = ptp_instance.PtpInstanceController() ptp_instances = ptp_instance.PtpInstanceController()
ptp_instance_maps = ptp_instance_map.PtpInstanceMapController()
ptp_interfaces = ptp_interface.PtpInterfaceController() ptp_interfaces = ptp_interface.PtpInterfaceController()
ptp_interface_maps = ptp_interface_map.PtpInterfaceMapController()
ptp_parameters = ptp_parameter.PtpParameterController() ptp_parameters = ptp_parameter.PtpParameterController()
ptp_parameter_ownerships = \ ptp_parameter_ownerships = \
ptp_paramownership.PtpParameterOwnershipController() ptp_paramownership.PtpParameterOwnershipController()

View File

@ -0,0 +1,167 @@
#
# Copyright (c) 2021 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import pecan
from pecan import rest
import wsme
from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan
from oslo_log import log
from sysinv._i18n import _
from sysinv.api.controllers.v1 import base
from sysinv.api.controllers.v1 import collection
from sysinv.api.controllers.v1 import types
from sysinv.common import exception
from sysinv.common import utils as cutils
from sysinv import objects
LOG = log.getLogger(__name__)
class PtpInstanceMapPatchType(types.JsonPatchType):
@staticmethod
def mandatory_attrs():
return []
class PtpInstanceMap(base.APIBase):
"""API representation of a PTP instance map to host.
This class enforces type checking and value constraints, and converts
between the internal object model and the API representation of
a PTP instance association to host.
"""
created_at = wtypes.datetime.datetime
"Timestamp of creation of this PTP instance mapping"
id = int
"Unique ID for this PTP instance mapping"
uuid = types.uuid
"Unique UUID for this PTP instance mapping"
host_id = int
"ID of the associated host"
hostname = wtypes.text
"Name of the associated host"
ptp_instance_id = int
"ID of the associated PTP instance"
name = wtypes.text
"Name of the associated PTP instance"
service = wtypes.text
"Service type of the associated PTP instance"
def __init__(self, **kwargs):
self.fields = list(objects.ptp_instance_map.fields.keys())
for k in self.fields:
if not hasattr(self, k):
continue
setattr(self, k, kwargs.get(k))
@classmethod
def convert_with_links(cls, rpc_ptp_instance_map, expand=True):
ptp_instance_map = PtpInstanceMap(**rpc_ptp_instance_map.as_dict())
if not expand:
ptp_instance_map.unset_fields_except(
['uuid', 'host_id', 'hostname', 'ptp_instance_id',
'name', 'service', 'created_at'])
LOG.debug("PtpInstanceMap.convert_with_links: converted %s" %
ptp_instance_map.as_dict())
return ptp_instance_map
class PtpInstanceMapCollection(collection.Collection):
"""API representation of a collection of PTP instance maps."""
ptp_instance_maps = [PtpInstanceMap]
"A list containing PTP instance mapping objects"
def __init__(self, **kwargs):
self._type = 'ptp_instance_maps'
@classmethod
def convert_with_links(cls, rpc_ptp_instance_maps, limit, url=None,
expand=False, **kwargs):
collection = PtpInstanceMapCollection()
collection.ptp_instance_maps = \
[PtpInstanceMap.convert_with_links(p, expand)
for p in rpc_ptp_instance_maps]
collection.next = collection.get_next(limit, url=url, **kwargs)
return collection
LOCK_NAME = 'PtpInstanceMapController'
class PtpInstanceMapController(rest.RestController):
"""REST controller for PTP instance map."""
@wsme_pecan.wsexpose(PtpInstanceMap, types.uuid)
def get_one(self, ptp_instance_map_uuid):
"""Retrieve a single PTP instance."""
LOG.debug("PtpInstanceMapController.get_one: uuid=%s" %
ptp_instance_map_uuid)
try:
ptp_instance_map = objects.ptp_instance_map.get_by_uuid(
pecan.request.context,
ptp_instance_map_uuid)
except exception.InvalidParameterValue:
raise wsme.exc.ClientSideError(
_("No PTP instance mapping found for %s"
% ptp_instance_map_uuid))
return PtpInstanceMap.convert_with_links(ptp_instance_map)
def _check_instance_exists(self, id):
LOG.debug("PtpInstanceMapController._check_instance_exists: "
"id %d" % id)
try:
pecan.request.dbapi.ptp_instance_get(id)
except exception.PtpInstanceNotFound:
raise wsme.exc.ClientSideError(
_("No PTP parameter object found with id %d" % id))
def _check_host_exists(self, id):
LOG.debug("PtpInstanceMapController._check_host_exists: "
"id %d" % id)
try:
pecan.request.dbapi.ihost_get(id)
except exception.ServerNotFound:
raise wsme.exc.ClientSideError(
_("No host found with id %d" % id))
@cutils.synchronized(LOCK_NAME)
@wsme_pecan.wsexpose(PtpInstanceMap, body=PtpInstanceMap)
def post(self, ptp_instance_map):
"""Create a new PTP instance mapping."""
ptp_instance_map_dict = ptp_instance_map.as_dict()
LOG.debug("PtpInstanceMapController.post: %s"
% ptp_instance_map_dict)
self._check_instance_exists(ptp_instance_map_dict['ptp_instance_id'])
self._check_host_exists(ptp_instance_map_dict['host_id'])
result = pecan.request.dbapi.ptp_instance_set_host(
ptp_instance_map_dict)
return PtpInstanceMap.convert_with_links(result)
@cutils.synchronized(LOCK_NAME)
@wsme_pecan.wsexpose(None, types.uuid, status_code=204)
def delete(self, ptp_instance_map_uuid):
"""Delete a PTP instance mapping."""
LOG.debug("PtpInstanceMapController.delete: %s"
% ptp_instance_map_uuid)
ptp_instance_map = objects.ptp_instance_map.get_by_uuid(
pecan.request.context, ptp_instance_map_uuid)
pecan.request.dbapi.ptp_parameter_unset_host(
ptp_instance_map.as_dict())

View File

@ -0,0 +1,174 @@
#
# Copyright (c) 2021 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import pecan
from pecan import rest
import wsme
from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan
from oslo_log import log
from sysinv._i18n import _
from sysinv.api.controllers.v1 import base
from sysinv.api.controllers.v1 import collection
from sysinv.api.controllers.v1 import types
from sysinv.common import exception
from sysinv.common import utils as cutils
from sysinv import objects
LOG = log.getLogger(__name__)
class PtpInterfaceMapPatchType(types.JsonPatchType):
@staticmethod
def mandatory_attrs():
return []
class PtpInterfaceMap(base.APIBase):
"""API representation of a PTP interface map to interface.
This class enforces type checking and value constraints, and converts
between the internal object model and the API representation of
a PTP interface association to interface.
"""
created_at = wtypes.datetime.datetime
"Timestamp of creation of this PTP interface mapping"
id = int
"Unique ID for this PTP interface mapping"
uuid = types.uuid
"Unique UUID for this PTP interface mapping"
interface_id = int
"ID of the associated interface"
ifname = wtypes.text
"Name of the associated interface"
iftype = wtypes.text
"Type of the associated interface"
hostname = wtypes.text
"Name of the host for the associated interface"
ptp_interface_id = int
"ID of the associated PTP interface"
name = wtypes.text
"Name of the PTP instance for the associated PTP interface"
service = wtypes.text
"Service type of the PTP instance for the associated PTP interface"
def __init__(self, **kwargs):
self.fields = list(objects.ptp_interface_map.fields.keys())
for k in self.fields:
if not hasattr(self, k):
continue
setattr(self, k, kwargs.get(k))
@classmethod
def convert_with_links(cls, rpc_ptp_interface_map, expand=True):
ptp_interface_map = PtpInterfaceMap(**rpc_ptp_interface_map.as_dict())
if not expand:
ptp_interface_map.unset_fields_except(
['uuid', 'interface_id', 'ifname', 'iftype', 'hostname',
'ptp_interface_id', 'name', 'service', 'created_at'])
LOG.debug("PtpInterfaceMap.convert_with_links: converted %s" %
ptp_interface_map.as_dict())
return ptp_interface_map
class PtpInterfaceMapCollection(collection.Collection):
"""API representation of a collection of PTP interface maps."""
ptp_interface_maps = [PtpInterfaceMap]
"A list containing PTP interface map objects"
def __init__(self, **kwargs):
self._type = 'ptp_interface_maps'
@classmethod
def convert_with_links(cls, rpc_ptp_interface_maps, limit, url=None,
expand=False, **kwargs):
collection = PtpInterfaceMapCollection()
collection.ptp_interface_maps = \
[PtpInterfaceMap.convert_with_links(p, expand)
for p in rpc_ptp_interface_maps]
collection.next = collection.get_next(limit, url=url, **kwargs)
return collection
LOCK_NAME = 'PtpInterfaceMapController'
class PtpInterfaceMapController(rest.RestController):
"""REST controller for PTP interface map."""
@wsme_pecan.wsexpose(PtpInterfaceMap, types.uuid)
def get_one(self, ptp_interface_map_uuid):
"""Retrieve a single PTP interface."""
LOG.debug("PtpInterfaceMapController.get_one: uuid=%s" %
ptp_interface_map_uuid)
try:
ptp_interface_map = objects.ptp_interface_map.get_by_uuid(
pecan.request.context,
ptp_interface_map_uuid)
except exception.InvalidParameterValue:
raise wsme.exc.ClientSideError(
_("No PTP interface mapping found for %s"
% ptp_interface_map_uuid))
return PtpInterfaceMap.convert_with_links(ptp_interface_map)
def _check_interface_exists(self, id):
LOG.debug("PtpInterfaceMapController._check_interface_exists: "
"id %d" % id)
try:
pecan.request.dbapi.iinterface_get(id)
except exception.InvalidParameterValue:
raise wsme.exc.ClientSideError(
_("No interface found with id %d" % id))
def _check_ptp_interface_exists(self, id):
LOG.debug("PtpInterfaceMapController._check_ptp_interface_exists: "
"id %d" % id)
try:
pecan.request.dbapi.ptp_interface_get(id)
except exception.PtpInterfaceNotFound:
raise wsme.exc.ClientSideError(
_("No PTP interface found with id %d" % id))
@cutils.synchronized(LOCK_NAME)
@wsme_pecan.wsexpose(PtpInterfaceMap, body=PtpInterfaceMap)
def post(self, ptp_interface_map):
"""Create a new PTP interface mapping."""
ptp_interface_map_dict = ptp_interface_map.as_dict()
LOG.debug("PtpInterfaceMapController.post: %s"
% ptp_interface_map_dict)
self._check_interface_exists(ptp_interface_map_dict['interface_id'])
self._check_ptp_interface_exists(
ptp_interface_map_dict['ptp_interface_id'])
result = pecan.request.dbapi.ptp_interface_set_interface(
ptp_interface_map_dict)
return PtpInterfaceMap.convert_with_links(result)
@cutils.synchronized(LOCK_NAME)
@wsme_pecan.wsexpose(None, types.uuid, status_code=204)
def delete(self, ptp_interface_map_uuid):
"""Delete a PTP interface mapping."""
LOG.debug("PtpInterfaceMapController.delete: %s"
% ptp_interface_map_uuid)
ptp_interface_map = objects.ptp_interface_map.get_by_uuid(
pecan.request.context, ptp_interface_map_uuid)
pecan.request.dbapi.ptp_parameter_unset_interface(
ptp_interface_map.as_dict())

View File

@ -46,7 +46,13 @@ class PtpParameterOwnership(base.APIBase):
"Unique UUID for this PTP parameter ownership" "Unique UUID for this PTP parameter ownership"
parameter_uuid = types.uuid parameter_uuid = types.uuid
"UUID of the PTP parameter (name/value)" "UUID of the PTP parameter"
parameter_name = wtypes.text
"Name of the PTP parameter"
parameter_value = wtypes.text
"Value of the PTP parameter"
owner_uuid = types.uuid owner_uuid = types.uuid
"UUID of the entity associated to PTP parameter (instance or interface)" "UUID of the entity associated to PTP parameter (instance or interface)"
@ -64,7 +70,8 @@ class PtpParameterOwnership(base.APIBase):
**rpc_ptp_paramownership.as_dict()) **rpc_ptp_paramownership.as_dict())
if not expand: if not expand:
ptp_parameter_ownership.unset_fields_except( ptp_parameter_ownership.unset_fields_except(
['uuid', 'parameter_uuid', 'owner_uuid', 'created_at']) ['uuid', 'parameter_uuid', 'parameter_name', 'parameter_value',
'owner_uuid', 'created_at'])
LOG.debug("PtpParameterOwnership.convert_with_links: converted %s" % LOG.debug("PtpParameterOwnership.convert_with_links: converted %s" %
ptp_parameter_ownership.as_dict()) ptp_parameter_ownership.as_dict())
@ -139,6 +146,14 @@ class PtpParameterOwnershipController(rest.RestController):
LOG.debug("PtpParameterOwnershipController.post: %s" LOG.debug("PtpParameterOwnershipController.post: %s"
% ptp_paramownership_dict) % ptp_paramownership_dict)
# Get rid of parameter details to set the ownership
try:
ptp_paramownership_dict.pop('parameter_name')
ptp_paramownership_dict.pop('parameter_value')
except KeyError:
LOG.debug("PtpParameterController.post: no parameter data in %s" %
ptp_paramownership_dict)
self._check_parameter_exists(ptp_paramownership_dict['parameter_uuid']) self._check_parameter_exists(ptp_paramownership_dict['parameter_uuid'])
self._check_owner_exists(ptp_paramownership_dict['owner_uuid']) self._check_owner_exists(ptp_paramownership_dict['owner_uuid'])
@ -150,7 +165,7 @@ class PtpParameterOwnershipController(rest.RestController):
@wsme_pecan.wsexpose(None, types.uuid, status_code=204) @wsme_pecan.wsexpose(None, types.uuid, status_code=204)
def delete(self, ptp_paramownership_uuid): def delete(self, ptp_paramownership_uuid):
"""Delete a PTP parameter ownership.""" """Delete a PTP parameter ownership."""
LOG.debug("PtpParameterController.delete: %s" LOG.debug("PtpParameterOwnershipController.delete: %s"
% ptp_paramownership_uuid) % ptp_paramownership_uuid)
ptp_paramownership = objects.ptp_paramownership.get_by_uuid( ptp_paramownership = objects.ptp_paramownership.get_by_uuid(
pecan.request.context, ptp_paramownership_uuid) pecan.request.context, ptp_paramownership_uuid)

View File

@ -469,6 +469,16 @@ class PtpParameterOwnershipAlreadyExists(Conflict):
message = _("UUID %(param)s is already a PTP parameter of UUID %(owner)s.") message = _("UUID %(param)s is already a PTP parameter of UUID %(owner)s.")
class PtpInstanceMapAlreadyExists(Conflict):
message = _("PTP instance %(ptp_instance)s is already associated to host "
"%(host)s.")
class PtpInterfaceMapAlreadyExists(Conflict):
message = _("PTP interface %(ptp_interface)s is already associated to "
"interface %(interface)s.")
class PMAlreadyExists(Conflict): class PMAlreadyExists(Conflict):
message = _("A PM with UUID %(uuid)s already exists.") message = _("A PM with UUID %(uuid)s already exists.")
@ -617,6 +627,14 @@ class PtpParameterOwnershipNotFound(NotFound):
message = _("No PTP parameter ownership with id %(uuid)s found.") message = _("No PTP parameter ownership with id %(uuid)s found.")
class PtpInstanceMapNotFound(NotFound):
message = _("No PTP instance mapping with id %(uuid)s found.")
class PtpInterfaceMapNotFound(NotFound):
message = _("No PTP interface mapping with id %(uuid)s found.")
class DiskNotFound(NotFound): class DiskNotFound(NotFound):
message = _("No disk with id %(disk_id)s") message = _("No disk with id %(disk_id)s")

View File

@ -1938,11 +1938,11 @@ class Connection(object):
""" """
@abc.abstractmethod @abc.abstractmethod
def ptp_instances_get_list(self, host=None, limit=None, marker=None, def ptp_instances_get_list(self, host_uuid=None, limit=None, marker=None,
sort_key=None, sort_dir=None): sort_key=None, sort_dir=None):
"""Returns a list of PTP service instances. """Returns a list of PTP service instances.
:param host: id or uuid of host. :param host_uuid: id or uuid of host.
:param limit: Maximum number of PTP instances to return. :param limit: Maximum number of PTP instances to return.
:param marker: The last item of the previous page; we return the next :param marker: The last item of the previous page; we return the next
result set. result set.
@ -1952,6 +1952,46 @@ class Connection(object):
:returns: A list of PTP instances. :returns: A list of PTP instances.
""" """
@abc.abstractmethod
def ptp_instance_set_host(self, values):
"""Set the PTP instance to some host.
:param values: A dict containing the IDs used to associate
the PTP instance to the host.
{
'host_id': 1,
'ptp_instance_id': 3
}
:returns: A PTP instance mapping.
"""
@abc.abstractmethod
def ptp_instance_unset_host(self, values):
"""Remove the association between a PTP instance and a host.
:param values: A dict containing the IDs used to associate
the PTP instance to the host.
{
'host_id': 1,
'ptp_instance_id': 3
}
"""
@abc.abstractmethod
def ptp_instance_get_hosts(self, ptp_instance_id, limit=None, marker=None,
sort_key=None, sort_dir=None):
"""Returns a list of all hosts associated to the PTP instance.
:param ptp_instance_id: The id or uuid of a PTP instance.
:param limit: Maximum number of hosts to return.
:param marker: The last item of the previous page; we return the next
result set.
:param sort_key: Attribute by which results should be sorted
:param sort_dir: direction in which results should be sorted
(asc, desc)
:returns: A list of hosts for the given PTP instance.
"""
@abc.abstractmethod @abc.abstractmethod
def ptp_instance_destroy(self, ptp_instance_id): def ptp_instance_destroy(self, ptp_instance_id):
"""Destroys a PTP service instance. """Destroys a PTP service instance.
@ -1966,6 +2006,14 @@ class Connection(object):
:param name: The name given for a PTP instance. :param name: The name given for a PTP instance.
""" """
@abc.abstractmethod
def ptp_instance_map_get(self, ptp_instance_map_id):
"""Returns a PTP instance mapping.
:param ptp_instance_map_id: The id or uuid of a PTP instance map.
:returns: A PTP instance map.
"""
@abc.abstractmethod @abc.abstractmethod
def ptp_interface_create(self, values): def ptp_interface_create(self, values):
"""Creates a new PTP association between an interface """Creates a new PTP association between an interface
@ -2046,6 +2094,46 @@ class Connection(object):
interface. interface.
""" """
@abc.abstractmethod
def ptp_interface_set_interface(self, values):
"""Set the PTP interface to some interface.
:param values: A dict containing the IDs used to associate
the PTP interface to the interface.
{
'interface_id': 1,
'ptp_interface_id': 3
}
:returns: A PTP interface mapping.
"""
@abc.abstractmethod
def ptp_interface_unset_interface(self, values):
"""Remove the association between a PTP interface and a interface.
:param values: A dict containing the IDs used to associate
the PTP interface to the interface.
{
'interface_id': 1,
'ptp_interface_id': 3
}
"""
@abc.abstractmethod
def ptp_interface_get_interfaces(self, ptp_interface_id, limit=None,
marker=None, sort_key=None, sort_dir=None):
"""Returns a list of all interfaces associated to the PTP interface.
:param ptp_interface_id: The id or uuid of a PTP interface.
:param limit: Maximum number of interfaces to return.
:param marker: The last item of the previous page; we return the next
result set.
:param sort_key: Attribute by which results should be sorted
:param sort_dir: direction in which results should be sorted
(asc, desc)
:returns: A list of interfaces for the given PTP interface.
"""
@abc.abstractmethod @abc.abstractmethod
def ptp_interface_destroy(self, ptp_interface_id): def ptp_interface_destroy(self, ptp_interface_id):
"""Destroys a PTP interface association. """Destroys a PTP interface association.
@ -2053,6 +2141,14 @@ class Connection(object):
:param ptp_interface_id: The id or uuid of a PTP interface association. :param ptp_interface_id: The id or uuid of a PTP interface association.
""" """
@abc.abstractmethod
def ptp_interface_map_get(self, ptp_interface_map_id):
"""Returns a PTP interface mapping.
:param ptp_interface_map_id: The id or uuid of a PTP interface map.
:returns: A PTP interface map.
"""
@abc.abstractmethod @abc.abstractmethod
def ptp_parameter_create(self, values): def ptp_parameter_create(self, values):
"""Creates a new PTP parameter to be applied later either to some """Creates a new PTP parameter to be applied later either to some

View File

@ -3779,25 +3779,58 @@ class Connection(api.Connection):
raise exception.NotFound() raise exception.NotFound()
@objects.objectify(objects.ptp_instance) @objects.objectify(objects.ptp_instance)
def ptp_instances_get_list(self, host=None, limit=None, marker=None, def ptp_instances_get_list(self, host_uuid=None, limit=None, marker=None,
sort_key=None, sort_dir=None): sort_key=None, sort_dir=None):
query = model_query(models.PtpInstances) query = model_query(models.PtpInstances)
if host is not None: if host_uuid is not None:
if utils.is_int_like(host): host = self.ihost_get(host_uuid)
ihost = self.ihost_get(int(host)) query = query.join(models.PtpInstanceMaps,
elif utils.is_uuid_like(host): models.PtpInstanceMaps.host_id == host.id)
ihost = self.ihost_get(host.strip())
elif isinstance(host, models.ihost):
ihost = host
else:
raise exception.NodeNotFound(node=host)
ptp_instance_id = ihost['ptp_instance_id']
if not ptp_instance_id:
return []
query = add_identity_filter(query, ptp_instance_id)
return _paginate_query(models.PtpInstances, limit, marker, return _paginate_query(models.PtpInstances, limit, marker,
sort_key, sort_dir, query) sort_key, sort_dir, query)
@objects.objectify(objects.ptp_instance_map)
def ptp_instance_set_host(self, values):
if not values.get('uuid'):
values['uuid'] = uuidutils.generate_uuid()
ptp_instance_map = models.PtpInstanceMaps(**values)
with _session_for_write() as session:
try:
session.add(ptp_instance_map)
session.flush()
except db_exc.DBDuplicateEntry:
raise exception.PtpInstanceMapAlreadyExists(
ptp_instance=values['ptp_instance_id'],
host=values['host_id'])
query = model_query(models.PtpInstanceMaps)
query = add_identity_filter(query, values['uuid'])
try:
return query.one()
except NoResultFound:
raise exception.PtpInstanceMapNotFound(uuid=values['uuid'])
def ptp_instance_unset_host(self, values):
with _session_for_write() as session:
query = model_query(models.PtpInstanceMaps, session=session)
query = query.filter_by(ptp_instance_id=values['ptp_instance_id'],
host_id=values['host_id'])
try:
query.one()
except NoResultFound:
return
query.delete()
@objects.objectify(objects.ptp_instance)
def ptp_instance_get_hosts(self, ptp_instance_id, limit=None, marker=None,
sort_key=None, sort_dir=None):
query = model_query(models.PtpInstances)
query = add_identity_filter(query, ptp_instance_id)
query = query.join(models.PtpInstances.hosts)
return _paginate_query(models.PtpInstances, limit, marker, sort_key,
sort_dir, query)
def ptp_instance_destroy(self, ptp_instance_id): def ptp_instance_destroy(self, ptp_instance_id):
with _session_for_write() as session: with _session_for_write() as session:
# PTP instance will be deleted by cascade # PTP instance will be deleted by cascade
@ -3819,6 +3852,15 @@ class Connection(api.Connection):
raise exception.NotFound() raise exception.NotFound()
query.delete() query.delete()
@objects.objectify(objects.ptp_instance_map)
def ptp_instance_map_get(self, ptp_instance_map_id):
query = model_query(models.PtpInstanceMaps)
query = add_identity_filter(query, ptp_instance_map_id)
try:
return query.one()
except NoResultFound:
raise exception.PtpInstanceMapNotFound(uuid=ptp_instance_map_id)
def _ptp_interface_get(self, ptp_interface_id): def _ptp_interface_get(self, ptp_interface_id):
query = model_query(models.PtpInterfaces) query = model_query(models.PtpInterfaces)
query = add_identity_filter(query, ptp_interface_id) query = add_identity_filter(query, ptp_interface_id)
@ -3910,6 +3952,50 @@ class Connection(api.Connection):
return _paginate_query(models.PtpInterfaces, limit, marker, return _paginate_query(models.PtpInterfaces, limit, marker,
sort_key, sort_dir, query) sort_key, sort_dir, query)
@objects.objectify(objects.ptp_interface_map)
def ptp_interface_set_interface(self, values):
if not values.get('uuid'):
values['uuid'] = uuidutils.generate_uuid()
ptp_interface_map = models.PtpInterfaceMaps(**values)
with _session_for_write() as session:
try:
session.add(ptp_interface_map)
session.flush()
except db_exc.DBDuplicateEntry:
raise exception.PtpInterfaceMapAlreadyExists(
ptp_interface=values['ptp_interface_id'],
interface=values['interface_id'])
query = model_query(models.PtpInterfaceMaps)
query = add_identity_filter(query, values['uuid'])
try:
return query.one()
except NoResultFound:
raise exception.PtpInterfaceMapNotFound(uuid=values['uuid'])
def ptp_interface_unset_interface(self, values):
with _session_for_write() as session:
query = model_query(models.PtpInterfaceMaps, session=session)
query = query.filter_by(
ptp_interface_id=values['ptp_interface_id'],
interface_id=values['interface_id'])
try:
query.one()
except NoResultFound:
return
query.delete()
@objects.objectify(objects.ptp_interface)
def ptp_interface_get_interfaces(self, ptp_interface_id, limit=None,
marker=None, sort_key=None,
sort_dir=None):
query = model_query(models.PtpInterfaces)
query = add_identity_filter(query, ptp_interface_id)
query = query.join(models.PtpInterfaces.interfaces)
return _paginate_query(models.PtpInterfaces, limit, marker, sort_key,
sort_dir, query)
def ptp_interface_destroy(self, ptp_interface_id): def ptp_interface_destroy(self, ptp_interface_id):
with _session_for_write() as session: with _session_for_write() as session:
# PTP instance will be deleted by cascade # PTP instance will be deleted by cascade
@ -3921,6 +4007,15 @@ class Connection(api.Connection):
raise exception.PtpInterfaceNotFound(uuid=ptp_interface_id) raise exception.PtpInterfaceNotFound(uuid=ptp_interface_id)
query.delete() query.delete()
@objects.objectify(objects.ptp_interface_map)
def ptp_interface_map_get(self, ptp_interface_map_id):
query = model_query(models.PtpInterfaceMaps)
query = add_identity_filter(query, ptp_interface_map_id)
try:
return query.one()
except NoResultFound:
raise exception.PtpInterfaceMapNotFound(uuid=ptp_interface_map_id)
def _ptp_parameter_get(self, ptp_parameter_id): def _ptp_parameter_get(self, ptp_parameter_id):
query = model_query(models.PtpParameters) query = model_query(models.PtpParameters)
query = add_identity_filter(query, ptp_parameter_id) query = add_identity_filter(query, ptp_parameter_id)

View File

@ -21,8 +21,7 @@ ENGINE = 'InnoDB'
CHARSET = 'utf8' CHARSET = 'utf8'
def _populate_ptp_tables(meta, ptp_instances, ptp_interfaces, def _populate_ptp_tables(meta, tables):
ptp_parameters, ptp_parameter_ownerships):
"""This function moves PTP configuration from other tables: """This function moves PTP configuration from other tables:
- If advanced (specialized) ptp4l configuration is found in - If advanced (specialized) ptp4l configuration is found in
'service_parameter' table, it inserts a 'ptp4l' entry in 'service_parameter' table, it inserts a 'ptp4l' entry in
@ -46,6 +45,8 @@ def upgrade(migrate_engine):
meta = MetaData() meta = MetaData()
meta.bind = migrate_engine meta.bind = migrate_engine
tables = {}
ptp_parameters = Table( ptp_parameters = Table(
'ptp_parameters', 'ptp_parameters',
meta, meta,
@ -65,6 +66,7 @@ def upgrade(migrate_engine):
mysql_charset=CHARSET, mysql_charset=CHARSET,
) )
ptp_parameters.create() ptp_parameters.create()
tables.update({'ptp_parameters': ptp_parameters})
ptp_parameter_owners = Table( ptp_parameter_owners = Table(
'ptp_parameter_owners', 'ptp_parameter_owners',
@ -84,6 +86,7 @@ def upgrade(migrate_engine):
mysql_charset=CHARSET, mysql_charset=CHARSET,
) )
ptp_parameter_owners.create() ptp_parameter_owners.create()
tables.update({'ptp_parameter_owners': ptp_parameter_owners})
ptp_instances = Table( ptp_instances = Table(
'ptp_instances', 'ptp_instances',
@ -103,10 +106,7 @@ def upgrade(migrate_engine):
mysql_charset=CHARSET, mysql_charset=CHARSET,
) )
ptp_instances.create() ptp_instances.create()
tables.update({'ptp_instances': ptp_instances})
host = Table('i_host', meta, autoload=True)
host.create_column(
Column('ptp_instance_id', Integer, ForeignKey('ptp_instances.id')))
ptp_interfaces = Table( ptp_interfaces = Table(
'ptp_interfaces', 'ptp_interfaces',
@ -127,10 +127,7 @@ def upgrade(migrate_engine):
mysql_charset=CHARSET, mysql_charset=CHARSET,
) )
ptp_interfaces.create() ptp_interfaces.create()
tables.update({'ptp_interfaces': ptp_interfaces})
interface = Table('interfaces', meta, autoload=True)
interface.create_column(
Column('ptp_interface_id', Integer, ForeignKey('ptp_interfaces.id')))
ptp_parameter_ownerships = Table( ptp_parameter_ownerships = Table(
'ptp_parameter_ownerships', 'ptp_parameter_ownerships',
@ -145,7 +142,9 @@ def upgrade(migrate_engine):
Column('parameter_uuid', String(UUID_LENGTH), Column('parameter_uuid', String(UUID_LENGTH),
ForeignKey('ptp_parameters.uuid', ondelete='CASCADE'), ForeignKey('ptp_parameters.uuid', ondelete='CASCADE'),
nullable=False), nullable=False),
Column('owner_uuid', String(UUID_LENGTH), nullable=False), Column('owner_uuid', String(UUID_LENGTH),
ForeignKey('ptp_parameter_owners.uuid', ondelete='CASCADE'),
nullable=False),
UniqueConstraint('parameter_uuid', 'owner_uuid', name='u_paramowner'), UniqueConstraint('parameter_uuid', 'owner_uuid', name='u_paramowner'),
@ -153,15 +152,78 @@ def upgrade(migrate_engine):
mysql_charset=CHARSET, mysql_charset=CHARSET,
) )
ptp_parameter_ownerships.create() ptp_parameter_ownerships.create()
tables.update({'ptp_parameter_ownerships': ptp_parameter_ownerships})
_populate_ptp_tables(meta, ptp_instances, ptp_interfaces, ptp_parameters, i_host = Table('i_host', meta, autoload=True)
ptp_parameter_ownerships) tables.update({'i_host': i_host})
ptp_instance_maps = Table(
'ptp_instance_maps',
meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('deleted_at', DateTime),
Column('id', Integer, primary_key=True, nullable=False),
Column('uuid', String(UUID_LENGTH), unique=True),
Column('host_id', Integer,
ForeignKey('i_host.id', ondelete='CASCADE'),
nullable=False),
Column('ptp_instance_id', Integer,
ForeignKey('ptp_instances.id', ondelete='CASCADE'),
nullable=False),
UniqueConstraint('host_id', 'ptp_instance_id', name='u_hostinstance'),
mysql_engine=ENGINE,
mysql_charset=CHARSET,
)
ptp_instance_maps.create()
tables.update({'ptp_instance_maps': ptp_instance_maps})
interfaces = Table('interfaces', meta, autoload=True)
tables.update({'interfaces': interfaces})
ptp_interface_maps = Table(
'ptp_interface_maps',
meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('deleted_at', DateTime),
Column('id', Integer, primary_key=True, nullable=False),
Column('uuid', String(UUID_LENGTH), unique=True),
Column('interface_id', Integer,
ForeignKey('interfaces.id', ondelete='CASCADE'),
nullable=False),
Column('ptp_interface_id', Integer,
ForeignKey('ptp_interfaces.id', ondelete='CASCADE'),
nullable=False),
UniqueConstraint('interface_id', 'ptp_interface_id',
name='u_ifaceptpiface'),
mysql_engine=ENGINE,
mysql_charset=CHARSET,
)
ptp_interface_maps.create()
tables.update({'ptp_interface_maps': ptp_interface_maps})
_populate_ptp_tables(meta, tables)
def downgrade(migrate_engine): def downgrade(migrate_engine):
meta = MetaData() meta = MetaData()
meta.bind = migrate_engine meta.bind = migrate_engine
ptp_interface_maps = Table('ptp_interface_maps', meta, autoload=True)
ptp_interface_maps.drop()
ptp_instance_maps = Table('ptp_instance_maps', meta, autoload=True)
ptp_instance_maps.drop()
ptp_parameter_ownerships = Table('ptp_parameter_ownerships', ptp_parameter_ownerships = Table('ptp_parameter_ownerships',
meta, meta,
autoload=True) autoload=True)

View File

@ -245,14 +245,19 @@ class ihost(Base):
peer_id = Column(Integer, peer_id = Column(Integer,
ForeignKey('peers.id')) ForeignKey('peers.id'))
ptp_instance_id = Column(Integer, ForeignKey('ptp_instances.id'))
ptp = relationship("PtpInstances", lazy="joined", join_depth=1)
system = relationship("isystem") system = relationship("isystem")
host_upgrade = relationship("HostUpgrade", uselist=False) host_upgrade = relationship("HostUpgrade", uselist=False)
kube_host_upgrade = relationship("KubeHostUpgrade", uselist=False) kube_host_upgrade = relationship("KubeHostUpgrade", uselist=False)
ptp_instances = relationship(
"PtpInstances",
secondary="ptp_instance_maps",
primaryjoin="ihost.id == foreign(PtpInstanceMaps.host_id)",
secondaryjoin="PtpInstances.id == "
"foreign(PtpInstanceMaps.ptp_instance_id)",
back_populates="hosts", lazy="joined", join_depth=1)
class inode(Base): class inode(Base):
__tablename__ = 'i_node' __tablename__ = 'i_node'
@ -361,9 +366,6 @@ class Interfaces(Base):
sriov_vf_driver = Column(String(255)) sriov_vf_driver = Column(String(255))
ptp_role = Column(String(255), default='none') # TODO: deprecate it ptp_role = Column(String(255), default='none') # TODO: deprecate it
ptp_interface_id = Column(Integer, ForeignKey('ptp_interfaces.id'))
ptp = relationship("PtpInterfaces", lazy="joined", join_depth=1)
used_by = relationship( used_by = relationship(
"Interfaces", "Interfaces",
secondary=interfaces_to_interfaces, secondary=interfaces_to_interfaces,
@ -389,6 +391,14 @@ class Interfaces(Base):
backref=backref("interface", lazy="joined"), backref=backref("interface", lazy="joined"),
cascade="all") cascade="all")
ptp_interfaces = relationship(
"PtpInterfaces",
secondary="ptp_interface_maps",
primaryjoin="Interfaces.id == foreign(PtpInterfaceMaps.interface_id)",
secondaryjoin="PtpInterfaces.id == "
"foreign(PtpInterfaceMaps.ptp_interface_id)",
back_populates="interfaces", lazy="joined", join_depth=1)
UniqueConstraint('ifname', 'forihostid', name='u_interfacenameihost') UniqueConstraint('ifname', 'forihostid', name='u_interfacenameihost')
__mapper_args__ = { __mapper_args__ = {
@ -846,6 +856,14 @@ class PtpInstances(PtpParameterOwners):
name = Column(String(255), unique=True, nullable=False) name = Column(String(255), unique=True, nullable=False)
service = Column(String(255)) service = Column(String(255))
hosts = relationship(
"ihost",
secondary="ptp_instance_maps",
primaryjoin="PtpInstances.id == "
"foreign(PtpInstanceMaps.ptp_instance_id)",
secondaryjoin="ihost.id == foreign(PtpInstanceMaps.host_id)",
back_populates="ptp_instances", lazy="joined", join_depth=1)
__mapper_args__ = { __mapper_args__ = {
'polymorphic_identity': constants.PTP_PARAMETER_OWNER_INSTANCE 'polymorphic_identity': constants.PTP_PARAMETER_OWNER_INSTANCE
} }
@ -868,6 +886,15 @@ class PtpInterfaces(PtpParameterOwners):
PtpInstances.name, PtpInstances.name,
PtpInstances.uuid]) PtpInstances.uuid])
interfaces = relationship(
"Interfaces",
secondary="ptp_interface_maps",
primaryjoin="PtpInterfaces.id == "
"foreign(PtpInterfaceMaps.ptp_interface_id)",
secondaryjoin="Interfaces.id == "
"foreign(PtpInterfaceMaps.interface_id)",
back_populates="ptp_interfaces", lazy="joined", join_depth=1)
__mapper_args__ = { __mapper_args__ = {
'polymorphic_identity': constants.PTP_PARAMETER_OWNER_INTERFACE 'polymorphic_identity': constants.PTP_PARAMETER_OWNER_INTERFACE
} }
@ -887,20 +914,64 @@ class PtpParameterOwnerships(Base):
ForeignKey('ptp_parameters.uuid', ForeignKey('ptp_parameters.uuid',
ondelete='CASCADE'), ondelete='CASCADE'),
nullable=False) nullable=False)
owner_uuid = Column(String(UUID_LENGTH), nullable=False) owner_uuid = Column(String(UUID_LENGTH),
ForeignKey('ptp_parameter_owners.uuid',
ondelete='CASCADE'),
nullable=False)
parameter = relationship("PtpParameters", lazy="joined", join_depth=1) parameter = relationship("PtpParameters", lazy="joined", join_depth=1)
owner = relationship("PtpParameterOwners", lazy="joined", join_depth=1)
owner = relationship(
"PtpParameterOwners",
primaryjoin="PtpParameterOwnerships.owner_uuid == "
"foreign(PtpParameterOwners.uuid)",
lazy="joined",
join_depth=1)
UniqueConstraint('parameter_uuid', 'owner_uuid', name='u_paramowner') UniqueConstraint('parameter_uuid', 'owner_uuid', name='u_paramowner')
class PtpInstanceMaps(Base):
"""
This is a bridge table used to model the many-to-many relationship between
PTP instances (the services) and the hosts they run.
"""
__tablename__ = "ptp_instance_maps"
id = Column(Integer, primary_key=True, nullable=False)
uuid = Column(String(UUID_LENGTH), unique=True)
host_id = Column(Integer,
ForeignKey('i_host.id', ondelete='CASCADE'),
nullable=False)
ptp_instance_id = Column(
Integer, ForeignKey('ptp_instances.id', ondelete='CASCADE'),
nullable=False)
host = relationship("ihost", lazy="joined", join_depth=1)
instance = relationship("PtpInstances", lazy="joined", join_depth=1)
UniqueConstraint('host_id', 'ptp_instance_id', name='u_hostinstance')
class PtpInterfaceMaps(Base):
"""
This is a bridge table used to model the many-to-many relationship between
PTP interfaces (PTP services and parameters) and the interfaces they run.
"""
__tablename__ = "ptp_interface_maps"
id = Column(Integer, primary_key=True, nullable=False)
uuid = Column(String(UUID_LENGTH), unique=True)
interface_id = Column(Integer,
ForeignKey('interfaces.id', ondelete='CASCADE'),
nullable=False)
ptp_interface_id = Column(
Integer, ForeignKey('ptp_interfaces.id', ondelete='CASCADE'),
nullable=False)
interface = relationship("Interfaces", lazy="joined", join_depth=1)
ptp_interface = relationship("PtpInterfaces", lazy="joined", join_depth=1)
UniqueConstraint('interface_id', 'ptp_interface_id',
name='u_ifaceptpiface')
class StorageTier(Base): class StorageTier(Base):
__tablename__ = 'storage_tiers' __tablename__ = 'storage_tiers'

View File

@ -71,7 +71,9 @@ from sysinv.objects import peer
from sysinv.objects import port from sysinv.objects import port
from sysinv.objects import ptp from sysinv.objects import ptp
from sysinv.objects import ptp_instance from sysinv.objects import ptp_instance
from sysinv.objects import ptp_instance_map
from sysinv.objects import ptp_interface from sysinv.objects import ptp_interface
from sysinv.objects import ptp_interface_map
from sysinv.objects import ptp_parameter from sysinv.objects import ptp_parameter
from sysinv.objects import ptp_paramowner from sysinv.objects import ptp_paramowner
from sysinv.objects import ptp_paramownership from sysinv.objects import ptp_paramownership
@ -160,7 +162,9 @@ dns = dns.DNS
ntp = ntp.NTP ntp = ntp.NTP
ptp = ptp.PTP ptp = ptp.PTP
ptp_instance = ptp_instance.PtpInstance ptp_instance = ptp_instance.PtpInstance
ptp_instance_map = ptp_instance_map.PtpInstanceMap
ptp_interface = ptp_interface.PtpInterface ptp_interface = ptp_interface.PtpInterface
ptp_interface_map = ptp_interface_map.PtpInterfaceMap
ptp_parameter = ptp_parameter.PtpParameter ptp_parameter = ptp_parameter.PtpParameter
ptp_paramowner = ptp_paramowner.PtpParameterOwner ptp_paramowner = ptp_paramowner.PtpParameterOwner
ptp_paramownership = ptp_paramownership.PtpParameterOwnership ptp_paramownership = ptp_paramownership.PtpParameterOwnership
@ -244,7 +248,9 @@ __all__ = ("system",
"ntp", "ntp",
"ptp", "ptp",
"ptp_instance", "ptp_instance",
"ptp_instance_map",
"ptp_interface", "ptp_interface",
"ptp_interface_map",
"ptp_parameter", "ptp_parameter",
"ptp_paramowner", "ptp_paramowner",
"ptp_paramownership", "ptp_paramownership",

View File

@ -23,11 +23,6 @@ def _get_target_load(field, db_object):
return db_object.host_upgrade.load_target.software_version return db_object.host_upgrade.load_target.software_version
def _get_ptp_configuration(field, db_object):
# TODO
return {}
class Host(base.SysinvObject): class Host(base.SysinvObject):
dbapi = db_api.get_instance() dbapi = db_api.get_instance()
@ -37,7 +32,6 @@ class Host(base.SysinvObject):
'forisystemid': utils.int_or_none, 'forisystemid': utils.int_or_none,
'isystem_uuid': utils.str_or_none, 'isystem_uuid': utils.str_or_none,
'peer_id': utils.int_or_none, 'peer_id': utils.int_or_none,
'ptp_instance_id': utils.int_or_none,
'recordtype': utils.str_or_none, 'recordtype': utils.str_or_none,
# 'created_at': utils.datetime_str_or_none, # 'created_at': utils.datetime_str_or_none,
@ -82,7 +76,6 @@ class Host(base.SysinvObject):
'config_target': utils.str_or_none, 'config_target': utils.str_or_none,
'capabilities': utils.dict_or_none, 'capabilities': utils.dict_or_none,
'clock_synchronization': utils.str_or_none, 'clock_synchronization': utils.str_or_none,
'ptp_config': utils.dict_or_none,
'boot_device': utils.str_or_none, 'boot_device': utils.str_or_none,
'rootfs_device': utils.str_or_none, 'rootfs_device': utils.str_or_none,
@ -103,8 +96,7 @@ class Host(base.SysinvObject):
_foreign_fields = { _foreign_fields = {
'isystem_uuid': 'system:uuid', 'isystem_uuid': 'system:uuid',
'software_load': _get_software_load, 'software_load': _get_software_load,
'target_load': _get_target_load, 'target_load': _get_target_load
'ptp_config': _get_ptp_configuration
} }
@base.remotable_classmethod @base.remotable_classmethod

View File

@ -108,11 +108,6 @@ def get_datanetworks(field, db_object):
return result return result
def _get_ptp_configuration(field, db_object):
# TODO
return {}
class Interface(base.SysinvObject): class Interface(base.SysinvObject):
# VERSION 1.0: Initial version # VERSION 1.0: Initial version
# VERSION 1.1: Added VLAN and uses/used_by interface support # VERSION 1.1: Added VLAN and uses/used_by interface support
@ -125,7 +120,6 @@ class Interface(base.SysinvObject):
'uuid': utils.str_or_none, 'uuid': utils.str_or_none,
'forihostid': utils.int_or_none, 'forihostid': utils.int_or_none,
'ihost_uuid': utils.str_or_none, 'ihost_uuid': utils.str_or_none,
'ptp_interface_id': utils.int_or_none,
'ifname': utils.str_or_none, 'ifname': utils.str_or_none,
'iftype': utils.str_or_none, 'iftype': utils.str_or_none,
@ -154,7 +148,6 @@ class Interface(base.SysinvObject):
'sriov_numvfs': utils.int_or_none, 'sriov_numvfs': utils.int_or_none,
'sriov_vf_driver': utils.str_or_none, 'sriov_vf_driver': utils.str_or_none,
'ptp_role': utils.str_or_none, 'ptp_role': utils.str_or_none,
'ptp_config': utils.dict_or_none,
'max_tx_rate': utils.int_or_none, 'max_tx_rate': utils.int_or_none,
} }
@ -166,8 +159,7 @@ class Interface(base.SysinvObject):
'ipv6_pool': get_ipv6_address_pool, 'ipv6_pool': get_ipv6_address_pool,
'ihost_uuid': get_host_uuid, 'ihost_uuid': get_host_uuid,
'networktypelist': get_networktypes, 'networktypelist': get_networktypes,
'datanetworks': get_datanetworks, 'datanetworks': get_datanetworks}
'ptp_config': _get_ptp_configuration}
_optional_fields = ['aemode', 'txhashpolicy', 'schedpolicy', _optional_fields = ['aemode', 'txhashpolicy', 'schedpolicy',
'vlan_id', 'vlan_type', 'primary_reselect'] 'vlan_id', 'vlan_type', 'primary_reselect']

View File

@ -12,16 +12,30 @@ from sysinv.objects import utils
from sysinv.objects import ptp_paramowner from sysinv.objects import ptp_paramowner
def get_hosts(field, db_object):
hosts = db_object['hosts']
if not hosts:
return []
hostnames = []
for h in hosts:
hostnames.append(h.hostname)
return hostnames
class PtpInstance(ptp_paramowner.PtpParameterOwner): class PtpInstance(ptp_paramowner.PtpParameterOwner):
dbapi = db_api.get_instance() dbapi = db_api.get_instance()
fields = dict({ fields = dict({
'name': utils.str_or_none, 'name': utils.str_or_none,
'service': utils.str_or_none 'service': utils.str_or_none,
'hosts': utils.list_of_strings_or_none
}, **ptp_paramowner.PtpParameterOwner.fields) }, **ptp_paramowner.PtpParameterOwner.fields)
_foreign_fields = {} _foreign_fields = {
'hosts': get_hosts
}
@base.remotable_classmethod @base.remotable_classmethod
def get_by_uuid(cls, context, uuid): def get_by_uuid(cls, context, uuid):

View File

@ -0,0 +1,40 @@
########################################################################
#
# Copyright (c) 2021 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
########################################################################
from sysinv.db import api as db_api
from sysinv.objects import base
from sysinv.objects import utils
class PtpInstanceMap(base.SysinvObject):
dbapi = db_api.get_instance()
fields = {
'id': int,
'uuid': utils.str_or_none,
'host_id': int,
'hostname': utils.str_or_none,
'ptp_instance_id': int,
'name': utils.str_or_none,
'service': utils.str_or_none
}
_foreign_fields = {
'host_id': 'host:id',
'hostname': 'host:hostname',
'ptp_instance_id': 'ptp_instance:id',
'name': 'ptp_instance:name',
'service': 'ptp_instance:service'
}
@base.remotable_classmethod
def get_by_uuid(cls, context, uuid):
return cls.dbapi.ptp_instance_map_get(uuid)

View File

@ -12,6 +12,24 @@ from sysinv.objects import utils
from sysinv.objects import ptp_paramowner from sysinv.objects import ptp_paramowner
def get_interfaces(field, db_object):
interfaces = db_object['interfaces']
if not interfaces:
return []
interfaces = []
for i in interfaces:
details = {}
details['name'] = i.ifname
details['type'] = i.iftype
host = getattr(i, 'host')
if host:
details['host'] = host.hostname
interfaces.append(details)
return interfaces
class PtpInterface(ptp_paramowner.PtpParameterOwner): class PtpInterface(ptp_paramowner.PtpParameterOwner):
dbapi = db_api.get_instance() dbapi = db_api.get_instance()
@ -19,12 +37,14 @@ class PtpInterface(ptp_paramowner.PtpParameterOwner):
fields = dict({ fields = dict({
'ptp_instance_id': utils.int_or_none, 'ptp_instance_id': utils.int_or_none,
'ptp_instance_uuid': utils.str_or_none, 'ptp_instance_uuid': utils.str_or_none,
'ptp_instance_name': utils.str_or_none 'ptp_instance_name': utils.str_or_none,
'interfaces': list
}, **ptp_paramowner.PtpParameterOwner.fields) }, **ptp_paramowner.PtpParameterOwner.fields)
_foreign_fields = { _foreign_fields = {
'ptp_instance_uuid': 'ptp_instance:uuid', 'ptp_instance_uuid': 'ptp_instance:uuid',
'ptp_instance_name': 'ptp_instance:name' 'ptp_instance_name': 'ptp_instance:name',
'interfaces': get_interfaces
} }
@base.remotable_classmethod @base.remotable_classmethod

View File

@ -0,0 +1,68 @@
########################################################################
#
# Copyright (c) 2021 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
########################################################################
from sysinv.db import api as db_api
from sysinv.objects import base
from sysinv.objects import utils
def get_hostname(field, db_object):
host = getattr(db_object['interface'], 'host')
if not host:
return None
return host.hostname
def get_instance_name(field, db_object):
instance = getattr(db_object['ptp_interface'], 'ptp_instance')
if not instance:
return None
return instance.name
def get_instance_service(field, db_object):
instance = getattr(db_object['ptp_interface'], 'ptp_instance')
if not instance:
return None
return instance.service
class PtpInterfaceMap(base.SysinvObject):
dbapi = db_api.get_instance()
fields = {
'id': int,
'uuid': utils.str_or_none,
'interface_id': int,
'ifname': utils.str_or_none,
'iftype': utils.str_or_none,
'hostname': utils.str_or_none,
'ptp_interface_id': int,
'name': utils.str_or_none,
'service': utils.str_or_none
}
_foreign_fields = {
'interface_id': 'interface:id',
'ifname': 'interface:ifname',
'iftype': 'interface:iftype',
'hostname': get_hostname,
'ptp_interface_id': 'ptp_interface:id',
'name': get_instance_name,
'service': get_instance_service
}
@base.remotable_classmethod
def get_by_uuid(cls, context, uuid):
return cls.dbapi.ptp_interface_map_get(uuid)

View File

@ -20,10 +20,18 @@ class PtpParameterOwnership(base.SysinvObject):
'uuid': utils.str_or_none, 'uuid': utils.str_or_none,
'parameter_uuid': utils.str_or_none, 'parameter_uuid': utils.str_or_none,
'parameter_name': utils.str_or_none,
'parameter_value': utils.str_or_none,
'owner_uuid': utils.str_or_none, 'owner_uuid': utils.str_or_none,
} }
_foreign_fields = {} _foreign_fields = {
'parameter_uuid': 'parameter:uuid',
'parameter_name': 'parameter:name',
'parameter_value': 'parameter:value',
'owner_uuid': 'owner:uuid'
}
@base.remotable_classmethod @base.remotable_classmethod
def get_by_uuid(cls, context, uuid): def get_by_uuid(cls, context, uuid):

View File

@ -2061,3 +2061,33 @@ class TestMigrations(BaseMigrationTestCase, WalkVersionsMixin):
self.assertTrue( self.assertTrue(
isinstance(ptp_parameter_ownerships.c[column].type, isinstance(ptp_parameter_ownerships.c[column].type,
getattr(sqlalchemy.types, column_type))) getattr(sqlalchemy.types, column_type)))
ptp_instance_maps = db_utils.get_table(engine, 'ptp_instance_maps')
ptp_instance_map_columns = {
'created_at': 'DateTime',
'updated_at': 'DateTime',
'deleted_at': 'DateTime',
'id': 'Integer',
'uuid': 'String',
'host_id': 'Integer',
'ptp_instance_id': 'Integer'
}
for column, column_type in ptp_instance_map_columns.items():
self.assertTrue(
isinstance(ptp_instance_maps.c[column].type,
getattr(sqlalchemy.types, column_type)))
ptp_interface_maps = db_utils.get_table(engine, 'ptp_interface_maps')
ptp_interface_map_columns = {
'created_at': 'DateTime',
'updated_at': 'DateTime',
'deleted_at': 'DateTime',
'id': 'Integer',
'uuid': 'String',
'interface_id': 'Integer',
'ptp_interface_id': 'Integer'
}
for column, column_type in ptp_interface_map_columns.items():
self.assertTrue(
isinstance(ptp_interface_maps.c[column].type,
getattr(sqlalchemy.types, column_type)))

View File

@ -597,6 +597,34 @@ def create_test_ptp_ownership(**kw):
return dbapi.ptp_parameter_set_owner(ownership) return dbapi.ptp_parameter_set_owner(ownership)
def get_test_ptp_instance_map(**kw):
map = {
'host_id': kw.get('host_id', None),
'ptp_instance_id': kw.get('ptp_instance_id', None)
}
return map
def create_test_ptp_instance_map(**kw):
map = get_test_ptp_instance_map(**kw)
dbapi = db_api.get_instance()
return dbapi.ptp_instance_set_host(map)
def get_test_ptp_interface_map(**kw):
map = {
'interface_id': kw.get('interface_id', None),
'ptp_interface_id': kw.get('ptp_interface_id', None)
}
return map
def create_test_ptp_interface_map(**kw):
map = get_test_ptp_interface_map(**kw)
dbapi = db_api.get_instance()
return dbapi.ptp_interface_set_interface(map)
# Create test dns object # Create test dns object
def get_test_dns(**kw): def get_test_dns(**kw):
dns = { dns = {