diff --git a/sysinv/cgts-client/cgts-client/cgtsclient/v1/client.py b/sysinv/cgts-client/cgts-client/cgtsclient/v1/client.py index 15b3d356d6..31b95442d6 100644 --- a/sysinv/cgts-client/cgts-client/cgtsclient/v1/client.py +++ b/sysinv/cgts-client/cgts-client/cgtsclient/v1/client.py @@ -72,6 +72,7 @@ from cgtsclient.v1 import ptp from cgtsclient.v1 import ptp_instance from cgtsclient.v1 import ptp_interface from cgtsclient.v1 import ptp_parameter +from cgtsclient.v1 import ptp_paramownership from cgtsclient.v1 import registry_image from cgtsclient.v1 import remotelogging from cgtsclient.v1 import restore @@ -124,6 +125,8 @@ class Client(http.HTTPClient): self.ptp_instance = ptp_instance.PtpInstanceManager(self) self.ptp_interface = ptp_interface.PtpInterfaceManager(self) self.ptp_parameter = ptp_parameter.PtpParameterManager(self) + self.ptp_paramownership = \ + ptp_paramownership.PtpParameterOwnershipManager(self) self.iextoam = iextoam.iextoamManager(self) self.controller_fs = controller_fs.ControllerFsManager(self) self.storage_backend = storage_backend.StorageBackendManager(self) diff --git a/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_instance.py b/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_instance.py index b78ef05f61..f0638dcc08 100644 --- a/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_instance.py +++ b/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_instance.py @@ -12,7 +12,7 @@ from cgtsclient import exc from cgtsclient.v1 import options -CREATION_ATTRIBUTES = ['name', 'service', 'host_uuid'] +CREATION_ATTRIBUTES = ['name', 'service'] class PtpInstance(base.Resource): @@ -50,6 +50,14 @@ class PtpInstanceManager(base.Manager): raise exc.InvalidAttribute('%s' % key) return self._create(self._path(), data) + def apply(self, ihost_uuid, ptp_instance_id): + return self._update('/v1/ihosts/%s?action=apply' % ihost_uuid, + ptp_instance_id) + + def remove(self, ihost_uuid, ptp_instance_id): + return self._update('/v1/ihosts/%s?action=remove' % ihost_uuid, + ptp_instance_id) + def delete(self, ptp_instance_id): return self._delete(self._path(ptp_instance_id)) diff --git a/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_instance_shell.py b/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_instance_shell.py index f8ba872e48..a7d9ba8d4c 100644 --- a/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_instance_shell.py +++ b/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_instance_shell.py @@ -16,18 +16,21 @@ def _print_ptp_instance_show(ptp_instance_obj): fields = ['uuid', 'name', 'service', - 'hostname', 'created_at'] data = [(f, getattr(ptp_instance_obj, f, '')) for f in fields] utils.print_tuple_list(data) +def _print_ptp_instance_list(ptp_instance_list): + field_labels = ['uuid', 'name', 'service'] + fields = ['uuid', 'name', 'service'] + utils.print_list(ptp_instance_list, fields, field_labels) + + def do_ptp_instance_list(cc, args): - """List all PTP instances, in any host.""" + """List all PTP instances.""" ptp_instances = cc.ptp_instance.list() - field_labels = ['uuid', 'name', 'service', 'hostname'] - fields = ['uuid', 'name', 'service', 'hostname'] - utils.print_list(ptp_instances, fields, field_labels) + _print_ptp_instance_list(ptp_instances) @utils.arg('hostnameorid', @@ -37,10 +40,7 @@ def do_host_ptp_instance_list(cc, args): """List PTP instances on host.""" ihost = ihost_utils._find_ihost(cc, args.hostnameorid) ptp_instances = cc.ptp_instance.list_by_host(ihost.uuid) - - field_labels = ['name', 'service', 'uuid'] - fields = ['name', 'service', 'uuid'] - utils.print_list(ptp_instances, fields, field_labels) + _print_ptp_instance_list(ptp_instances) @utils.arg('nameoruuid', @@ -59,9 +59,6 @@ def do_ptp_instance_show(cc, args): metavar='', choices=['ptp4l', 'phc2sys', 'ts2phc'], help="Service type [REQUIRED]") -@utils.arg('hostnameorid', - metavar='', - help="Name or ID of host [REQUIRED]") def do_ptp_instance_add(cc, args): """Add a PTP instance.""" @@ -71,9 +68,6 @@ def do_ptp_instance_add(cc, args): data = dict((k, v) for (k, v) in vars(args).items() if k in field_list and not (v is None)) - ihost = ihost_utils._find_ihost(cc, args.hostnameorid) - data.update({'host_uuid': ihost.uuid}) - ptp_instance = cc.ptp_instance.create(**data) uuid = getattr(ptp_instance, 'uuid', '') try: @@ -93,3 +87,43 @@ def do_ptp_instance_delete(cc, args): uuid = ptp_instance.uuid cc.ptp_instance.delete(uuid) print('Deleted PTP instance: %s' % uuid) + + +@utils.arg('hostnameorid', + metavar='', + help="Name or ID of host [REQUIRED]") +@utils.arg('nameoruuid', + metavar='', + help="Name or UUID of PTP instance [REQUIRED]") +def do_host_ptp_instance_add(cc, args): + """Associate PTP instance to host.""" + ihost = ihost_utils._find_ihost(cc, args.hostnameorid) + ptp_instance = ptp_instance_utils._find_ptp_instance(cc, args.nameoruuid) + try: + cc.ptp_instance.apply(ihost.uuid, ptp_instance.id) + except exc.HTTPNotFound: + raise exc.CommandError( + "Failed to apply PTP instance '%s' to host '%s'" + % (ihost.hostname, ptp_instance.name)) + print("Applying PTP instance '%s' to host '%s'" + % (ihost.hostname, ptp_instance.name)) + + +@utils.arg('hostnameorid', + metavar='', + help="Name or ID of host") +@utils.arg('nameoruuid', + metavar='', + help="Name or UUID of PTP instance") +def do_host_ptp_instance_delete(cc, args): + """Disassociate PTP instance on host.""" + ihost = ihost_utils._find_ihost(cc, args.hostnameorid) + ptp_instance = ptp_instance_utils._find_ptp_instance(cc, args.nameoruuid) + try: + cc.ptp_instance.remove(ihost.uuid, ptp_instance.id) + except exc.HTTPNotFound: + raise exc.CommandError( + "Failed to remove PTP instance '%s' from host '%s'" + % (ihost.hostname, ptp_instance.name)) + print("Removing PTP instance '%s' from host '%s'" + % (ihost.hostname, ptp_instance.name)) diff --git a/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_parameter.py b/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_parameter.py index f0c4327e9e..306ce613a9 100644 --- a/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_parameter.py +++ b/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_parameter.py @@ -11,7 +11,7 @@ from cgtsclient import exc from cgtsclient.v1 import options -CREATION_ATTRIBUTES = ['name', 'value', 'type', 'foreign_uuid'] +CREATION_ATTRIBUTES = ['name', 'value'] class PtpParameter(base.Resource): diff --git a/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_parameter_shell.py b/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_parameter_shell.py index d4a1a503a3..896fef6ecc 100644 --- a/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_parameter_shell.py +++ b/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_parameter_shell.py @@ -11,71 +11,44 @@ from cgtsclient import exc from cgtsclient.v1 import ptp_parameter as ptp_parameter_utils -def _owner_formatter(values): - result = [] - result.append(str(values['name'] + - " of type " + values['type'] + - " at " + values['hostname'])) - return result - - def _print_ptp_parameter_show(ptp_parameter_obj): - fields = ['uuid', 'name', 'value', 'type', - 'owner', 'foreign_uuid', 'created_at', 'updated_at'] - labels = ['uuid', 'name', 'value', 'type', - 'owned_by', 'owner_id', 'created_at', 'updated_at'] + fields = ['uuid', 'name', 'value', 'created_at', 'updated_at'] data = [(f, getattr(ptp_parameter_obj, f, '')) for f in fields] - utils.print_tuple_list(data, labels, - formatters={'owner': _owner_formatter}) + utils.print_tuple_list(data) + + +def _print_ptp_parameter_list(ptp_parameter_list): + fields = ['uuid', 'name', 'value'] + labels = ['uuid', 'name', 'value'] + utils.print_list(ptp_parameter_list, fields, labels) -@utils.arg('-t', '--type', - metavar='', - choices=['ptp-instance', 'ptp-interface'], - help='List PTP parameters for a specific owner type') -@utils.arg('-u', '--foreign_uuid', - metavar='', - help='List PTP parameters associated to specified owner') def do_ptp_parameter_list(cc, args): - """List all PTP parameters, in any host.""" - missing = ((args.type is None) and (args.foreign_uuid is not None)) or \ - ((args.type is not None) and (args.foreign_uuid is None)) - if missing: - raise exc.CommandError("Both 'type' and 'foreign_uuid' " - "must be provided") - ptp_parameters = None - if args.type == 'ptp-instance': - ptp_parameters = cc.ptp_parameter.list_by_ptp_instance( - args.foreign_uuid) - elif args.type == 'ptp-interface': - ptp_parameters = cc.ptp_parameter.list_by_interface( - args.foreign_uuid) - if ptp_parameters: - fields = ['uuid', 'name', 'value'] - labels = ['uuid', 'name', 'value'] - else: - ptp_parameters = cc.ptp_parameter.list() - for ptp_parameter in ptp_parameters: - owner_dict = getattr(ptp_parameter, 'owner', '') - setattr(ptp_parameter, 'owner_name', owner_dict['name']) - setattr(ptp_parameter, 'owner_host', owner_dict['hostname']) + """List all PTP parameters.""" + ptp_parameters = cc.ptp_parameter.list() + _print_ptp_parameter_list(ptp_parameters) - fields = ['uuid', - 'name', - 'value', - 'type', - 'owner_name', - 'owner_host', - 'foreign_uuid'] - labels = ['uuid', - 'name', - 'value', - 'owner_type', - 'owner_name', - 'owner_host', - 'owner_uuid'] - utils.print_list(ptp_parameters, fields, labels) +@utils.arg('ptp_instance_uuid', + metavar='', + help="UUID of PTP instance") +def do_ptp_parameter_list_instances(cc, args): + """List all PTP parameters that are associated to a specific PTP instance. + """ + ptp_parameters = cc.ptp_parameter.list_by_ptp_instance( + args.ptp_instance_uuid) + _print_ptp_parameter_list(ptp_parameters) + + +@utils.arg('ptp_interface_uuid', + metavar='', + help="UUID of PTP interface") +def do_ptp_parameter_list_interfaces(cc, args): + """List all PTP parameters that are associated to a specific PTP interface. + """ + ptp_parameters = cc.ptp_parameter.list_by_interface( + args.ptp_interface_uuid) + _print_ptp_parameter_list(ptp_parameters) @utils.arg('uuid', @@ -93,18 +66,10 @@ def do_ptp_parameter_show(cc, args): @utils.arg('value', metavar='', help="Value of PTP parameter [REQUIRED]") -@utils.arg('type', - metavar='', - choices=['ptp-instance', 'ptp-interface'], - help="Type of parameter owner ('ptp-instance' or 'ptp-interface') " - "[REQUIRED]") -@utils.arg('foreign_uuid', - metavar='', - help="UUID of parameter owner [REQUIRED]") def do_ptp_parameter_add(cc, args): """Add a PTP parameter.""" - field_list = ['name', 'value', 'type', 'foreign_uuid'] + field_list = ['name', 'value'] # Prune input fields down to required/expected values data = dict((k, v) for (k, v) in vars(args).items() diff --git a/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_paramownership.py b/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_paramownership.py new file mode 100644 index 0000000000..94cbc6f282 --- /dev/null +++ b/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_paramownership.py @@ -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 = ['parameter_uuid', 'owner_uuid'] + + +class PtpParameterOwnership(base.Resource): + def __repr__(self): + return "" % self._info + + +class PtpParameterOwnershipManager(base.Manager): + resource_class = PtpParameterOwnership + + def _path(self, ptp_paramownership_id=None): + return '/v1/ptp_parameter_ownerships/%s' % ptp_paramownership_id \ + if ptp_paramownership_id else '/v1/ptp_parameter_ownerships' + + def get(self, ptp_paramownership_id): + try: + return self._list(self._path(ptp_paramownership_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_paramownership_id): + return self._delete(self._path(ptp_paramownership_id)) diff --git a/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_paramownership_shell.py b/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_paramownership_shell.py new file mode 100644 index 0000000000..9006b6d429 --- /dev/null +++ b/sysinv/cgts-client/cgts-client/cgtsclient/v1/ptp_paramownership_shell.py @@ -0,0 +1,49 @@ +######################################################################## +# +# Copyright (c) 2021 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +######################################################################## + +from cgtsclient.common import utils +from cgtsclient import exc + + +@utils.arg('parameter_uuid', + metavar='', + help="UUID of PTP parameter [REQUIRED]") +@utils.arg('owner_uuid', + metavar='', + help="UUID of PTP instance or PTP interface [REQUIRED]") +def do_ptp_parameter_set_owner(cc, args): + """Set ownership of a PTP parameter.""" + + field_list = ['parameter_uuid', 'owner_uuid'] + + # Prune input fields down to required/expected values + data = dict((k, v) for (k, v) in vars(args).items() + if k in field_list and not (v is None)) + + ptp_paramownership = cc.ptp_paramownership.create(**data) + uuid = getattr(ptp_paramownership, 'uuid', '') + try: + ptp_paramownership = cc.ptp_paramownership.get(uuid) + except exc.HTTPNotFound: + raise exc.CommandError('PTP ownership just set not found: %s' % uuid) + fields = ['uuid', 'parameter_uuid', 'owner_uuid', 'created_at'] + labels = ('uuid', 'parameter', 'owner', 'created_at') + data = [(f, getattr(ptp_paramownership, f, '')) for f in fields] + utils.print_tuple_list(data, labels) + + +@utils.arg('parameter_uuid', + metavar='', + help="UUID of PTP parameter") +@utils.arg('owner_uuid', + metavar='', + help="UUID of PTP instance or PTP interface") +def do_ptp_parameter_unset_owner(cc, args): + """Remove ownership of a PTP parameter.""" + cc.ptp_paramownership.delete(args.parameter_uuid, args.owner_uuid) + print('Removed association to PTP parameter %s', args.parameter_uuid) diff --git a/sysinv/cgts-client/cgts-client/cgtsclient/v1/shell.py b/sysinv/cgts-client/cgts-client/cgtsclient/v1/shell.py index e4c29cf410..53f0b41a27 100644 --- a/sysinv/cgts-client/cgts-client/cgtsclient/v1/shell.py +++ b/sysinv/cgts-client/cgts-client/cgtsclient/v1/shell.py @@ -57,6 +57,7 @@ from cgtsclient.v1 import port_shell from cgtsclient.v1 import ptp_instance_shell from cgtsclient.v1 import ptp_interface_shell from cgtsclient.v1 import ptp_parameter_shell +from cgtsclient.v1 import ptp_paramownership_shell from cgtsclient.v1 import ptp_shell from cgtsclient.v1 import registry_image_shell from cgtsclient.v1 import remotelogging_shell @@ -81,6 +82,7 @@ COMMAND_MODULES = [ ptp_instance_shell, ptp_interface_shell, ptp_parameter_shell, + ptp_paramownership_shell, iextoam_shell, controller_fs_shell, storage_backend_shell, diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/__init__.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/__init__.py index 28d01742ce..805de7dc17 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/__init__.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/__init__.py @@ -68,6 +68,7 @@ from sysinv.api.controllers.v1 import ptp from sysinv.api.controllers.v1 import ptp_instance from sysinv.api.controllers.v1 import ptp_interface from sysinv.api.controllers.v1 import ptp_parameter +from sysinv.api.controllers.v1 import ptp_paramownership from sysinv.api.controllers.v1 import pv from sysinv.api.controllers.v1 import registry_image from sysinv.api.controllers.v1 import remotelogging @@ -158,6 +159,9 @@ class V1(base.APIBase): ptp_parameters = [link.Link] "Links to the ptp_parameters resource" + ptp_parameter_ownerships = [link.Link] + "Links to the ptp_parameter_ownerships resource" + iextoam = [link.Link] "Links to the iextoam resource" @@ -480,6 +484,14 @@ class V1(base.APIBase): 'ptp_parameters', '', bookmark=True)] + v1.ptp_parameter_ownerships = \ + [link.Link.make_link('self', pecan.request.host_url, + 'ptp_parameter_ownerships', ''), + link.Link.make_link('bookmark', + pecan.request.host_url, + 'ptp_parameter_ownerships', '', + bookmark=True)] + v1.iextoam = [link.Link.make_link('self', pecan.request.host_url, 'iextoam', ''), link.Link.make_link('bookmark', @@ -925,6 +937,8 @@ class Controller(rest.RestController): ptp_instances = ptp_instance.PtpInstanceController() ptp_interfaces = ptp_interface.PtpInterfaceController() ptp_parameters = ptp_parameter.PtpParameterController() + ptp_parameter_ownerships = \ + ptp_paramownership.PtpParameterOwnershipController() iextoam = network_oam.OAMNetworkController() controller_fs = controller_fs.ControllerFsController() storage_backend = storage_backend.StorageBackendController() diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ptp_instance.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ptp_instance.py index b3b3befd9b..58049e6eec 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ptp_instance.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ptp_instance.py @@ -43,20 +43,21 @@ class PtpInstance(base.APIBase): created_at = wtypes.datetime.datetime "Timestamp of creation of this PTP instance" - id = int - "Unique ID for this PTP instance" + # Inherited from PtpParameterOwner uuid = types.uuid "Unique UUID for this PTP instance" - host_id = int - "ID of host the PTP instance is associated to" + type = wtypes.Enum(str, + constants.PTP_PARAMETER_OWNER_INSTANCE, + constants.PTP_PARAMETER_OWNER_INTERFACE) + "Type of parameter owner (PTP_PARAMETER_OWNER_INSTANCE)" - host_uuid = types.uuid - "UUID of the host the PTP instance is associated to" + capabilities = {wtypes.text: utils.ValidTypes(wtypes.text, + six.integer_types)} + "Capabilities (metadata) of this PTP instance" - hostname = wtypes.text - "Name of the host the PTP instance is associated to" + # Fields of PtpInstance name = wtypes.text "Name given to the PTP instance" @@ -67,10 +68,6 @@ class PtpInstance(base.APIBase): constants.PTP_INSTANCE_TYPE_TS2PHC) "Type of service of the PTP instance" - capabilities = {wtypes.text: utils.ValidTypes(wtypes.text, - six.integer_types)} - "Capabilities (metadata) of this PTP instance" - def __init__(self, **kwargs): self.fields = list(objects.ptp_instance.fields.keys()) for k in self.fields: @@ -83,16 +80,12 @@ class PtpInstance(base.APIBase): ptp_instance = PtpInstance(**rpc_ptp_instance.as_dict()) if not expand: ptp_instance.unset_fields_except(['uuid', - 'host_uuid', - 'hostname', + 'type', + 'capabilities', 'name', 'service', - 'capabilities', 'created_at']) - # do not expose the id attribute - ptp_instance.host_id = wtypes.Unset - LOG.debug("PtpInstance.convert_with_links: converted %s" % ptp_instance.as_dict()) return ptp_instance @@ -130,12 +123,13 @@ class PtpInstanceController(rest.RestController): def __init__(self, from_ihosts=False): self._from_ihosts = from_ihosts - def _get_ptp_instance_collection( - self, host_uuid=None, marker=None, limit=None, sort_key=None, - sort_dir=None, expand=False, resource_url=None): - LOG.debug("PtpInstanceController._get_ptp_instance_collection: " - "from_ihosts %s host_uuid %s" % (self._from_ihosts, - host_uuid)) + @wsme_pecan.wsexpose(PtpInstanceCollection, types.uuid, types.uuid, + int, wtypes.text, wtypes.text) + def get_all(self, host_uuid=None, marker=None, limit=None, + sort_key='id', sort_dir='asc'): + """Retrieve a list of PTP instances.""" + LOG.debug("PtpInstanceController.get_all: from_ihosts %s host_uuid %s" + % (self._from_ihosts, host_uuid)) if self._from_ihosts and not host_uuid: raise exception.InvalidParameterValue(_( "Host id not specified.")) @@ -143,52 +137,39 @@ class PtpInstanceController(rest.RestController): limit = utils.validate_limit(limit) sort_dir = utils.validate_sort_dir(sort_dir) - LOG.debug("PtpInstanceController._get_ptp_instance_collection: " - "marker %s, limit %s, sort_dir %s" % (marker, limit, - sort_dir)) - marker_obj = None if marker: marker_obj = objects.ptp_instance.get_by_uuid( pecan.request.context, marker) - if self._from_ihosts or host_uuid: - ptp_instances = pecan.request.dbapi.ptp_instances_get_by_ihost( - host_uuid, limit, - marker_obj, - sort_key=sort_key, - sort_dir=sort_dir) - else: - ptp_instances = pecan.request.dbapi.ptp_instances_get_list( - limit, marker_obj, - sort_key=sort_key, - sort_dir=sort_dir) + ptp_instances = \ + pecan.request.dbapi.ptp_instances_get_list( + host_uuid, limit, marker_obj, sort_key, sort_dir) return PtpInstanceCollection.convert_with_links( - ptp_instances, limit, url=resource_url, expand=expand, - sort_key=sort_key, sort_dir=sort_dir) + ptp_instances, limit, sort_key=sort_key, sort_dir=sort_dir) - @wsme_pecan.wsexpose(PtpInstanceCollection, types.uuid, types.uuid, - int, wtypes.text, wtypes.text) - def get_all(self, uuid=None, marker=None, limit=None, - sort_key='id', sort_dir='asc'): - """Retrieve a list of PTP instances.""" - LOG.debug("PtpInstanceController.get_all: uuid=%s" % uuid) - return self._get_ptp_instance_collection(uuid, marker, limit, - sort_key=sort_key, - sort_dir=sort_dir) - - @wsme_pecan.wsexpose(PtpInstance, types.uuid) - def get_one(self, ptp_instance_uuid): + @wsme_pecan.wsexpose(PtpInstance, types.uuid, types.uuid) + def get_one(self, ptp_instance_uuid=None, host_uuid=None): """Retrieve a single PTP instance.""" - LOG.debug("PtpInstanceController.get_one: uuid=%s" % ptp_instance_uuid) + LOG.debug("PtpInstanceController.get_one: uuid=%s, host=%s" + % (ptp_instance_uuid, host_uuid)) + if self._from_ihosts and not host_uuid: + raise exception.InvalidParameterValue(_( + "Host id not specified.")) try: - ptp_instance = objects.ptp_instance.get_by_uuid( - pecan.request.context, - ptp_instance_uuid) + if host_uuid: + uuid = host_uuid + ptp_instance = \ + pecan.request.dbapi.ptp_instances_get_one(host=host_uuid) + else: + uuid = ptp_instance_uuid + ptp_instance = objects.ptp_instance.get_by_uuid( + pecan.request.context, + ptp_instance_uuid) except exception.InvalidParameterValue: raise wsme.exc.ClientSideError( - _("No PTP instance found for %s" % ptp_instance_uuid)) + _("No PTP instance found for %s" % uuid)) return PtpInstance.convert_with_links(ptp_instance) @@ -198,23 +179,6 @@ class PtpInstanceController(rest.RestController): """Create a new PTP instance.""" ptp_instance_dict = ptp_instance.as_dict() LOG.debug("PtpInstanceController.post: %s" % ptp_instance_dict) - - # Get rid of hostname (if any) to create the PTP instance - try: - ptp_instance_dict.pop('hostname') - except KeyError: - LOG.debug("PtpInstanceController.post: no hostname in %s" % - ptp_instance_dict) - - # Replace host UUID by host ID - host_uuid = ptp_instance_dict.pop('host_uuid') - try: - ihost_obj = pecan.request.dbapi.ihost_get(host_uuid) - except exception.HostNotFound: - msg = _("Host with uuid '%s' does not exist. " % host_uuid) - raise wsme.exc.ClientSideError(msg) - - ptp_instance_dict['host_id'] = ihost_obj['id'] return PtpInstance.convert_with_links( pecan.request.dbapi.ptp_instance_create(ptp_instance_dict)) @@ -228,23 +192,21 @@ class PtpInstanceController(rest.RestController): # Only allow delete if there are no associated interfaces and # parameters - parameters = pecan.request.dbapi.ptp_parameters_get_by_owner( + parameters = pecan.request.dbapi.ptp_parameters_get_by_owner_uuid( ptp_instance_uuid) if parameters: - names = [str(p['name']) for p in parameters] raise wsme.exc.ClientSideError( - "PTP instance %s is still associated with PTP parameter(s): %s" - % (ptp_instance_uuid, names)) + "PTP instance %s is still associated with PTP parameter(s)" + % ptp_instance_uuid) ptp_instance_obj = objects.ptp_instance.get_by_uuid( pecan.request.context, ptp_instance_uuid) interfaces = pecan.request.dbapi.ptp_interfaces_get_by_instance( ptp_instance_obj.id) if interfaces: - names = [str(i['ifname']) for i in interfaces] raise wsme.exc.ClientSideError( - "PTP instance %s is still associated with PTP interface(s): %s" - % (ptp_instance_uuid, names)) + "PTP instance %s is still associated with PTP interface(s)" + % ptp_instance_uuid) LOG.debug("PtpInstanceController.delete: all clear for %s" % ptp_instance_uuid) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ptp_interface.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ptp_interface.py index 7cef666385..dfee029671 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ptp_interface.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ptp_interface.py @@ -19,6 +19,7 @@ from sysinv.api.controllers.v1 import collection from sysinv.api.controllers.v1 import link from sysinv.api.controllers.v1 import types from sysinv.api.controllers.v1 import utils +from sysinv.common import constants from sysinv.common import exception from sysinv import objects @@ -40,11 +41,21 @@ class PtpInterface(base.APIBase): interface. """ + # Inherited from PtpParameterOwner + uuid = types.uuid "Unique UUID for this PTP interface" - interface_uuid = types.uuid - "ID for the interface associated with the PTP interface" + type = wtypes.Enum(str, + constants.PTP_PARAMETER_OWNER_INSTANCE, + constants.PTP_PARAMETER_OWNER_INTERFACE) + "Type of parameter owner (PTP_PARAMETER_OWNER_INTERFACE)" + + capabilities = {wtypes.text: utils.ValidTypes(wtypes.text, + six.integer_types)} + "Capabilities (metadata) of this PTP interface" + + # Fields of PtpInterface ptp_instance_id = int "ID for the PTP instance this interface is associated with" @@ -55,19 +66,9 @@ class PtpInterface(base.APIBase): ptp_instance_uuid = types.uuid "The UUID of the host this PTP interface belongs to" - ifname = wtypes.text - "The name of the underlying interface" - - forihostid = int - "The foreign key host id" - ptp_instance_name = wtypes.text "The name of the associated PTP instance" - capabilities = {wtypes.text: utils.ValidTypes(wtypes.text, - six.integer_types)} - "Capabilities (metadata) of this PTP interface" - created_at = wtypes.datetime.datetime def __init__(self, **kwargs): @@ -83,13 +84,12 @@ class PtpInterface(base.APIBase): ptp_interface = PtpInterface(**rpc_ptp_interface.as_dict()) if not expand: ptp_interface.unset_fields_except(['uuid', - 'ptp_instance_id', - 'forihostid', - 'ptp_instance_name', - 'ifname', - 'interface_uuid', - 'capabilities', - 'created_at']) + 'type', + 'capabilities', + 'ptp_instance_id', + 'ptp_instance_uuid', + 'ptp_instance_name', + 'created_at']) return ptp_interface @@ -105,10 +105,10 @@ class PtpInterfaceCollection(collection.Collection): @classmethod def convert_with_links(cls, rpc_ptp_interfaces, limit, url=None, - expand=False, **kwargs): + expand=False, **kwargs): collection = PtpInterfaceCollection() collection.ptp_interfaces = [PtpInterface.convert_with_links(p, expand) - for p in rpc_ptp_interfaces] + for p in rpc_ptp_interfaces] collection.next = collection.get_next(limit, url=url, **kwargs) return collection @@ -123,56 +123,42 @@ class PtpInterfaceController(rest.RestController): def __init__(self, from_ihosts=False): self._from_ihosts = from_ihosts - def _get_ptp_interfaces_collection(self, host_uuid=None, marker=None, - limit=None, sort_key=None, - sort_dir=None, expand=False, - resource_url=None, interface_uuid=None): - + @wsme_pecan.wsexpose(PtpInterfaceCollection, types.uuid, int, wtypes.text, + wtypes.text) + def get_all(self, marker=None, limit=None, sort_key='id', sort_dir='asc'): + """Retrieve a list of PTP interfaces.""" limit = utils.validate_limit(limit) sort_dir = utils.validate_sort_dir(sort_dir) - marker_obj = None + """ TODO + marker_obj = None if marker: - marker_obj = objects.ptp_interface.get_by_uuid(pecan.request.context, - marker) + marker_obj = objects.ptp_interface.get_by_uuid( + pecan.request.context, marker) + if self._from_ihosts or host_uuid is not None: if interface_uuid is not None: - ptp_interfaces = pecan.request.dbapi.ptp_interfaces_get_by_interface( - interface_uuid, limit, - marker_obj, - sort_key, - sort_dir) + ptp_interfaces = \ + pecan.request.dbapi.ptp_interfaces_get_by_interface( + interface_uuid, limit, marker_obj, sort_key, sort_dir) else: - ptp_interfaces = pecan.request.dbapi.ptp_interfaces_get_by_host( - host_uuid, limit, - marker_obj, - sort_key, - sort_dir) + ptp_interfaces = \ + pecan.request.dbapi.ptp_interfaces_get_by_host( + host_uuid, limit, marker_obj, sort_key, sort_dir) else: ptp_interfaces = pecan.request.dbapi.ptp_interfaces_get_list() + """ + ptp_interfaces = pecan.request.dbapi.ptp_interfaces_get_list() return PtpInterfaceCollection.convert_with_links(ptp_interfaces, - limit, - url=resource_url, - expand=expand, - sort_key=sort_key, - sort_dir=sort_dir) - - @wsme_pecan.wsexpose(PtpInterfaceCollection, types.uuid, types.uuid, int, - wtypes.text, wtypes.text, types.uuid) - def get_all(self, host_uuid, marker=None, limit=None, - sort_key='id', sort_dir='asc', interface_uuid=None): - """Retrieve a list of PTP interfaces.""" - return self._get_ptp_interfaces_collection(host_uuid, marker, limit, - sort_key=sort_key, - sort_dir=sort_dir, - expand=False, - interface_uuid=interface_uuid) + limit, + sort_key=sort_key, + sort_dir=sort_dir) @wsme_pecan.wsexpose(PtpInterface, types.uuid) def get_one(self, ptp_interface_uuid): """Retrieve information about the given PTP interface""" - rpc_ptp_interface = objects.ptp_interface.get_by_uuid(pecan.request.context, - ptp_interface_uuid) + rpc_ptp_interface = objects.ptp_interface.get_by_uuid( + pecan.request.context, ptp_interface_uuid) return PtpInterface.convert_with_links(rpc_ptp_interface) @wsme_pecan.wsexpose(PtpInterface, body=PtpInterface) @@ -187,18 +173,16 @@ class PtpInterfaceController(rest.RestController): instance_uuid = ptp_interface_dict.pop('ptp_instance_uuid', None) instance = objects.ptp_instance.get_by_uuid(pecan.request.context, instance_uuid) - - interface_uuid = ptp_interface_dict.pop('interface_uuid', None) - interface = pecan.request.dbapi.iinterface_get(interface_uuid) - - ptp_interface_dict['interface_id'] = interface['id'] ptp_interface_dict['ptp_instance_id'] = instance['id'] - check = pecan.request.dbapi.ptp_interfaces_get_by_instance_and_interface( - ptp_interface_dict["ptp_instance_id"], - ptp_interface_dict["interface_id"]) + """ TODO + check = \ + pecan.request.dbapi.ptp_interfaces_get_by_instance_and_interface( + ptp_interface_dict["ptp_instance_id"], + ptp_interface_dict["interface_id"]) if len(check) != 0: raise exception.PtpInterfaceAlreadyExists() + """ result = pecan.request.dbapi.ptp_interface_create(ptp_interface_dict) return PtpInterface.convert_with_links(result) @@ -213,7 +197,7 @@ class PtpInterfaceController(rest.RestController): raise # Only allow delete if there are no associated parameters - parameters = pecan.request.dbapi.ptp_parameters_get_by_owner( + parameters = pecan.request.dbapi.ptp_parameters_get_by_owner_uuid( ptp_interface_uuid) if parameters: names = [str(p['name']) for p in parameters] diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ptp_parameter.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ptp_parameter.py index 488e795ceb..c103e848d4 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ptp_parameter.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ptp_parameter.py @@ -17,7 +17,6 @@ from sysinv.api.controllers.v1 import base from sysinv.api.controllers.v1 import collection from sysinv.api.controllers.v1 import types from sysinv.api.controllers.v1 import utils -from sysinv.common import constants from sysinv.common import exception from sysinv.common import utils as cutils from sysinv import objects @@ -57,16 +56,8 @@ class PtpParameter(base.APIBase): value = wtypes.text "Value of PTP parameter" - type = wtypes.Enum(str, - constants.PTP_PARAMETER_OWNER_INSTANCE, - constants.PTP_PARAMETER_OWNER_INTERFACE) - "Type of owner of this PTP parameter" - - foreign_uuid = types.uuid - "UUID of the owner of this PTP parameter" - - owner = types.MultiType([dict]) - "Owner information: name, type, hostname" + owners = types.MultiType([list]) + "Owners information: name, type, etc." def __init__(self, **kwargs): self.fields = list(objects.ptp_parameter.fields.keys()) @@ -82,9 +73,7 @@ class PtpParameter(base.APIBase): ptp_parameter.unset_fields_except(['uuid', 'name', 'value', - 'type', - 'foreign_uuid', - 'owner', + 'owners', 'created_at', 'updated_at']) @@ -121,11 +110,12 @@ class PtpParameterController(rest.RestController): def __init__(self, parent=None): self._parent = parent - def _get_ptp_parameter_collection( - self, parent_uuid=None, type=None, marker=None, limit=None, - sort_key=None, sort_dir=None, expand=False, resource_url=None): - LOG.debug("PtpParameterController._get_ptp_parameter_collection: " - "parent %s uuid %s type %s" % + @wsme_pecan.wsexpose(PtpParameterCollection, types.uuid, wtypes.text, + types.uuid, int, wtypes.text, wtypes.text) + def get_all(self, parent_uuid=None, type=None, marker=None, limit=None, + sort_key='id', sort_dir='asc'): + """Retrieve a list of PTP parameters.""" + LOG.debug("PtpParameterController.get_all: parent %s uuid %s type %s" % (self._parent, parent_uuid, type)) if self._parent and not parent_uuid: raise exception.InvalidParameterValue(_( @@ -134,42 +124,27 @@ class PtpParameterController(rest.RestController): limit = utils.validate_limit(limit) sort_dir = utils.validate_sort_dir(sort_dir) - LOG.debug("PtpParameterController._get_ptp_parameter_collection: " - "marker %s, limit %s, sort_dir %s" % (marker, limit, - sort_dir)) - marker_obj = None if marker: marker_obj = objects.ptp_parameter.get_by_uuid( pecan.request.context, marker) if parent_uuid: - ptp_parameters = pecan.request.dbapi.ptp_parameters_get_by_owner( - parent_uuid, limit, marker_obj, sort_key=sort_key, - sort_dir=sort_dir) + ptp_parameters = \ + pecan.request.dbapi.ptp_parameters_get_by_owner_uuid( + parent_uuid, limit, marker_obj, sort_key=sort_key, + sort_dir=sort_dir) elif type is not None: - ptp_parameters = pecan.request.dbapi.ptp_parameters_get_by_type( - type, limit, marker_obj, sort_key=sort_key, sort_dir=sort_dir) + ptp_parameters = \ + pecan.request.dbapi.ptp_parameters_get_by_owner_type( + type, limit, marker_obj, sort_key=sort_key, + sort_dir=sort_dir) else: ptp_parameters = pecan.request.dbapi.ptp_parameters_get_list( limit, marker_obj, sort_key=sort_key, sort_dir=sort_dir) return PtpParameterCollection.convert_with_links( - ptp_parameters, limit, url=resource_url, expand=expand, - sort_key=sort_key, sort_dir=sort_dir) - - @wsme_pecan.wsexpose(PtpParameterCollection, types.uuid, types.uuid, - int, wtypes.text, wtypes.text) - def get_all(self, uuid=None, marker=None, limit=None, - sort_key='id', sort_dir='asc'): - """Retrieve a list of PTP parameters.""" - type = None - LOG.debug("PtpParameterController.get_all: uuid=%s, type=%s" % - (uuid, type)) - return self._get_ptp_parameter_collection(uuid, type, - marker, limit, - sort_key=sort_key, - sort_dir=sort_dir) + ptp_parameters, limit, sort_key=sort_key, sort_dir=sort_dir) @wsme_pecan.wsexpose(PtpParameter, types.uuid) def get_one(self, ptp_parameter_uuid): @@ -186,24 +161,6 @@ class PtpParameterController(rest.RestController): return PtpParameter.convert_with_links(ptp_parameter) - def _check_foreign_exists(self, type, uuid): - LOG.debug("PtpParameterController._check_foreign_exists: " - "type %s uuid %s" % (type, uuid)) - try: - if type == constants.PTP_PARAMETER_OWNER_INSTANCE: - try: - pecan.request.dbapi.ptp_instance_get(uuid) - except exception.PtpInstanceNotFound: - raise exception.NotFound - elif type == constants.PTP_PARAMETER_OWNER_INTERFACE: - try: - pecan.request.dbapi.ptp_interface_get(uuid) - except exception.PtpInterfaceNotFound: - raise exception.NotFound - except exception.NotFound: - raise wsme.exc.ClientSideError( - _("No foreign object found with id %s" % uuid)) - @cutils.synchronized(LOCK_NAME) @wsme_pecan.wsexpose(PtpParameter, body=PtpParameter) def post(self, ptp_parameter): @@ -211,12 +168,9 @@ class PtpParameterController(rest.RestController): ptp_parameter_dict = ptp_parameter.as_dict() LOG.debug("PtpParameterController.post: %s" % ptp_parameter_dict) - self._check_foreign_exists(ptp_parameter_dict['type'], - ptp_parameter_dict['foreign_uuid']) - # Get rid of owner details to create the PTP parameter try: - ptp_parameter_dict.pop('owner') + ptp_parameter_dict.pop('owners') except KeyError: LOG.debug("PtpParameterController.post: no owner data in %s" % ptp_parameter_dict) @@ -259,4 +213,14 @@ class PtpParameterController(rest.RestController): if self._parent: raise exception.OperationNotPermitted + # Only allow delete if there are no associated PTP instances and + # interfaces + owners = pecan.request.dbapi.ptp_paramownerships_get_by_parameter( + ptp_parameter_uuid) + if owners: + uuids = [str(o['owner_uuid']) for o in owners] + raise wsme.exc.ClientSideError( + "PTP parameter %s is still associated with %s" + % (ptp_parameter_uuid, uuids)) + pecan.request.dbapi.ptp_parameter_destroy(ptp_parameter_uuid) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ptp_paramownership.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ptp_paramownership.py new file mode 100644 index 0000000000..a12731915e --- /dev/null +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ptp_paramownership.py @@ -0,0 +1,158 @@ +# +# 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 PtpParameterOwnershipPatchType(types.JsonPatchType): + @staticmethod + def mandatory_attrs(): + return [] + + +class PtpParameterOwnership(base.APIBase): + """API representation of a PTP parameter ownership. + + This class enforces type checking and value constraints, and converts + between the internal object model and the API representation of + a PTP parameter ownership. + """ + + created_at = wtypes.datetime.datetime + "Timestamp of creation of this PTP parameter ownership" + + id = int + "Unique ID for this PTP parameter ownership" + + uuid = types.uuid + "Unique UUID for this PTP parameter ownership" + + parameter_uuid = types.uuid + "UUID of the PTP parameter (name/value)" + + owner_uuid = types.uuid + "UUID of the entity associated to PTP parameter (instance or interface)" + + def __init__(self, **kwargs): + self.fields = list(objects.ptp_paramownership.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_paramownership, expand=True): + ptp_parameter_ownership = PtpParameterOwnership( + **rpc_ptp_paramownership.as_dict()) + if not expand: + ptp_parameter_ownership.unset_fields_except( + ['uuid', 'parameter_uuid', 'owner_uuid', 'created_at']) + + LOG.debug("PtpParameterOwnership.convert_with_links: converted %s" % + ptp_parameter_ownership.as_dict()) + return ptp_parameter_ownership + + +class PtpParameterOwnershipCollection(collection.Collection): + """API representation of a collection of PTP owners.""" + + ptp_parameter_ownerships = [PtpParameterOwnership] + "A list containing PTP ownership objects" + + def __init__(self, **kwargs): + self._type = 'ptp_parameter_ownerships' + + @classmethod + def convert_with_links(cls, rpc_ptp_paramownerships, limit, url=None, + expand=False, **kwargs): + collection = PtpParameterOwnershipCollection() + collection.ptp_paramownerships = \ + [PtpParameterOwnership.convert_with_links(p, expand) + for p in rpc_ptp_paramownerships] + collection.next = collection.get_next(limit, url=url, **kwargs) + return collection + + +LOCK_NAME = 'PtpParameterOwnershipController' + + +class PtpParameterOwnershipController(rest.RestController): + """REST controller for PTP parameter ownership.""" + + @wsme_pecan.wsexpose(PtpParameterOwnership, types.uuid) + def get_one(self, ptp_paramownership_uuid): + """Retrieve a single PTP parameter.""" + LOG.debug("PtpParameterOwnershipController.get_one: uuid=%s" % + ptp_paramownership_uuid) + try: + ptp_paramownership = objects.ptp_paramownership.get_by_uuid( + pecan.request.context, + ptp_paramownership_uuid) + except exception.InvalidParameterValue: + raise wsme.exc.ClientSideError( + _("No PTP parameter ownership found for %s" + % ptp_paramownership_uuid)) + + return PtpParameterOwnership.convert_with_links(ptp_paramownership) + + def _check_parameter_exists(self, uuid): + LOG.debug("PtpParameterOwnershipController._check_parameter_exists: " + "uuid %s" % uuid) + try: + pecan.request.dbapi.ptp_parameter_get(uuid) + except exception.PtpParameterNotFound: + raise wsme.exc.ClientSideError( + _("No PTP parameter object found with id %s" % uuid)) + + def _check_owner_exists(self, uuid): + LOG.debug("PtpParameterOwnershipController._check_owner_exists: " + "uuid %s" % uuid) + try: + pecan.request.dbapi.ptp_paramowner_get(uuid) + except exception.NotFound: + raise wsme.exc.ClientSideError( + _("No PTP parameter owner found with id %s" % uuid)) + + @cutils.synchronized(LOCK_NAME) + @wsme_pecan.wsexpose(PtpParameterOwnership, body=PtpParameterOwnership) + def post(self, ptp_paramownership): + """Create a new PTP parameter ownership.""" + ptp_paramownership_dict = ptp_paramownership.as_dict() + LOG.debug("PtpParameterOwnershipController.post: %s" + % ptp_paramownership_dict) + + self._check_parameter_exists(ptp_paramownership_dict['parameter_uuid']) + self._check_owner_exists(ptp_paramownership_dict['owner_uuid']) + + result = pecan.request.dbapi.ptp_parameter_set_owner( + ptp_paramownership_dict) + return PtpParameterOwnership.convert_with_links(result) + + @cutils.synchronized(LOCK_NAME) + @wsme_pecan.wsexpose(None, types.uuid, status_code=204) + def delete(self, ptp_paramownership_uuid): + """Delete a PTP parameter ownership.""" + LOG.debug("PtpParameterController.delete: %s" + % ptp_paramownership_uuid) + ptp_paramownership = objects.ptp_paramownership.get_by_uuid( + pecan.request.context, ptp_paramownership_uuid) + pecan.request.dbapi.ptp_parameter_unset_owner( + ptp_paramownership.as_dict()) diff --git a/sysinv/sysinv/sysinv/sysinv/common/exception.py b/sysinv/sysinv/sysinv/sysinv/common/exception.py index de3bea6f5a..189aa87947 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/exception.py +++ b/sysinv/sysinv/sysinv/sysinv/common/exception.py @@ -461,7 +461,12 @@ class PtpInterfaceAlreadyExists(Conflict): class PtpParameterAlreadyExists(Conflict): - message = _("A PTP parameter with UUID %(uuid)s already exists.") + message = _("A PTP parameter with name '%(name)s' and value " + "'%(value)s' already exists.") + + +class PtpParameterOwnershipAlreadyExists(Conflict): + message = _("UUID %(param)s is already a PTP parameter of UUID %(owner)s.") class PMAlreadyExists(Conflict): @@ -604,6 +609,14 @@ class PtpParameterNotFound(NotFound): message = _("No PTP parameter with id %(uuid)s found.") +class PtpParameterOwnerNotFound(NotFound): + message = _("No PTP parameter owner with id %(uuid)s found.") + + +class PtpParameterOwnershipNotFound(NotFound): + message = _("No PTP parameter ownership with id %(uuid)s found.") + + class DiskNotFound(NotFound): message = _("No disk with id %(disk_id)s") diff --git a/sysinv/sysinv/sysinv/sysinv/db/api.py b/sysinv/sysinv/sysinv/sysinv/db/api.py index 49cfe5dce4..848765d734 100644 --- a/sysinv/sysinv/sysinv/sysinv/db/api.py +++ b/sysinv/sysinv/sysinv/sysinv/db/api.py @@ -1914,7 +1914,6 @@ class Connection(object): { 'name': 'default', 'service': 'ptp4l', - 'host': 'controller-0', 'capabilities': { ... } } :returns: A PTP service instance. @@ -1929,19 +1928,21 @@ class Connection(object): """ @abc.abstractmethod - def ptp_instance_get_one(self, name=None, service=None): + def ptp_instance_get_one(self, name=None, host=None, service=None): """Returns exactly one PTP service instance. :param name: name of PTP instance given by user. + :param host: id or uuid of host. :param service: service of PTP instance. :returns: A PTP service instance. """ @abc.abstractmethod - def ptp_instances_get_list(self, limit=None, marker=None, sort_key=None, - sort_dir=None): + def ptp_instances_get_list(self, host=None, limit=None, marker=None, + sort_key=None, sort_dir=None): """Returns a list of PTP service instances. + :param host: id or uuid of host. :param limit: Maximum number of PTP instances to return. :param marker: The last item of the previous page; we return the next result set. @@ -1951,38 +1952,6 @@ class Connection(object): :returns: A list of PTP instances. """ - @abc.abstractmethod - def ptp_instances_get_by_ihost(self, ihost_id, limit=None, marker=None, - sort_key=None, sort_dir=None): - """Returns a list of the PTP instances for a given ihost. - - :param ihost_id: The id or uuid of an ihost. - :param limit: Maximum number of PTP instances 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 PTP instances. - """ - - @abc.abstractmethod - def ptp_instance_update(self, ptp_instance_id, values): - """Updates properties of a PTP instance. - - :param ptp_instance_id: The id or uuid of a PTP instance. - :param values: May be a partial list, eg. when setting the - properties for capabilities. For example: - { - 'capabilities': - { - 'my-field-1': val1, - 'my-field-2': val2 - } - } - :returns: A PTP service instance. - """ - @abc.abstractmethod def ptp_instance_destroy(self, ptp_instance_id): """Destroys a PTP service instance. @@ -2041,39 +2010,6 @@ class Connection(object): :returns: A list of PTP interface associations. """ - @abc.abstractmethod - def ptp_interfaces_get_by_host(self, host_uuid, limit=None, - marker=None, sort_key=None, - sort_dir=None): - - """Returns a list of the PTP associations for a given host. - - :param host_uuid: The id or uuid of a host. - :param limit: Maximum number of PTP associations 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 PTP associations (instances) for the host - """ - - @abc.abstractmethod - def ptp_interfaces_get_by_interface(self, interface_id, limit=None, - marker=None, sort_key=None, - sort_dir=None): - """Returns a list of the PTP associations for a given interface. - - :param interface_id: The id or uuid of an interface. - :param limit: Maximum number of PTP associations 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 PTP associations (instances) for the interface. - """ - @abc.abstractmethod def ptp_interfaces_get_by_instance(self, ptp_instance_id, limit=None, marker=None, sort_key=None, @@ -2110,21 +2046,6 @@ class Connection(object): interface. """ - def ptp_interface_update(self, ptp_interface_id, values): - """Updates capabilities of a PTP interface. - - :param ptp_interface_id: The id or uuid of a PTP interface. - :param values: May be a partial list. For example: - { - 'capabilities': - { - 'my-field-1': val1, - 'my-field-2': val2 - } - } - :returns: A PTP interface association. - """ - @abc.abstractmethod def ptp_interface_destroy(self, ptp_interface_id): """Destroys a PTP interface association. @@ -2134,15 +2055,14 @@ class Connection(object): @abc.abstractmethod def ptp_parameter_create(self, values): - """Creates a new PTP parameter. + """Creates a new PTP parameter to be applied later either to some + instance(s) or PTP interface(s). :param values: A dict containing several items used to identify and track the PTP parameter. { 'name': 'domain', - 'value': '24', - 'type': 'ptp-instance', - 'foreign_uuid': 'c2abca03-2f33-413e-b60d-85133a4a37b6' + 'value': '24' } :returns: A PTP parameter. """ @@ -2178,8 +2098,8 @@ class Connection(object): """ @abc.abstractmethod - def ptp_parameters_get_by_type(self, type, limit=None, marker=None, - sort_key=None, sort_dir=None): + def ptp_parameters_get_by_owner_type(self, type, limit=None, marker=None, + sort_key=None, sort_dir=None): """Returns a list of all PTP parameters for a given owner type. :param type: Type of the parameter owner (either 'ptp-instance' or @@ -2194,8 +2114,8 @@ class Connection(object): """ @abc.abstractmethod - def ptp_parameters_get_by_owner(self, uuid, limit=None, marker=None, - sort_key=None, sort_dir=None): + def ptp_parameters_get_by_owner_uuid(self, uuid, limit=None, marker=None, + sort_key=None, sort_dir=None): """Returns a list of the PTP parameters for a given owner identified by its UUID. @@ -2221,6 +2141,50 @@ class Connection(object): :returns: A PTP parameter. """ + @abc.abstractmethod + def ptp_parameter_set_owner(self, values): + """Set the PTP parameter to either a PTP instance or PTP interface + by associating their UUIDs to each other. + + :param values: A dict containing the IDs used to associate + the PTP parameter to the owner entity. + { + 'parameter_uuid': '86089c13-c687-4025-991b-45525d031b67', + 'owner_uuid': 'ccc95d7c-abea-47ef-955b-026d68fd2b02' + } + :returns: A PTP parameter association. + """ + + @abc.abstractmethod + def ptp_parameter_unset_owner(self, values): + """Remove the association between a PTP parameter and either a PTP + instance or interface. + + :param values: A dict containing the IDs used to associate + the PTP parameter to the owner entity. + { + 'parameter_uuid': '86089c13-c687-4025-991b-45525d031b67', + 'owner_uuid': 'ccc95d7c-abea-47ef-955b-026d68fd2b02' + } + """ + + @abc.abstractmethod + def ptp_parameter_get_owners_list(self, ptp_parameter_id, limit=None, + marker=None, sort_key=None, + sort_dir=None): + """Returns a list of all PTP instances and/or PTP interfaces that refer + to the PTP parameter. + + :param ptp_parameter_id: The id or uuid of a PTP parameter. + :param limit: Maximum number of owners 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 owners for the given PTP parameter. + """ + @abc.abstractmethod def ptp_parameter_destroy(self, ptp_parameter_id): """Destroys a PTP parameter. @@ -2228,6 +2192,55 @@ class Connection(object): :param ptp_parameter_id: The id or uuid of a PTP parameter. """ + @abc.abstractmethod + def ptp_paramowner_get(self, ptp_paramowner_id): + """Returns a PTP parameter owner (can be either a PTP instance or a + PTP interface). + + :param ptp_paramowner_id: The id or uuid of a PTP owner. + :returns: A PTP parameter owner. + """ + + @abc.abstractmethod + def ptp_paramownership_get(self, ptp_paramownership_id): + """Returns a PTP parameter ownership. + + :param ptp_paramownership_id: The id or uuid of a PTP parameter + ownership. + :returns: A PTP parameter ownership. + """ + + @abc.abstractmethod + def ptp_paramownerships_get_by_parameter(self, uuid, limit=None, + marker=None, sort_key=None, + sort_dir=None): + """Returns a list of PTP ownerships for a given parameter. + + :param uuid: UUID of the PTP parameter owner. + :param limit: Maximum number of PTP ownerships 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 PTP parameter ownerships. + """ + + @abc.abstractmethod + def ptp_paramownerships_get_by_owner(self, uuid, limit=None, marker=None, + sort_key=None, sort_dir=None): + """Returns a list of PTP ownerships for a given owner. + + :param uuid: UUID of the PTP parameter owner (instance or interface). + :param limit: Maximum number of PTP ownerships 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 PTP parameter ownerships. + """ + @abc.abstractmethod def iextoam_get_one(self): """Return exactly one iextoam. diff --git a/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/api.py b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/api.py index 5dd3a6b1c2..63de5b2215 100644 --- a/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/api.py +++ b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/api.py @@ -1178,43 +1178,6 @@ def add_deviceimage_filter(query, value): return add_identity_filter(query, value, use_name=True) -def add_ptp_instance_filter_by_host(query, hostid): - """Adds a ptp-instance-specific ihost filter to a query. - - Filters results by host id if supplied value is an integer, - otherwise attempts to filter results by host uuid. - - :param query: Initial query to add filter to. - :param hostid: host id or uuid to filter results by. - :return: Modified query. - """ - if utils.is_int_like(hostid): - return query.filter_by(host_id=hostid) - elif utils.is_uuid_like(hostid): - query = query.join(models.ihost) - return query.filter(models.ihost.uuid == hostid) - - LOG.debug("ptp_instance_filter_by_host: " - "No match for supplied filter id (%s)" % str(hostid)) - - -def add_ptp_parameter_filter_by_owner(query, type, uuid): - if type == constants.PTP_PARAMETER_OWNER_INSTANCE: - query = query.join(models.PtpInstances, - models.PtpInstances.uuid == uuid) - elif type == constants.PTP_PARAMETER_OWNER_INTERFACE: - query = (query.join(models.PtpInterfaces, - models.PtpInterfaces.uuid == uuid) - .join(models.Interfaces, models.Interfaces.id == - models.PtpInterfaces.interface_id)) - else: - LOG.error("ptp_parameter_filter_by_owner: " - "Invalid owner type (%s)" % type) - raise exception.Invalid() - - return query - - class Connection(api.Connection): """SqlAlchemy connection.""" @@ -3791,10 +3754,23 @@ class Connection(api.Connection): return self._ptp_instance_get(ptp_instance_id) @objects.objectify(objects.ptp_instance) - def ptp_instance_get_one(self, name=None, service=None): + def ptp_instance_get_one(self, name=None, host=None, service=None): query = model_query(models.PtpInstances) if name is not None: query = query.filter_by(name=name) + elif host is not None: + if utils.is_int_like(host): + ihost = self.ihost_get(int(host)) + elif utils.is_uuid_like(host): + 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 None + query = add_identity_filter(query, ptp_instance_id) elif service is not None: query = query.filter_by(service=service) try: @@ -3803,33 +3779,29 @@ class Connection(api.Connection): raise exception.NotFound() @objects.objectify(objects.ptp_instance) - def ptp_instances_get_list(self, limit=None, marker=None, + def ptp_instances_get_list(self, host=None, limit=None, marker=None, sort_key=None, sort_dir=None): query = model_query(models.PtpInstances) - return _paginate_query(models.PtpInstances, limit, marker, - sort_key, sort_dir, query) - - @objects.objectify(objects.ptp_instance) - def ptp_instances_get_by_ihost(self, ihost_id, limit=None, marker=None, - sort_key=None, sort_dir=None): - query = model_query(models.PtpInstances) - query = add_ptp_instance_filter_by_host(query, ihost_id) - return _paginate_query(models.PtpInstances, limit, marker, - sort_key, sort_dir, query) - - @objects.objectify(objects.ptp_instance) - def ptp_instance_update(self, ptp_instance_id, values): - with _session_for_write() as session: - query = model_query(models.PtpInstances, session=session) + if host is not None: + if utils.is_int_like(host): + ihost = self.ihost_get(int(host)) + elif utils.is_uuid_like(host): + 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) - count = query.update(values, synchronize_session='fetch') - if count != 1: - raise exception.PtpInstanceNotFound(uuid=ptp_instance_id) - return query.one() + return _paginate_query(models.PtpInstances, limit, marker, + sort_key, sort_dir, query) def ptp_instance_destroy(self, ptp_instance_id): with _session_for_write() as session: - query = model_query(models.PtpInstances, session=session) + # PTP instance will be deleted by cascade + query = model_query(models.PtpParameterOwners, session=session) query = add_identity_filter(query, ptp_instance_id) try: query.one() @@ -3874,56 +3846,37 @@ class Connection(api.Connection): return self._ptp_interface_get(ptp_interface_id) @objects.objectify(objects.ptp_interface) - def ptp_interface_get_one(self): + def ptp_interface_get_one(self, interface_uuid=None): query = model_query(models.PtpInterfaces) + if interface_uuid is not None: + interface = self.iinterface_get(interface_uuid) + ptp_interface_id = interface['ptp_interface_id'] + if not ptp_interface_id: + return None + query = add_identity_filter(query, ptp_interface_id) try: return query.one() except NoResultFound: raise exception.NotFound() @objects.objectify(objects.ptp_interface) - def ptp_interfaces_get_list(self, limit=None, marker=None, sort_key=None, + def ptp_interfaces_get_list(self, host_uuid=None, interface_uuid=None, + limit=None, marker=None, sort_key=None, sort_dir=None): query = model_query(models.PtpInterfaces) - return _paginate_query(models.PtpInterfaces, limit, marker, - sort_key, sort_dir, query) - - @objects.objectify(objects.ptp_interface) - def ptp_interfaces_get_by_host(self, host_uuid, limit=None, - marker=None, sort_key=None, - sort_dir=None): - ihost_obj = self.ihost_get(host_uuid) - query = model_query(models.PtpInterfaces) - query = (query.join(models.Interfaces). - join(models.ihost, - models.ihost.id == models.Interfaces.forihostid)) - query, field = add_filter_by_many_identities(query, models.ihost, [ihost_obj.uuid]) - return _paginate_query(models.PtpInterfaces, limit, marker, sort_key, sort_dir, query) - - @objects.objectify(objects.ptp_interface) - def ptp_interfaces_get_by_interface(self, interface_id, limit=None, - marker=None, sort_key=None, - sort_dir=None): - # NOTE: iinterface_get() to raise an exception if the interface is - # not found or multiple results found - iface_obj = self.iinterface_get(interface_id) - query = model_query(models.PtpInterfaces) - query = query.filter_by(interface_id=iface_obj.id) - return _paginate_query(models.PtpInterfaces, limit, marker, - sort_key, sort_dir, query) - - @objects.objectify(objects.ptp_interface) - def ptp_interfaces_get_by_instance_and_interface(self, ptp_instance_id, - interface_id, - limit=None, - marker=None, - sort_key=None, - sort_dir=None): - ptp_instance_obj = self.ptp_instance_get(ptp_instance_id) - ptp_interface_obj = self.iinterface_get(interface_id) - query = model_query(models.PtpInterfaces) - query = query.filter_by(interface_id=ptp_interface_obj.id) - query = query.filter_by(ptp_instance_id=ptp_instance_obj.id) + if host_uuid is not None: + query = query.join(models.Interfaces).join( + models.ihost, + models.ihost.id == models.Interfaces.forihostid).filter( + models.ihost.uuid == host_uuid, + models.Interfaces.ptp_interface_id == + models.PtpInterfaces.id) + elif interface_uuid is not None: + interface = self.iinterface_get(interface_uuid) + ptp_interface_id = interface['ptp_interface_id'] + if not ptp_interface_id: + return [] + query = add_identity_filter(query, ptp_interface_id) return _paginate_query(models.PtpInterfaces, limit, marker, sort_key, sort_dir, query) @@ -3940,18 +3893,27 @@ class Connection(api.Connection): sort_key, sort_dir, query) @objects.objectify(objects.ptp_interface) - def ptp_interface_update(self, ptp_interface_id, values): - with _session_for_write() as session: - query = model_query(models.PtpInterfaces, session=session) - query = add_identity_filter(query, ptp_interface_id) - count = query.update(values, synchronize_session='fetch') - if count != 1: - raise exception.PtpInterfaceNotFound(uuid=ptp_interface_id) - return query.one() + def ptp_interfaces_get_by_instance_and_interface(self, ptp_instance_id, + interface_id, + limit=None, + marker=None, + sort_key=None, + sort_dir=None): + query = model_query(models.PtpInterfaces) + interface = self.iinterface_get(interface_id) + ptp_interface_id = interface['ptp_interface_id'] + if not ptp_interface_id: + return [] + query = add_identity_filter(query, ptp_interface_id) + ptp_instance_obj = self.ptp_instance_get(ptp_instance_id) + query = query.filter_by(ptp_instance_id=ptp_instance_obj.id) + return _paginate_query(models.PtpInterfaces, limit, marker, + sort_key, sort_dir, query) def ptp_interface_destroy(self, ptp_interface_id): with _session_for_write() as session: - query = model_query(models.PtpInterfaces, session=session) + # PTP instance will be deleted by cascade + query = model_query(models.PtpParameterOwners, session=session) query = add_identity_filter(query, ptp_interface_id) try: query.one() @@ -3978,7 +3940,8 @@ class Connection(api.Connection): session.add(ptp_parameter) session.flush() except db_exc.DBDuplicateEntry: - raise exception.PtpParameterAlreadyExists(uuid=values['uuid']) + raise exception.PtpParameterAlreadyExists( + name=values['name'], value=values['value']) return self._ptp_parameter_get(values['uuid']) @objects.objectify(objects.ptp_parameter) @@ -4003,34 +3966,22 @@ class Connection(api.Connection): sort_key, sort_dir, query) @objects.objectify(objects.ptp_parameter) - def ptp_parameters_get_by_type(self, type, limit=None, marker=None, - sort_key=None, sort_dir=None): + def ptp_parameters_get_by_owner_type(self, type, limit=None, marker=None, + sort_key=None, sort_dir=None): query = model_query(models.PtpParameters) - query = query.filter_by(type=type) - return _paginate_query(models.PtpParameters, limit, marker, - sort_key, sort_dir, query) - - def _ptp_parameter_get_type(self, uuid): - type = None - query = model_query(models.PtpParameters) - query = query.filter_by(foreign_uuid=uuid) - ptp_parameter_object = query.first() - if ptp_parameter_object: - type = ptp_parameter_object.type - - return type + query = query.join(models.PtpParameters.ptp_parameter_owners).filter( + models.PtpParameterOwners.type == type) + return _paginate_query(models.PtpParameters, limit, marker, sort_key, + sort_dir, query) @objects.objectify(objects.ptp_parameter) - def ptp_parameters_get_by_owner(self, uuid, limit=None, marker=None, - sort_key=None, sort_dir=None): - type = self._ptp_parameter_get_type(uuid) - if not type: - return [] + def ptp_parameters_get_by_owner_uuid(self, uuid, limit=None, marker=None, + sort_key=None, sort_dir=None): query = model_query(models.PtpParameters) - query = query.filter_by(foreign_uuid=uuid) - query = add_ptp_parameter_filter_by_owner(query, type, uuid) - return _paginate_query(models.PtpParameters, limit, marker, - sort_key, sort_dir, query) + query = query.join(models.PtpParameters.ptp_parameter_owners).filter( + models.PtpParameterOwners.uuid == uuid) + return _paginate_query(models.PtpParameters, limit, marker, sort_key, + sort_dir, query) @objects.objectify(objects.ptp_parameter) def ptp_parameter_update(self, ptp_parameter_id, values): @@ -4042,6 +3993,49 @@ class Connection(api.Connection): raise exception.PtpParameterNotFound(uuid=ptp_parameter_id) return query.one() + @objects.objectify(objects.ptp_paramownership) + def ptp_parameter_set_owner(self, values): + if not values.get('uuid'): + values['uuid'] = uuidutils.generate_uuid() + param_ownership = models.PtpParameterOwnerships(**values) + with _session_for_write() as session: + try: + session.add(param_ownership) + session.flush() + except db_exc.DBDuplicateEntry: + raise exception.PtpParameterOwnershipAlreadyExists( + param=values['parameter_uuid'], owner=values['owner_uuid']) + + query = model_query(models.PtpParameterOwnerships) + query = add_identity_filter(query, values['uuid']) + + try: + return query.one() + except NoResultFound: + raise exception.PtpParameterOwnershipNotFound( + uuid=values['uuid']) + + def ptp_parameter_unset_owner(self, values): + with _session_for_write() as session: + query = model_query(models.PtpParameterOwnerships, session=session) + query = query.filter_by(parameter_uuid=values['parameter_uuid'], + owner_uuid=values['owner_uuid']) + try: + query.one() + except NoResultFound: + return + query.delete() + + @objects.objectify(objects.ptp_parameter) + def ptp_parameter_get_owners_list(self, ptp_parameter_id, limit=None, + marker=None, sort_key=None, + sort_dir=None): + query = model_query(models.PtpParameters) + query = add_identity_filter(query, ptp_parameter_id) + query = query.join(models.PtpParameters.ptp_parameter_owners) + return _paginate_query(models.PtpParameters, limit, marker, sort_key, + sort_dir, query) + def ptp_parameter_destroy(self, ptp_parameter_id): with _session_for_write() as session: query = model_query(models.PtpParameters, session=session) @@ -4052,6 +4046,42 @@ class Connection(api.Connection): raise exception.PtpParameterNotFound(uuid=ptp_parameter_id) query.delete() + @objects.objectify(objects.ptp_paramowner) + def ptp_paramowner_get(self, ptp_paramowner_id): + query = model_query(models.PtpParameterOwners) + query = add_identity_filter(query, ptp_paramowner_id) + try: + return query.one() + except NoResultFound: + raise exception.PtpParameterOwnerNotFound(uuid=ptp_paramowner_id) + + @objects.objectify(objects.ptp_paramownership) + def ptp_paramownership_get(self, ptp_paramownership_id): + query = model_query(models.PtpParameterOwnerships) + query = add_identity_filter(query, ptp_paramownership_id) + try: + return query.one() + except NoResultFound: + raise exception.PtpParameterOwnershipNotFound( + uuid=ptp_paramownership_id) + + @objects.objectify(objects.ptp_paramownership) + def ptp_paramownerships_get_by_parameter(self, uuid, limit=None, + marker=None, sort_key=None, + sort_dir=None): + query = model_query(models.PtpParameterOwnerships) + query = query.filter_by(parameter_uuid=uuid) + return _paginate_query(models.PtpParameterOwnerships, limit, marker, + sort_key, sort_dir, query) + + @objects.objectify(objects.ptp_paramownership) + def ptp_paramownerships_get_by_owner(self, uuid, limit=None, marker=None, + sort_key=None, sort_dir=None): + query = model_query(models.PtpParameterOwnerships) + query = query.filter_by(owner_uuid=uuid) + return _paginate_query(models.PtpParameterOwnerships, limit, marker, + sort_key, sort_dir, query) + # NOTE: method is deprecated and provided for API compatibility. # object class will convert Network entity to an iextoam object @objects.objectify(objects.oam_network) diff --git a/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/migrate_repo/versions/120_ptp_instances.py b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/migrate_repo/versions/120_ptp_instances.py index c8e56839fe..673977db56 100644 --- a/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/migrate_repo/versions/120_ptp_instances.py +++ b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/migrate_repo/versions/120_ptp_instances.py @@ -22,7 +22,7 @@ CHARSET = 'utf8' def _populate_ptp_tables(meta, ptp_instances, ptp_interfaces, - ptp_parameters, i_host, interfaces): + ptp_parameters, ptp_parameter_ownerships): """This function moves PTP configuration from other tables: - If advanced (specialized) ptp4l configuration is found in 'service_parameter' table, it inserts a 'ptp4l' entry in @@ -46,51 +46,6 @@ def upgrade(migrate_engine): meta = MetaData() meta.bind = migrate_engine - i_host = Table('i_host', meta, autoload=True) - ptp_instances = Table( - 'ptp_instances', - 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('name', String(255), unique=True), - Column('service', String(255)), - - Column('host_id', Integer, - ForeignKey('i_host.id', ondelete="CASCADE")), - Column('capabilities', Text), - - mysql_engine=ENGINE, - mysql_charset=CHARSET, - ) - ptp_instances.create() - - interfaces = Table('interfaces', meta, autoload=True) - ptp_interfaces = Table( - 'ptp_interfaces', - 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")), - Column('ptp_instance_id', Integer, - ForeignKey('ptp_instances.id', ondelete="CASCADE")), - Column('capabilities', Text), - - mysql_engine=ENGINE, - mysql_charset=CHARSET, - ) - ptp_interfaces.create() - ptp_parameters = Table( 'ptp_parameters', meta, @@ -101,31 +56,125 @@ def upgrade(migrate_engine): Column('id', Integer, primary_key=True, nullable=False), Column('uuid', String(UUID_LENGTH), unique=True), - Column('name', String(255), nullable=False), + Column('name', String(255), unique=True, nullable=False), Column('value', String(255)), - Column('type', String(255)), - Column('foreign_uuid', String(UUID_LENGTH), nullable=False), - UniqueConstraint('name', 'foreign_uuid', name='u_paramnameforeign'), + UniqueConstraint('name', 'value', name='u_paramnamevalue'), mysql_engine=ENGINE, mysql_charset=CHARSET, ) ptp_parameters.create() + ptp_parameter_owners = Table( + 'ptp_parameter_owners', + 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('type', String(255), nullable=False), + + Column('capabilities', Text), + + mysql_engine=ENGINE, + mysql_charset=CHARSET, + ) + ptp_parameter_owners.create() + + ptp_instances = Table( + 'ptp_instances', + meta, + Column('created_at', DateTime), + Column('updated_at', DateTime), + Column('deleted_at', DateTime), + + Column('id', Integer, + ForeignKey('ptp_parameter_owners.id', ondelete="CASCADE"), + primary_key=True, nullable=False), + + Column('name', String(255), unique=True, nullable=False), + Column('service', String(255)), + + mysql_engine=ENGINE, + mysql_charset=CHARSET, + ) + ptp_instances.create() + + host = Table('i_host', meta, autoload=True) + host.create_column( + Column('ptp_instance_id', Integer, ForeignKey('ptp_instances.id'))) + + ptp_interfaces = Table( + 'ptp_interfaces', + meta, + Column('created_at', DateTime), + Column('updated_at', DateTime), + Column('deleted_at', DateTime), + + Column('id', Integer, + ForeignKey('ptp_parameter_owners.id', ondelete="CASCADE"), + primary_key=True, nullable=False), + + Column('ptp_instance_id', Integer, + ForeignKey('ptp_instances.id', ondelete="CASCADE"), + nullable=False), + + mysql_engine=ENGINE, + mysql_charset=CHARSET, + ) + ptp_interfaces.create() + + 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', + 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('parameter_uuid', String(UUID_LENGTH), + ForeignKey('ptp_parameters.uuid', ondelete='CASCADE'), + nullable=False), + Column('owner_uuid', String(UUID_LENGTH), nullable=False), + + UniqueConstraint('parameter_uuid', 'owner_uuid', name='u_paramowner'), + + mysql_engine=ENGINE, + mysql_charset=CHARSET, + ) + ptp_parameter_ownerships.create() + _populate_ptp_tables(meta, ptp_instances, ptp_interfaces, ptp_parameters, - i_host, interfaces) + ptp_parameter_ownerships) def downgrade(migrate_engine): meta = MetaData() meta.bind = migrate_engine - ptp_parameters = Table('ptp_parameters', meta, autoload=True) - ptp_parameters.drop() + ptp_parameter_ownerships = Table('ptp_parameter_ownerships', + meta, + autoload=True) + ptp_parameter_ownerships.drop() ptp_interfaces = Table('ptp_interfaces', meta, autoload=True) ptp_interfaces.drop() ptp_instances = Table('ptp_instances', meta, autoload=True) ptp_instances.drop() + + ptp_parameter_owners = Table('ptp_parameter_owners', meta, autoload=True) + ptp_parameter_owners.drop() + + ptp_parameters = Table('ptp_parameters', meta, autoload=True) + ptp_parameters.drop() diff --git a/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/models.py b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/models.py index 5c7864a38f..92ab54564b 100644 --- a/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/models.py +++ b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/models.py @@ -245,6 +245,9 @@ class ihost(Base): peer_id = Column(Integer, ForeignKey('peers.id')) + ptp_instance_id = Column(Integer, ForeignKey('ptp_instances.id')) + ptp = relationship("PtpInstances", lazy="joined", join_depth=1) + system = relationship("isystem") host_upgrade = relationship("HostUpgrade", uselist=False) @@ -262,7 +265,7 @@ class inode(Base): forihostid = Column(Integer, ForeignKey('i_host.id', ondelete='CASCADE')) - host = relationship("ihost", backref="nodes", lazy="joined", cascade="all") + host = relationship("ihost", backref="nodes", lazy="joined", join_depth=1) UniqueConstraint('numa_node', 'forihostid', name='u_hostnuma') @@ -356,7 +359,10 @@ class Interfaces(Base): farend = Column(JSONEncodedDict) sriov_numvfs = Column(Integer) sriov_vf_driver = Column(String(255)) - ptp_role = Column(String(255), default='none') + 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( "Interfaces", @@ -369,7 +375,7 @@ class Interfaces(Base): join_depth=1) host = relationship("ihost", backref="interfaces", - lazy="joined", cascade="all") + lazy="joined", join_depth=1) addresses = relationship("Addresses", backref=backref("interface", lazy="joined"), @@ -481,10 +487,10 @@ class Ports(Base): capabilities = Column(JSONEncodedDict) # JSON{'speed':1000,'MTU':9600, 'duplex':'', 'autonegotiation':'false'} - node = relationship("inode", backref="ports", lazy="joined", cascade="all") - host = relationship("ihost", backref="ports", lazy="joined", cascade="all") + node = relationship("inode", backref="ports", lazy="joined", join_depth=1) + host = relationship("ihost", backref="ports", lazy="joined", join_depth=1) interface = relationship("Interfaces", backref="port", - lazy="joined", cascade="all") + lazy="joined", join_depth=1) UniqueConstraint('pciaddr', 'dev_id', 'host_id', name='u_pciaddrdevihost') @@ -784,45 +790,6 @@ class PTP(Base): system = relationship("isystem", lazy="joined", join_depth=1) -class PtpInstances(Base): - __tablename__ = "ptp_instances" - - id = Column(Integer, primary_key=True, nullable=False) - uuid = Column(String(UUID_LENGTH), unique=True) - - name = Column(String(255), unique=True) - service = Column(String(255)) - host_id = Column(Integer, ForeignKey('i_host.id', ondelete='CASCADE'), - nullable=True) - - # capabilities not used yet: JSON{'':"", '':''} - capabilities = Column(JSONEncodedDict) - - host = relationship("ihost", backref="ptp_instance", lazy="joined", - cascade="all") - - -class PtpInterfaces(Base): - __tablename__ = "ptp_interfaces" - - id = Column(Integer, primary_key=True, nullable=False) - uuid = Column(String(UUID_LENGTH), unique=True) - - interface_id = Column(Integer, - ForeignKey('interfaces.id', ondelete='CASCADE')) - ptp_instance_id = Column(Integer, - ForeignKey('ptp_instances.id', - ondelete='CASCADE')) - - # capabilities not used yet: JSON{'':"", '':''} - capabilities = Column(JSONEncodedDict) - - interface = relationship("Interfaces", backref="ptp_interface", - lazy="joined", cascade="all") - ptp_instance = relationship("PtpInstances", backref="ptp_interface", - lazy="joined", cascade="all") - - class PtpParameters(Base): __tablename__ = "ptp_parameters" @@ -832,23 +799,106 @@ class PtpParameters(Base): name = Column(String(255), nullable=False) value = Column(String(255)) - type = Column(String(255)) - foreign_uuid = Column(String(UUID_LENGTH), nullable=False) + ptp_parameter_owners = relationship( + "PtpParameterOwners", + secondary="ptp_parameter_ownerships", + primaryjoin="PtpParameters.uuid == " + "foreign(PtpParameterOwnerships.parameter_uuid)", + secondaryjoin="PtpParameterOwners.uuid == " + "foreign(PtpParameterOwnerships.owner_uuid)", + back_populates="ptp_parameters", lazy="joined", join_depth=1) - ptp_instance = relationship( - "PtpInstances", - primaryjoin="PtpParameters.foreign_uuid == foreign(PtpInstances.uuid)", - lazy="subquery", - cascade="all") + UniqueConstraint('name', 'value', name='u_paramnamevalue') - ptp_interface = relationship( - "PtpInterfaces", - primaryjoin="PtpParameters.foreign_uuid == " - "foreign(PtpInterfaces.uuid)", - lazy="subquery", - cascade="all") - UniqueConstraint('name', 'foreign_uuid', name='u_paramnameforeign') +class PtpParameterOwners(Base): + __tablename__ = "ptp_parameter_owners" + + id = Column(Integer, primary_key=True, nullable=False) + uuid = Column(String(UUID_LENGTH), unique=True) + type = Column(String(255), nullable=False) + + # capabilities not used yet: JSON{'':"", '':''} + capabilities = Column(JSONEncodedDict) + + ptp_parameters = relationship( + "PtpParameters", + secondary="ptp_parameter_ownerships", + primaryjoin="PtpParameterOwners.uuid == " + "foreign(PtpParameterOwnerships.owner_uuid)", + secondaryjoin="PtpParameters.uuid == " + "foreign(PtpParameterOwnerships.parameter_uuid)", + back_populates="ptp_parameter_owners", lazy="joined", join_depth=1) + + __mapper_args__ = { + 'polymorphic_identity': 'ptp_parameter_owner', + 'polymorphic_on': type, + 'with_polymorphic': '*' + } + + +class PtpInstances(PtpParameterOwners): + __tablename__ = "ptp_instances" + + id = Column(Integer, ForeignKey('ptp_parameter_owners.id'), + primary_key=True, + nullable=False) + name = Column(String(255), unique=True, nullable=False) + service = Column(String(255)) + + __mapper_args__ = { + 'polymorphic_identity': constants.PTP_PARAMETER_OWNER_INSTANCE + } + + +class PtpInterfaces(PtpParameterOwners): + __tablename__ = "ptp_interfaces" + + id = Column(Integer, ForeignKey('ptp_parameter_owners.id'), + primary_key=True, + nullable=False) + ptp_instance_id = Column(Integer, + ForeignKey('ptp_instances.id', + ondelete='CASCADE'), + nullable=False) + + ptp_instance = relationship("PtpInstances", lazy="joined", join_depth=1, + foreign_keys=[ + PtpInstances.id, + PtpInstances.name, + PtpInstances.uuid]) + + __mapper_args__ = { + 'polymorphic_identity': constants.PTP_PARAMETER_OWNER_INTERFACE + } + + +class PtpParameterOwnerships(Base): + """ + This is a bridge table used to model the many-to-many relationship between + PTP parameters and their owners: PTP instances and PTP interfaces. + """ + __tablename__ = "ptp_parameter_ownerships" + + id = Column(Integer, primary_key=True, nullable=False) + uuid = Column(String(UUID_LENGTH), unique=True) + + parameter_uuid = Column(String(UUID_LENGTH), + ForeignKey('ptp_parameters.uuid', + ondelete='CASCADE'), + nullable=False) + owner_uuid = Column(String(UUID_LENGTH), nullable=False) + + parameter = relationship("PtpParameters", 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') class StorageTier(Base): diff --git a/sysinv/sysinv/sysinv/sysinv/objects/__init__.py b/sysinv/sysinv/sysinv/sysinv/objects/__init__.py index a121c3716a..1573b293f0 100644 --- a/sysinv/sysinv/sysinv/sysinv/objects/__init__.py +++ b/sysinv/sysinv/sysinv/sysinv/objects/__init__.py @@ -73,6 +73,8 @@ from sysinv.objects import ptp from sysinv.objects import ptp_instance from sysinv.objects import ptp_interface from sysinv.objects import ptp_parameter +from sysinv.objects import ptp_paramowner +from sysinv.objects import ptp_paramownership from sysinv.objects import pv from sysinv.objects import remote_logging from sysinv.objects import route @@ -160,6 +162,8 @@ ptp = ptp.PTP ptp_instance = ptp_instance.PtpInstance ptp_interface = ptp_interface.PtpInterface ptp_parameter = ptp_parameter.PtpParameter +ptp_paramowner = ptp_paramowner.PtpParameterOwner +ptp_paramownership = ptp_paramownership.PtpParameterOwnership oam_network = network_oam.OAMNetwork storage_backend = storage_backend.StorageBackend storage_ceph = storage_ceph.StorageCeph @@ -242,6 +246,8 @@ __all__ = ("system", "ptp_instance", "ptp_interface", "ptp_parameter", + "ptp_paramowner", + "ptp_paramownership", "oam_network", "storage_backend", "storage_ceph", diff --git a/sysinv/sysinv/sysinv/sysinv/objects/host.py b/sysinv/sysinv/sysinv/sysinv/objects/host.py index 1195414ca8..3e98471f4a 100644 --- a/sysinv/sysinv/sysinv/sysinv/objects/host.py +++ b/sysinv/sysinv/sysinv/sysinv/objects/host.py @@ -23,6 +23,11 @@ def _get_target_load(field, db_object): return db_object.host_upgrade.load_target.software_version +def _get_ptp_configuration(field, db_object): + # TODO + return {} + + class Host(base.SysinvObject): dbapi = db_api.get_instance() @@ -32,6 +37,7 @@ class Host(base.SysinvObject): 'forisystemid': utils.int_or_none, 'isystem_uuid': utils.str_or_none, 'peer_id': utils.int_or_none, + 'ptp_instance_id': utils.int_or_none, 'recordtype': utils.str_or_none, # 'created_at': utils.datetime_str_or_none, @@ -76,6 +82,7 @@ class Host(base.SysinvObject): 'config_target': utils.str_or_none, 'capabilities': utils.dict_or_none, 'clock_synchronization': utils.str_or_none, + 'ptp_config': utils.dict_or_none, 'boot_device': utils.str_or_none, 'rootfs_device': utils.str_or_none, @@ -97,6 +104,7 @@ class Host(base.SysinvObject): 'isystem_uuid': 'system:uuid', 'software_load': _get_software_load, 'target_load': _get_target_load, + 'ptp_config': _get_ptp_configuration } @base.remotable_classmethod diff --git a/sysinv/sysinv/sysinv/sysinv/objects/interface.py b/sysinv/sysinv/sysinv/sysinv/objects/interface.py index a49c0b9526..cfddc5ca9b 100644 --- a/sysinv/sysinv/sysinv/sysinv/objects/interface.py +++ b/sysinv/sysinv/sysinv/sysinv/objects/interface.py @@ -108,6 +108,11 @@ def get_datanetworks(field, db_object): return result +def _get_ptp_configuration(field, db_object): + # TODO + return {} + + class Interface(base.SysinvObject): # VERSION 1.0: Initial version # VERSION 1.1: Added VLAN and uses/used_by interface support @@ -120,6 +125,7 @@ class Interface(base.SysinvObject): 'uuid': utils.str_or_none, 'forihostid': utils.int_or_none, 'ihost_uuid': utils.str_or_none, + 'ptp_interface_id': utils.int_or_none, 'ifname': utils.str_or_none, 'iftype': utils.str_or_none, @@ -148,6 +154,7 @@ class Interface(base.SysinvObject): 'sriov_numvfs': utils.int_or_none, 'sriov_vf_driver': utils.str_or_none, 'ptp_role': utils.str_or_none, + 'ptp_config': utils.dict_or_none, 'max_tx_rate': utils.int_or_none, } @@ -159,7 +166,8 @@ class Interface(base.SysinvObject): 'ipv6_pool': get_ipv6_address_pool, 'ihost_uuid': get_host_uuid, 'networktypelist': get_networktypes, - 'datanetworks': get_datanetworks} + 'datanetworks': get_datanetworks, + 'ptp_config': _get_ptp_configuration} _optional_fields = ['aemode', 'txhashpolicy', 'schedpolicy', 'vlan_id', 'vlan_type', 'primary_reselect'] diff --git a/sysinv/sysinv/sysinv/sysinv/objects/ptp_instance.py b/sysinv/sysinv/sysinv/sysinv/objects/ptp_instance.py index 1a7b4679e4..7eae9c5d9c 100644 --- a/sysinv/sysinv/sysinv/sysinv/objects/ptp_instance.py +++ b/sysinv/sysinv/sysinv/sysinv/objects/ptp_instance.py @@ -9,36 +9,20 @@ from sysinv.db import api as db_api from sysinv.objects import base from sysinv.objects import utils +from sysinv.objects import ptp_paramowner -class PtpInstance(base.SysinvObject): +class PtpInstance(ptp_paramowner.PtpParameterOwner): dbapi = db_api.get_instance() - fields = { - 'id': int, - 'uuid': utils.str_or_none, - + fields = dict({ 'name': utils.str_or_none, - 'service': utils.str_or_none, + 'service': utils.str_or_none + }, **ptp_paramowner.PtpParameterOwner.fields) - 'host_id': utils.int_or_none, - - 'host_uuid': utils.str_or_none, - 'hostname': utils.str_or_none, - - 'capabilities': utils.dict_or_none - } - - _foreign_fields = { - 'host_uuid': 'host:uuid', - 'hostname': 'host:hostname' - } + _foreign_fields = {} @base.remotable_classmethod def get_by_uuid(cls, context, uuid): return cls.dbapi.ptp_instance_get(uuid) - - def save_changes(self, context, updates): - self.dbapi.ptp_instance_update(self.uuid, # pylint: disable=no-member - updates) diff --git a/sysinv/sysinv/sysinv/sysinv/objects/ptp_interface.py b/sysinv/sysinv/sysinv/sysinv/objects/ptp_interface.py index d6a07aa59d..d8778cfa13 100644 --- a/sysinv/sysinv/sysinv/sysinv/objects/ptp_interface.py +++ b/sysinv/sysinv/sysinv/sysinv/objects/ptp_interface.py @@ -9,37 +9,22 @@ from sysinv.db import api as db_api from sysinv.objects import base from sysinv.objects import utils +from sysinv.objects import ptp_paramowner -class PtpInterface(base.SysinvObject): +class PtpInterface(ptp_paramowner.PtpParameterOwner): dbapi = db_api.get_instance() - fields = { - 'id': int, - 'uuid': utils.str_or_none, - - 'interface_uuid': utils.str_or_none, - 'interface_id': utils.int_or_none, - - 'ptp_instance_uuid': utils.str_or_none, + fields = dict({ 'ptp_instance_id': utils.int_or_none, - 'ptp_instance_name': utils.str_or_none, - - 'ifname': utils.str_or_none, - 'forihostid': utils.int_or_none, - - 'capabilities': utils.dict_or_none - } + 'ptp_instance_uuid': utils.str_or_none, + 'ptp_instance_name': utils.str_or_none + }, **ptp_paramowner.PtpParameterOwner.fields) _foreign_fields = { - 'interface_uuid': 'interface:uuid', - 'interface_id': 'interface:id', 'ptp_instance_uuid': 'ptp_instance:uuid', - 'ptp_instance_name': 'ptp_instance:name', - 'ifname': 'interface:ifname', - 'forihostid': 'interface:forihostid', - 'ptp_instance_host': 'ptp_instance:host_id' + 'ptp_instance_name': 'ptp_instance:name' } @base.remotable_classmethod diff --git a/sysinv/sysinv/sysinv/sysinv/objects/ptp_parameter.py b/sysinv/sysinv/sysinv/sysinv/objects/ptp_parameter.py index 21772478ee..c1fd885906 100644 --- a/sysinv/sysinv/sysinv/sysinv/objects/ptp_parameter.py +++ b/sysinv/sysinv/sysinv/sysinv/objects/ptp_parameter.py @@ -12,30 +12,21 @@ from sysinv.objects import base from sysinv.objects import utils -def get_owner(field, db_object): - owner = {} - """Retrieves the owner details based on type and uuid.""" - if db_object['type'] == constants.PTP_PARAMETER_OWNER_INSTANCE: - ptp_instances = getattr(db_object, 'ptp_instance') - if ptp_instances: - owner['name'] = ptp_instances[0].name - owner['type'] = ptp_instances[0].service - host = getattr(ptp_instances[0], 'host') - if host: - owner['hostname'] = host.hostname +def get_owners(field, db_object): + ptp_parameter_owners = db_object['ptp_parameter_owners'] + if not ptp_parameter_owners: + return [] - elif db_object['type'] == constants.PTP_PARAMETER_OWNER_INTERFACE: - ptp_interfaces = getattr(db_object, 'ptp_interface') - if ptp_interfaces: - interface = getattr(ptp_interfaces[0], 'interface') - if interface: - owner['name'] = interface.ifname - owner['type'] = interface.iftype - host = getattr(interface, 'host') - if host: - owner['hostname'] = host.hostname + owners = [] + for owner in ptp_parameter_owners: + details = {} + details['uuid'] = owner.uuid + if owner.type == constants.PTP_PARAMETER_OWNER_INSTANCE: + details['owner'] = owner.name + details['type'] = owner.service + owners.append(details) - return owner + return owners class PtpParameter(base.SysinvObject): @@ -49,14 +40,11 @@ class PtpParameter(base.SysinvObject): 'name': utils.str_or_none, 'value': utils.str_or_none, - 'type': utils.str_or_none, - 'foreign_uuid': utils.str_or_none, - - 'owner': dict + 'owners': list } _foreign_fields = { - 'owner': get_owner + 'owners': get_owners } @base.remotable_classmethod diff --git a/sysinv/sysinv/sysinv/sysinv/objects/ptp_paramowner.py b/sysinv/sysinv/sysinv/sysinv/objects/ptp_paramowner.py new file mode 100644 index 0000000000..800019e8c4 --- /dev/null +++ b/sysinv/sysinv/sysinv/sysinv/objects/ptp_paramowner.py @@ -0,0 +1,29 @@ +######################################################################## +# +# 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 PtpParameterOwner(base.SysinvObject): + + dbapi = db_api.get_instance() + + fields = { + 'id': int, + 'uuid': utils.str_or_none, + 'type': utils.str_or_none, + 'capabilities': utils.dict_or_none + } + + _foreign_fields = {} + + @base.remotable_classmethod + def get_by_uuid(cls, context, uuid): + return cls.dbapi.ptp_paramowner_get(uuid) diff --git a/sysinv/sysinv/sysinv/sysinv/objects/ptp_paramownership.py b/sysinv/sysinv/sysinv/sysinv/objects/ptp_paramownership.py new file mode 100644 index 0000000000..28e3a632fc --- /dev/null +++ b/sysinv/sysinv/sysinv/sysinv/objects/ptp_paramownership.py @@ -0,0 +1,30 @@ +######################################################################## +# +# 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 PtpParameterOwnership(base.SysinvObject): + + dbapi = db_api.get_instance() + + fields = { + 'id': int, + 'uuid': utils.str_or_none, + + 'parameter_uuid': utils.str_or_none, + 'owner_uuid': utils.str_or_none, + } + + _foreign_fields = {} + + @base.remotable_classmethod + def get_by_uuid(cls, context, uuid): + return cls.dbapi.ptp_paramownership_get(uuid) diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/networking.py b/sysinv/sysinv/sysinv/sysinv/puppet/networking.py index 7e94c51ef4..df42d38244 100644 --- a/sysinv/sysinv/sysinv/sysinv/puppet/networking.py +++ b/sysinv/sysinv/sysinv/sysinv/puppet/networking.py @@ -195,7 +195,7 @@ class NetworkingPuppet(base.BasePuppet): return {'platform::ptpinstance::enabled': ptp_enabled} # Get the database entries for instances, interfaces and parameters - ptp_instances = self.dbapi.ptp_instances_get_by_ihost(host.uuid) + ptp_instances = self.dbapi.ptp_instances_get_list(host=host.uuid) ptp_interfaces = self.dbapi.ptp_interfaces_get_by_host(host.uuid) ptp_parameters_instance = self.dbapi.ptp_parameters_get_by_type( constants.PTP_PARAMETER_OWNER_INSTANCE) diff --git a/sysinv/sysinv/sysinv/sysinv/tests/api/test_ptp_instance.py b/sysinv/sysinv/sysinv/sysinv/tests/api/test_ptp_instance.py index 3846b98f88..c76d86bf79 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/api/test_ptp_instance.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/api/test_ptp_instance.py @@ -38,37 +38,22 @@ class BasePtpInstanceTestCase(base.FunctionalTest, dbbase.BaseHostTestCase): return '%s/%s%s' % (self.HOST_PREFIX, host_uuid, self.API_PREFIX) def get_post_object(self, name='test_instance', - service=constants.PTP_INSTANCE_TYPE_PTP4L, - host_id=None, host_uuid=None, hostname=None): + service=constants.PTP_INSTANCE_TYPE_PTP4L): ptp_instance_db = dbutils.get_test_ptp_instance(name=name, - service=service, - host_id=host_id) - ptp_instance_db['host_uuid'] = host_uuid - ptp_instance_db['hostname'] = hostname + service=service) return ptp_instance_db class TestCreatePtpInstance(BasePtpInstanceTestCase): name = constants.PTP_INSTANCE_DEFAULT_PTP4L service = constants.PTP_INSTANCE_TYPE_PTP4L - host_id = None - host_uuid = None - hostname = None def setUp(self): super(TestCreatePtpInstance, self).setUp() - self.host_id = self.controller.id - self.host_uuid = self.controller.uuid - self.hostname = self.controller.hostname - dbutils.create_test_ptp_instance(name=self.name, service=self.service, - host_id=self.host_id) + dbutils.create_test_ptp_instance(name=self.name, service=self.service) - def _create_ptp_instance_success(self, name, service, host_id, host_uuid, - hostname): - ptp_instance_db = self.get_post_object(name=name, service=service, - host_id=host_id, - host_uuid=host_uuid, - hostname=hostname) + def _create_ptp_instance_success(self, name, service): + ptp_instance_db = self.get_post_object(name=name, service=service) response = self.post_json(self.API_PREFIX, ptp_instance_db, headers=self.API_HEADERS) self.assertEqual('application/json', response.content_type) @@ -76,12 +61,9 @@ class TestCreatePtpInstance(BasePtpInstanceTestCase): self.assertEqual(response.json[self.COMMON_FIELD], ptp_instance_db[self.COMMON_FIELD]) - def _create_ptp_instance_failed(self, name, service, host_id, host_uuid, - hostname, status_code, error_message): - ptp_instance_db = self.get_post_object(name=name, service=service, - host_id=host_id, - host_uuid=host_uuid, - hostname=hostname) + def _create_ptp_instance_failed(self, name, service, + status_code, error_message): + ptp_instance_db = self.get_post_object(name=name, service=service) response = self.post_json(self.API_PREFIX, ptp_instance_db, headers=self.API_HEADERS, expect_errors=True) self.assertEqual('application/json', response.content_type) @@ -90,18 +72,12 @@ class TestCreatePtpInstance(BasePtpInstanceTestCase): def test_create_ptp_instance_ok(self): self._create_ptp_instance_success('test-instance', - constants.PTP_INSTANCE_TYPE_PTP4L, - host_id=self.controller.id, - host_uuid=self.controller.uuid, - hostname=self.controller.hostname) + constants.PTP_INSTANCE_TYPE_PTP4L) def test_create_ptp_instance_invalid_service(self): self._create_ptp_instance_failed( 'test-invalid', 'invalid', - host_id=self.controller.id, - host_uuid=self.controller.uuid, - hostname=self.controller.hostname, status_code=http_client.BAD_REQUEST, error_message='Invalid input for field/attribute service') @@ -111,23 +87,26 @@ class TestCreatePtpInstance(BasePtpInstanceTestCase): self._create_ptp_instance_failed( name=self.name, service=self.service, - host_id=self.host_id, - host_uuid=self.host_uuid, - hostname=self.controller.hostname, status_code=http_client.CONFLICT, error_message=error_message) - def test_create_ptp_instance_invalid_host(self): - bad_uuid = 'f4c56ddf-aef3-46ed-b9aa-126a1faafd40' - error_message = '%s could not be found' % bad_uuid - self._create_ptp_instance_failed( - 'test-invalid', - constants.PTP_INSTANCE_TYPE_PHC2SYS, - host_id=99, - host_uuid=bad_uuid, - hostname='badhost', - status_code=http_client.NOT_FOUND, - error_message=error_message) + +class TestSetPtpInstance(BasePtpInstanceTestCase): + def setUp(self): + super(TestSetPtpInstance, self).setUp() + + def test_set_ptp_instance_to_hosts(self): + # TODO + pass + + +class TestUnsetPtpInstance(BasePtpInstanceTestCase): + def setUp(self): + super(TestUnsetPtpInstance, self).setUp() + + def test_unset_ptp_instance_from_hosts(self): + # TODO + pass class TestGetPtpInstance(BasePtpInstanceTestCase): @@ -137,8 +116,7 @@ class TestGetPtpInstance(BasePtpInstanceTestCase): def test_get_ptp_instance_found(self): ptp_instance = dbutils.create_test_ptp_instance( name=constants.PTP_INSTANCE_DEFAULT_PTP4L, - service=constants.PTP_INSTANCE_TYPE_PTP4L, - host_id=self.controller.id) + service=constants.PTP_INSTANCE_TYPE_PTP4L) uuid = ptp_instance['uuid'] response = self.get_json(self.get_single_url(uuid)) self.assertIn(self.COMMON_FIELD, response) @@ -159,17 +137,15 @@ class TestListPtpInstance(BasePtpInstanceTestCase): super(TestListPtpInstance, self).setUp() self._create_test_ptp_instances() - def _create_test_ptp_instances(self, name_prefix='test', host_id=None): + def _create_test_ptp_instances(self, name_prefix='test'): services = [constants.PTP_INSTANCE_TYPE_PTP4L, constants.PTP_INSTANCE_TYPE_PHC2SYS, constants.PTP_INSTANCE_TYPE_TS2PHC] instances = [] - if not host_id: - host_id = self.controller.id for service in services: name = '%s-%s' % (name_prefix, service) instance = dbutils.create_test_ptp_instance( - name=name, service=service, host_id=host_id) + name=name, service=service) instances.append(instance) return instances @@ -183,11 +159,8 @@ class TestListPtpInstance(BasePtpInstanceTestCase): self.assertEqual([], response[self.RESULT_KEY]) def test_list_ptp_instance_host(self): - self._create_test_ptp_instances(name_prefix='fake', - host_id=self.worker.id) - response = self.get_json(self.get_host_scoped_url(self.worker.uuid)) - for result in response[self.RESULT_KEY]: - self.assertEqual(self.worker.uuid, result['host_uuid']) + # TODO + pass class TestDeletePtpInstance(BasePtpInstanceTestCase): @@ -203,8 +176,7 @@ class TestDeletePtpInstance(BasePtpInstanceTestCase): super(TestDeletePtpInstance, self).setUp() self.ptp_instance = dbutils.create_test_ptp_instance( name=constants.PTP_INSTANCE_DEFAULT_PTP4L, - service=constants.PTP_INSTANCE_TYPE_PTP4L, - host_id=self.controller.id) + service=constants.PTP_INSTANCE_TYPE_PTP4L) self.uuid = self.ptp_instance['uuid'] def test_delete_ptp_instance_ok(self): @@ -220,12 +192,16 @@ class TestDeletePtpInstance(BasePtpInstanceTestCase): self.assertEqual(response.status_code, http_client.NOT_FOUND) self.assertIn(error_message, response.json['error_message']) + def test_delete_ptp_instance_with_host_failed(self): + # TODO + pass + def test_delete_ptp_instance_with_parameters_failed(self): ptp_parameter = dbutils.create_test_ptp_parameter( - name='fake-param', value='fake-value', - type=constants.PTP_PARAMETER_OWNER_INSTANCE, - foreign_uuid=self.uuid) - self.assertEqual(self.uuid, ptp_parameter['foreign_uuid']) + name='fake-param', value='fake-value') + ptp_ownership = dbutils.create_test_ptp_ownership( + parameter_uuid=ptp_parameter['uuid'], owner_uuid=self.uuid) + self.assertEqual(self.uuid, ptp_ownership['owner_uuid']) response = self.delete(self.get_single_url(self.uuid), headers=self.API_HEADERS, expect_errors=True) diff --git a/sysinv/sysinv/sysinv/sysinv/tests/api/test_ptp_interface.py b/sysinv/sysinv/sysinv/sysinv/tests/api/test_ptp_interface.py index 91977d65bf..f933f941f7 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/api/test_ptp_interface.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/api/test_ptp_interface.py @@ -6,7 +6,6 @@ # ######################################################################## -from oslo_utils import uuidutils from six.moves import http_client from sysinv.common import constants from sysinv.tests.api import base @@ -25,21 +24,22 @@ class BasePtpInterfaceTestCase(base.FunctionalTest, dbbase.BaseHostTestCase): RESULT_KEY = 'ptp_interfaces' # Field that is known to exist for inputs and outputs - COMMON_FIELD = 'interface_uuid' + COMMON_FIELD = 'ptp_instance_uuid' # Can perform API operations on thie object at a sublevel of host HOST_PREFIX = '/ihosts' - # Attributes that should be populated by an API query - expected_api_fields = ['uuid', 'interface_id', 'ptp_instance_id'] - - # Attributes that should NOT be populated by an API query - hidden_api_fields = ['host_id'] - def setUp(self): super(BasePtpInterfaceTestCase, self).setUp() self.controller = self._create_test_host(constants.CONTROLLER) - self.worker = self._create_test_host(constants.WORKER) + self.interface = dbutils.create_test_interface( + ifname='ptp0', + ifclass=constants.INTERFACE_CLASS_PLATFORM, + forihostid=self.controller.id, + ihost_uuid=self.controller.uuid) + self.instance = dbutils.create_test_ptp_instance( + name='testInstance', + service=constants.PTP_INSTANCE_TYPE_PTP4L) def get_single_url(self, ptp_interface_uuid): return '%s/%s' % (self.API_PREFIX, ptp_interface_uuid) @@ -53,51 +53,32 @@ class BasePtpInterfaceTestCase(base.FunctionalTest, dbbase.BaseHostTestCase): self.API_PREFIX, interface_uuid) - def get_post_object(self, interface_uuid=None, ptp_instance_uuid=None): - ptp_interface_db = { - 'interface_uuid': interface_uuid, - 'ptp_instance_uuid': ptp_instance_uuid - } + def get_post_object(self, ptp_instance_uuid): + ptp_interface_db = dbutils.get_test_ptp_interface( + ptp_instance_uuid=ptp_instance_uuid) return ptp_interface_db - def assert_fields(self, api_object): - assert(uuidutils.is_uuid_like(api_object['uuid'])) - for field in self.expected_api_fields: - self.assertIn(field, api_object) - for field in self.hidden_api_fields: - self.assertNotIn(field, api_object) - class TestCreatePtpInterface(BasePtpInterfaceTestCase): def setUp(self): super(TestCreatePtpInterface, self).setUp() - self.test_interface = dbutils.create_test_interface( - ifname='ptp0', - ifclass=constants.INTERFACE_CLASS_PLATFORM, - forihostid=self.controller.id, - ihost_uuid=self.controller.uuid) - - self.test_instance = dbutils.create_test_ptp_instance( - name='testInstance', - service=constants.PTP_INSTANCE_TYPE_PTP4L, - host_id=self.controller.id) - - def _create_ptp_interface_success(self, interface_uuid, ptp_instance_uuid): - ptp_interface_db = self.get_post_object(interface_uuid, - ptp_instance_uuid) + def _create_ptp_interface_success(self, ptp_instance_uuid): + ptp_interface_db = self.get_post_object(ptp_instance_uuid) response = self.post_json(self.API_PREFIX, ptp_interface_db, headers=self.API_HEADERS) self.assertEqual('application/json', response.content_type) self.assertEqual(response.status_code, http_client.OK) + """ + TODO: Check ptp_instance_uuid empty in the response self.assertEqual(response.json[self.COMMON_FIELD], ptp_interface_db[self.COMMON_FIELD]) + """ - def _create_ptp_interface_failed(self, interface_uuid, ptp_instance_uuid, + def _create_ptp_interface_failed(self, ptp_instance_uuid, status_code, error_message): - ptp_interface_db = self.get_post_object(interface_uuid, - ptp_instance_uuid) + ptp_interface_db = self.get_post_object(ptp_instance_uuid) response = self.post_json(self.API_PREFIX, ptp_interface_db, headers=self.API_HEADERS, expect_errors=True) @@ -106,54 +87,40 @@ class TestCreatePtpInterface(BasePtpInterfaceTestCase): self.assertIn(error_message, response.json['error_message']) def test_create_ptp_interface_ok(self): - self._create_ptp_interface_success(self.test_interface.uuid, - self.test_instance.uuid) - - def test_create_ptp_interface_invalid_interface(self): - self._create_ptp_interface_failed( - '32dbb999-6c10-448d-aeca-964c50af6384', - self.test_instance.uuid, - status_code=http_client.BAD_REQUEST, - error_message='No entry found for interface 32dbb999-6c10-448d-aeca-964c50af6384') + self._create_ptp_interface_success(self.instance.uuid) def test_create_ptp_interface_invalid_instance(self): self._create_ptp_interface_failed( - self.test_interface.uuid, '32dbb999-6c10-448d-aeca-964c50af6384', status_code=http_client.NOT_FOUND, error_message='No PTP instance with id 32dbb999-6c10-448d-aeca-964c50af6384 found.') - def test_create_ptp_interface_duplicate(self): - self._create_ptp_interface_success(self.test_interface.uuid, - self.test_instance.uuid) - self._create_ptp_interface_failed( - interface_uuid=self.test_interface.uuid, - ptp_instance_uuid=self.test_instance.uuid, - status_code=http_client.INTERNAL_SERVER_ERROR, - error_message='') +class TestSetPtpInterface(BasePtpInterfaceTestCase): + def setUp(self): + super(TestSetPtpInterface, self).setUp() + + def test_set_ptp_interface_to_interfaces(self): + # TODO + pass + + +class TestUnsetPtpInterface(BasePtpInterfaceTestCase): + def setUp(self): + super(TestUnsetPtpInterface, self).setUp() + + def test_unset_ptp_interface_from_interfaces(self): + # TODO + pass class TestGetPtpInterface(BasePtpInterfaceTestCase): def setUp(self): super(TestGetPtpInterface, self).setUp() - self.test_interface = dbutils.create_test_interface( - ifname='ptp0', - ifclass=constants.INTERFACE_CLASS_PLATFORM, - forihostid=self.controller.id, - ihost_uuid=self.controller.uuid) - - self.test_instance = dbutils.create_test_ptp_instance( - name='testInstance', - service=constants.PTP_INSTANCE_TYPE_PTP4L, - host_id=self.controller.id) - self.test_ptp_interface = dbutils.create_test_ptp_interface( - interface_id=self.test_interface.id, - ptp_instance_id=self.test_instance.id) + ptp_instance_id=self.instance.id) def test_get_ptp_interface_found(self): - response = self.get_json( self.get_single_url(self.test_ptp_interface.uuid)) self.assertIn(self.COMMON_FIELD, response) @@ -161,7 +128,6 @@ class TestGetPtpInterface(BasePtpInterfaceTestCase): def test_get_ptp_interface_not_found(self): fake_uuid = 'f4c56ddf-aef3-46ed-b9aa-126a1faafd40' error_message = 'No PTP interface with id %s found' % fake_uuid - response = self.get_json(self.get_single_url(fake_uuid), expect_errors=True) self.assertEqual('application/json', response.content_type) @@ -172,60 +138,28 @@ class TestGetPtpInterface(BasePtpInterfaceTestCase): class TestListPtpInterface(BasePtpInterfaceTestCase): def setUp(self): super(TestListPtpInterface, self).setUp() - self.test_interface = dbutils.create_test_interface( - ifname='ptp0', - ifclass=constants.INTERFACE_CLASS_PLATFORM, - forihostid=self.worker.id, - ihost_uuid=self.worker.uuid) - - self.dummy_interface = dbutils.create_test_interface( - ifname='ptp1', - ifclass=constants.INTERFACE_CLASS_PLATFORM, - forihostid=self.worker.id, - ihost_uuid=self.worker.uuid) - self.test_instance_ptp4l = dbutils.create_test_ptp_instance( name='ptp4lInstance', - service=constants.PTP_INSTANCE_TYPE_PTP4L, - host_id=self.worker.id) - + service=constants.PTP_INSTANCE_TYPE_PTP4L) self.test_instance_phc2sys = dbutils.create_test_ptp_instance( name='phc2sysInstance', - service='phc2sys', - host_id=self.worker.id) - + service='phc2sys') self.ptp4l_ptp_interface = dbutils.create_test_ptp_interface( - interface_id=self.test_interface.id, ptp_instance_id=self.test_instance_ptp4l.id) self.phc2sys_ptp_interface = dbutils.create_test_ptp_interface( - interface_id=self.test_interface.id, ptp_instance_id=self.test_instance_phc2sys.id) - self.dummy_ptp_interface = dbutils.create_test_ptp_interface( - interface_id=self.dummy_interface.id, - ptp_instance_id=self.test_instance_ptp4l.id) def test_list_ptp_interface_host(self): - response = self.get_json(self.get_host_scoped_url(self.worker.uuid)) - for result in response[self.RESULT_KEY]: - self.assertEqual(self.worker.id, result['forihostid']) - if result['uuid'] == self.ptp4l_ptp_interface.uuid \ - or result['uuid'] == self.dummy_interface.uuid: - self.assertEqual(self.test_instance_ptp4l.id, - result['ptp_instance_id']) - elif result['uuid'] == self.phc2sys_ptp_interface.uuid: - self.assertEqual(self.test_instance_phc2sys.id, - result['ptp_instance_id']) + # TODO + pass def test_list_ptp_interface_interface(self): - response = self.get_json(self.get_host_scoped_url_interface( - self.worker.uuid, self.test_interface.uuid)) - for result in response[self.RESULT_KEY]: - self.assertIn(self.COMMON_FIELD, result) - self.assertNotIn(self.dummy_interface.uuid, result) + # TODO + pass def test_list_ptp_interface_empty(self): - response = self.get_json(self.get_host_scoped_url(self.controller.uuid)) - self.assertEqual([], response[self.RESULT_KEY]) + # TODO + pass class TestDeletePtpInterface(BasePtpInterfaceTestCase): @@ -237,28 +171,14 @@ class TestDeletePtpInterface(BasePtpInterfaceTestCase): def setUp(self): super(TestDeletePtpInterface, self).setUp() - - self.test_interface = dbutils.create_test_interface( - ifname='ptp0', - ifclass=constants.INTERFACE_CLASS_PLATFORM, - forihostid=self.worker.id, - ihost_uuid=self.worker.uuid) - - self.test_instance_ptp4l = dbutils.create_test_ptp_instance( - name='ptp4lInstance', - service=constants.PTP_INSTANCE_TYPE_PTP4L, - host_id=self.worker.id) - self.test_ptp_interface = dbutils.create_test_ptp_interface( - interface_id=self.test_interface.id, - ptp_instance_id=self.test_instance_ptp4l.id) + ptp_instance_id=self.instance.id) def test_delete_ptp_interface(self): response = self.delete( self.get_single_url(self.test_ptp_interface.uuid), headers=self.API_HEADERS) self.assertEqual(response.status_code, http_client.NO_CONTENT) - error_message = \ 'No PTP interface with id %s found' % self.test_ptp_interface.uuid response = self.get_json( @@ -268,14 +188,18 @@ class TestDeletePtpInterface(BasePtpInterfaceTestCase): self.assertEqual(response.status_code, http_client.NOT_FOUND) self.assertIn(error_message, response.json['error_message']) + def test_delete_ptp_interface_with_interface_failed(self): + # TODO + pass + def test_delete_ptp_interface_with_parameters_failed(self): ptp_parameter = dbutils.create_test_ptp_parameter( - name='fake-param', value='fake-value', - type=constants.PTP_PARAMETER_OWNER_INTERFACE, - foreign_uuid=self.test_ptp_interface.uuid) + name='fake-param', value='fake-value') + ptp_ownership = dbutils.create_test_ptp_ownership( + parameter_uuid=ptp_parameter['uuid'], + owner_uuid=self.test_ptp_interface.uuid) self.assertEqual(self.test_ptp_interface.uuid, - ptp_parameter['foreign_uuid']) - + ptp_ownership['owner_uuid']) response = self.delete( self.get_single_url(self.test_ptp_interface.uuid), headers=self.API_HEADERS, expect_errors=True) diff --git a/sysinv/sysinv/sysinv/sysinv/tests/api/test_ptp_parameter.py b/sysinv/sysinv/sysinv/sysinv/tests/api/test_ptp_parameter.py index fcd73870b9..3349b367e5 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/api/test_ptp_parameter.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/api/test_ptp_parameter.py @@ -15,13 +15,22 @@ class BasePtpParameterTestCase(base.FunctionalTest, dbbase.BaseHostTestCase): API_HEADERS = {'User-Agent': 'sysinv-test'} # Prefix for the URL - API_PREFIX = '/ptp_parameters' + PARAMETER_PREFIX = '/ptp_parameters' # Python table key for the list of results - RESULT_KEY = 'ptp_parameters' + PARAMETER_KEY = 'ptp_parameters' # Field that is known to exist for inputs and outputs - COMMON_FIELD = 'name' + PARAMETER_FIELD = 'name' + + # Prefix for the URL + OWNERSHIP_PREFIX = '/ptp_parameter_ownerships' + + # Python table key for the list of results + OWNERSHIP_KEY = 'ptp_parameter_ownerships' + + # Field that is known to exist for inputs and outputs + OWNERSHIP_FIELD = 'owner_uuid' # Can perform API operations on this object at a sublevel of PTP instances PTP_INSTANCE_PREFIX = '/ptp_instances' @@ -32,64 +41,60 @@ class BasePtpParameterTestCase(base.FunctionalTest, dbbase.BaseHostTestCase): def setUp(self): super(BasePtpParameterTestCase, self).setUp() self.controller = self._create_test_host(constants.CONTROLLER) - self.ptp_instances = self._create_test_ptp_instance(self.controller) - self.platform_interfaces = \ - self._create_test_host_platform_interface(self.controller) + self.ptp_instances = self._create_test_ptp_instance() self.ptp_interfaces = self._create_test_ptp_interface( - self.ptp_instances, self.platform_interfaces) + self.ptp_instances) - def get_single_url(self, ptp_parameter_uuid): - return '%s/%s' % (self.API_PREFIX, ptp_parameter_uuid) + def get_parameter_url(self, ptp_parameter_uuid): + return '%s/%s' % (self.PARAMETER_PREFIX, ptp_parameter_uuid) + + def get_ownership_url(self, ptp_paramownership_uuid): + return '%s/%s' % (self.OWNERSHIP_PREFIX, ptp_paramownership_uuid) def get_instance_scoped_url(self, ptp_instance_uuid): return '%s/%s%s' % (self.PTP_INSTANCE_PREFIX, ptp_instance_uuid, - self.API_PREFIX) + self.PARAMETER_PREFIX) def get_interface_scoped_url(self, interface_uuid): return '%s/%s%s' % (self.INTERFACE_PREFIX, interface_uuid, - self.API_PREFIX) + self.PARAMETER_PREFIX) - def get_post_object(self, name='test_parameter', value='test_value', - type=None, foreign_uuid=None): + def get_post_parameter(self, name='test_parameter', value='test_value'): return dbutils.get_test_ptp_parameter(name=name, - value=value, - type=type, - foreign_uuid=foreign_uuid) + value=value) + + def get_post_ownership(self, parameter_uuid=None, owner_uuid=None): + return dbutils.get_test_ptp_ownership(parameter_uuid=parameter_uuid, + owner_uuid=owner_uuid) class TestCreatePtpParameter(BasePtpParameterTestCase): name = 'test-param' value = 'test-value' - type = constants.PTP_PARAMETER_OWNER_INSTANCE - foreign_uuid = None def setUp(self): super(TestCreatePtpParameter, self).setUp() - self.foreign_uuid = self.ptp_instances[0].uuid - dbutils.create_test_ptp_parameter(name=self.name, - value=self.value, - type=self.type, - foreign_uuid=self.foreign_uuid) + ptp_parameter_db = dbutils.create_test_ptp_parameter(name=self.name, + value=self.value) + uuid = ptp_parameter_db['uuid'] + response = self.get_json(self.get_parameter_url(uuid)) + self.assertIn(self.PARAMETER_FIELD, response) - def _create_ptp_parameter_success(self, name, value, type, foreign_uuid): - ptp_parameter_db = self.get_post_object(name=name, - value=value, - type=type, - foreign_uuid=foreign_uuid) - response = self.post_json(self.API_PREFIX, ptp_parameter_db, + def _create_ptp_parameter_success(self, name, value): + ptp_parameter_db = self.get_post_parameter(name=name, + value=value) + response = self.post_json(self.PARAMETER_PREFIX, ptp_parameter_db, headers=self.API_HEADERS) self.assertEqual('application/json', response.content_type) self.assertEqual(response.status_code, http_client.OK) - self.assertEqual(response.json[self.COMMON_FIELD], - ptp_parameter_db[self.COMMON_FIELD]) + self.assertEqual(response.json[self.PARAMETER_FIELD], + ptp_parameter_db[self.PARAMETER_FIELD]) - def _create_ptp_parameter_failed(self, name, value, type, foreign_uuid, - status_code, error_message): - ptp_parameter_db = self.get_post_object(name=name, - value=value, - type=type, - foreign_uuid=foreign_uuid) - response = self.post_json(self.API_PREFIX, ptp_parameter_db, + def _create_ptp_parameter_failed(self, name, value, status_code, + error_message): + ptp_parameter_db = self.get_post_parameter(name=name, + value=value) + response = self.post_json(self.PARAMETER_PREFIX, ptp_parameter_db, headers=self.API_HEADERS, expect_errors=True) self.assertEqual('application/json', response.content_type) self.assertEqual(response.status_code, status_code) @@ -97,62 +102,217 @@ class TestCreatePtpParameter(BasePtpParameterTestCase): def test_create_ptp_parameter_instance_ok(self): self._create_ptp_parameter_success( - name='instance-param', value='instance-value', - type=constants.PTP_PARAMETER_OWNER_INSTANCE, - foreign_uuid=self.ptp_instances[0].uuid) + name='instance-param', value='instance-value') def test_create_ptp_parameter_interface_ok(self): self._create_ptp_parameter_success( - name='interface-param', value='interface-value', - type=constants.PTP_PARAMETER_OWNER_INTERFACE, - foreign_uuid=self.ptp_interfaces[0].uuid) - - def test_create_ptp_parameter_invalid_type(self): - self._create_ptp_parameter_failed( - name='fake-param', value='fake-value', - type='invalid', - foreign_uuid=self.ptp_instances[0].uuid, - status_code=http_client.BAD_REQUEST, - error_message='Invalid input for field/attribute type') - - def test_create_ptp_parameter_invalid_uuid(self): - bad_uuid = 'f4c56ddf-aef3-46ed-b9aa-126a1faafd40' - error_message = 'No foreign object found with id %s' % bad_uuid - self._create_ptp_parameter_failed( - name='fake-param', value='fake-value', - type=constants.PTP_PARAMETER_OWNER_INSTANCE, - foreign_uuid=bad_uuid, - status_code=http_client.BAD_REQUEST, - error_message=error_message) + name='interface-param', value='interface-value') def test_create_ptp_parameter_duplicate(self): self._create_ptp_parameter_failed( name=self.name, - value='another-value', - type=constants.PTP_PARAMETER_OWNER_INSTANCE, - foreign_uuid=self.foreign_uuid, + value=self.value, status_code=http_client.CONFLICT, error_message='already exists') +class TestSetPtpParameter(BasePtpParameterTestCase): + name = 'test-param' + value = 'test-value' + parameter_uuid = None + owner_uuid = None + + def setUp(self): + super(TestSetPtpParameter, self).setUp() + self.owner_uuid = self.ptp_instances[0].uuid + ptp_parameter_db = dbutils.create_test_ptp_parameter(name=self.name, + value=self.value) + self.parameter_uuid = ptp_parameter_db['uuid'] + response = self.get_json(self.get_parameter_url(self.parameter_uuid)) + self.assertIn(self.PARAMETER_FIELD, response) + + ptp_ownership_db = dbutils.create_test_ptp_ownership( + parameter_uuid=self.parameter_uuid, + owner_uuid=self.owner_uuid) + ownership_uuid = ptp_ownership_db['uuid'] + response = self.get_json(self.get_ownership_url(ownership_uuid)) + self.assertIn(self.OWNERSHIP_FIELD, response) + + def _set_ptp_parameter(self, name, value): + ptp_parameter_db = dbutils.create_test_ptp_parameter(name=name, + value=value) + return ptp_parameter_db['uuid'] + + def _set_ptp_ownership_success(self, name, value, owner_uuid): + parameter_uuid = self._set_ptp_parameter(name, value) + + ptp_ownership_db = self.get_post_ownership( + parameter_uuid=parameter_uuid, + owner_uuid=owner_uuid) + response = self.post_json(self.OWNERSHIP_PREFIX, ptp_ownership_db, + headers=self.API_HEADERS) + self.assertEqual('application/json', response.content_type) + self.assertEqual(response.status_code, http_client.OK) + self.assertEqual(response.json[self.OWNERSHIP_FIELD], + ptp_ownership_db[self.OWNERSHIP_FIELD]) + + def _set_ptp_ownership_failed(self, name, value, owner_uuid, + status_code, error_message): + parameter_uuid = self._set_ptp_parameter(name, value) + + ptp_ownership_db = self.get_post_ownership( + parameter_uuid=parameter_uuid, + owner_uuid=owner_uuid) + response = self.post_json(self.OWNERSHIP_PREFIX, ptp_ownership_db, + headers=self.API_HEADERS, expect_errors=True) + self.assertEqual('application/json', response.content_type) + self.assertEqual(response.status_code, status_code) + self.assertIn(error_message, response.json['error_message']) + + def test_set_ptp_parameter_instance_ok(self): + self._set_ptp_ownership_success( + name='instance-param', value='instance-value', + owner_uuid=self.ptp_instances[0].uuid) + + def test_set_ptp_parameter_interface_ok(self): + self._set_ptp_ownership_success( + name='interface-param', value='interface-value', + owner_uuid=self.ptp_interfaces[0].uuid) + + def test_set_ptp_parameter_duplicate(self): + ptp_ownership_db = self.get_post_ownership( + parameter_uuid=self.parameter_uuid, + owner_uuid=self.owner_uuid) + response = self.post_json(self.OWNERSHIP_PREFIX, ptp_ownership_db, + headers=self.API_HEADERS, expect_errors=True) + self.assertEqual('application/json', response.content_type) + self.assertEqual(response.status_code, http_client.CONFLICT) + self.assertIn('already a PTP parameter', + response.json['error_message']) + + def test_set_ptp_parameter_invalid_param(self): + bad_uuid = 'f4c56ddf-aef3-46ed-b9aa-126a1faafd40' + error_message = 'No PTP parameter object found with id %s' % bad_uuid + + ptp_ownership_db = self.get_post_ownership( + parameter_uuid=bad_uuid, + owner_uuid=self.owner_uuid) + response = self.post_json(self.OWNERSHIP_PREFIX, ptp_ownership_db, + headers=self.API_HEADERS, expect_errors=True) + self.assertEqual('application/json', response.content_type) + self.assertEqual(response.status_code, http_client.BAD_REQUEST) + self.assertIn(error_message, response.json['error_message']) + + def test_set_ptp_parameter_invalid_owner_uuid(self): + bad_uuid = 'f4c56ddf-aef3-46ed-b9aa-126a1faafd40' + error_message = 'No PTP parameter owner found with id %s' % bad_uuid + self._set_ptp_ownership_failed( + name='fake-param', value='fake-value', + owner_uuid=bad_uuid, + status_code=http_client.BAD_REQUEST, + error_message=error_message) + + +class TestUnsetPtpParameter(BasePtpParameterTestCase): + def setUp(self): + super(TestUnsetPtpParameter, self).setUp() + + def test_unset_ptp_parameter_instance(self): + owner_uuid = self.ptp_instances[0].uuid + ptp_parameter = dbutils.create_test_ptp_parameter( + name='instance-param', value='instance-value') + ptp_ownership = dbutils.create_test_ptp_ownership( + parameter_uuid=ptp_parameter['uuid'], + owner_uuid=owner_uuid) + uuid = ptp_ownership['uuid'] + + response = self.delete(self.get_ownership_url(uuid), + headers=self.API_HEADERS) + self.assertEqual(response.status_code, http_client.NO_CONTENT) + + # Double check the ownership was removed + error_message = 'No PTP parameter ownership with id %s found' % uuid + response = self.get_json(self.get_ownership_url(uuid), + expect_errors=True) + self.assertEqual('application/json', response.content_type) + self.assertEqual(response.status_code, http_client.NOT_FOUND) + self.assertIn(error_message, response.json['error_message']) + + response = self.get_json(self.get_instance_scoped_url(owner_uuid)) + self.assertEqual([], response[self.PARAMETER_KEY]) + + def test_unset_ptp_parameter_interface(self): + owner_uuid = self.ptp_interfaces[0].uuid + ptp_parameter = dbutils.create_test_ptp_parameter( + name='interface-param', value='interface-value') + ptp_ownership = dbutils.create_test_ptp_ownership( + parameter_uuid=ptp_parameter['uuid'], + owner_uuid=owner_uuid) + uuid = ptp_ownership['uuid'] + + response = self.delete(self.get_ownership_url(uuid), + headers=self.API_HEADERS) + self.assertEqual(response.status_code, http_client.NO_CONTENT) + + # Double check the ownership was removed + error_message = 'No PTP parameter ownership with id %s found' % uuid + response = self.get_json(self.get_ownership_url(uuid), + expect_errors=True) + self.assertEqual('application/json', response.content_type) + self.assertEqual(response.status_code, http_client.NOT_FOUND) + self.assertIn(error_message, response.json['error_message']) + + response = self.get_json(self.get_interface_scoped_url(owner_uuid)) + self.assertEqual([], response[self.PARAMETER_KEY]) + + class TestGetPtpParameter(BasePtpParameterTestCase): + name = 'test-param' + value = 'test-value' + type = constants.PTP_PARAMETER_OWNER_INSTANCE + parameter_uuid = None + owner_uuid = None + def setUp(self): super(TestGetPtpParameter, self).setUp() + self.owner_uuid = self.ptp_instances[0].uuid + ptp_parameter_db = dbutils.create_test_ptp_parameter(name=self.name, + value=self.value) + self.parameter_uuid = ptp_parameter_db['uuid'] + response = self.get_json(self.get_parameter_url(self.parameter_uuid)) + self.assertIn(self.PARAMETER_FIELD, response) def test_get_ptp_parameter_found(self): ptp_parameter = dbutils.create_test_ptp_parameter( - name='fake-param', value='fake-value', - type=constants.PTP_PARAMETER_OWNER_INSTANCE, - foreign_uuid=self.ptp_instances[0].uuid) + name='fake-param', value='fake-value') uuid = ptp_parameter['uuid'] - response = self.get_json(self.get_single_url(uuid)) - self.assertIn(self.COMMON_FIELD, response) + response = self.get_json(self.get_parameter_url(uuid)) + self.assertIn(self.PARAMETER_FIELD, response) def test_get_ptp_parameter_not_found(self): fake_uuid = 'f4c56ddf-aef3-46ed-b9aa-126a1faafd40' error_message = 'No PTP parameter with id %s found' % fake_uuid - response = self.get_json(self.get_single_url(fake_uuid), + response = self.get_json(self.get_parameter_url(fake_uuid), + expect_errors=True) + self.assertEqual('application/json', response.content_type) + self.assertEqual(response.status_code, http_client.NOT_FOUND) + self.assertIn(error_message, response.json['error_message']) + + def test_get_ptp_parameter_owner_found(self): + ptp_ownership = dbutils.create_test_ptp_ownership( + parameter_uuid=self.parameter_uuid, + owner_uuid=self.owner_uuid) + uuid = ptp_ownership['uuid'] + response = self.get_json(self.get_ownership_url(uuid)) + self.assertIn(self.OWNERSHIP_FIELD, response) + + def test_get_ptp_parameter_owner_not_found(self): + fake_uuid = 'f4c56ddf-aef3-46ed-b9aa-126a1faafd40' + error_message = \ + 'No PTP parameter ownership with id %s found' % fake_uuid + + response = self.get_json(self.get_ownership_url(fake_uuid), expect_errors=True) self.assertEqual('application/json', response.content_type) self.assertEqual(response.status_code, http_client.NOT_FOUND) @@ -163,84 +323,62 @@ class TestListPtpParameter(BasePtpParameterTestCase): def setUp(self): super(TestListPtpParameter, self).setUp() self._create_test_ptp_parameters( - type=constants.PTP_PARAMETER_OWNER_INSTANCE, - prefix='ptp') + prefix='ptp', + type=constants.PTP_PARAMETER_OWNER_INSTANCE) self._create_test_ptp_parameters( - type=constants.PTP_PARAMETER_OWNER_INTERFACE, - prefix='iface') + prefix='iface', + type=constants.PTP_PARAMETER_OWNER_INTERFACE) - def _create_test_ptp_parameters(self, type, prefix='test', - foreign_uuid=None): + def _create_test_ptp_parameters(self, prefix='test', + owner_uuid=None, type=None): parameters = [] + ownerships = [] - if not foreign_uuid: + if not owner_uuid: if type == constants.PTP_PARAMETER_OWNER_INSTANCE: - foreign_uuid = self.ptp_instances[0].uuid + owner_uuid = self.ptp_instances[0].uuid elif type == constants.PTP_PARAMETER_OWNER_INTERFACE: - foreign_uuid = self.ptp_interfaces[0].uuid + owner_uuid = self.ptp_interfaces[0].uuid else: - return parameters + return parameters, ownerships for i in range(2): name = '%s-name%s' % (prefix, i) value = '%s-value%s' % (prefix, i) - parameter = dbutils.create_test_ptp_parameter( - name=name, value=value, type=type, foreign_uuid=foreign_uuid) + parameter = dbutils.create_test_ptp_parameter(name=name, + value=value) parameters.append(parameter) - return parameters + + ownership = dbutils.create_test_ptp_ownership( + parameter_uuid=parameter['uuid'], + owner_uuid=owner_uuid) + ownerships.append(ownership) + + return parameters, ownerships def test_list_ptp_parameter_all(self): - response = self.get_json(self.API_PREFIX) - for result in response[self.RESULT_KEY]: - self.assertIn(self.COMMON_FIELD, result) + response = self.get_json(self.PARAMETER_PREFIX) + for result in response[self.PARAMETER_KEY]: + self.assertIn(self.PARAMETER_FIELD, result) def test_list_ptp_parameter_empty(self): fake_uuid = 'f4c56ddf-aef3-46ed-b9aa-126a1faafd40' response = self.get_json(self.get_instance_scoped_url(fake_uuid)) - self.assertEqual([], response[self.RESULT_KEY]) - - def test_list_ptp_parameter_by_type(self): - self._create_test_ptp_parameters( - constants.PTP_PARAMETER_OWNER_INSTANCE, - foreign_uuid=self.ptp_instances[1].uuid) - """ - TODO: needs investigation of the reason to get this: - webtest.app.AppError: Bad response: 400 Bad Request (not 200 OK or 3xx - redirect for http:// - localhost/v1/ptp_parameters?q.field=type&q.value=ptp-instance&q.op=eq) - '{"error_message": "{\\"debuginfo\\": null, \\"faultcode\\": - \\"Client\\", \\"faultstring\\": \\"Unknown argument: \\\\\\"q.field, - q.value, q.op\\\\\\"\\"}"}' - query = [{ - 'field': 'type', - 'value': constants.PTP_PARAMETER_OWNER_INSTANCE, - 'op': 'eq' - }] - response = self.get_json(self.API_PREFIX, q=query) - for result in response[self.RESULT_KEY]: - self.assertEqual(constants.PTP_PARAMETER_OWNER_INSTANCE, - result['type']) - """ + self.assertEqual([], response[self.PARAMETER_KEY]) def test_list_ptp_parameter_by_instance(self): - self._create_test_ptp_parameters( - constants.PTP_PARAMETER_OWNER_INSTANCE, - foreign_uuid=self.ptp_instances[1].uuid) - response = self.get_json(self.get_instance_scoped_url( - self.ptp_instances[1].uuid)) - for result in response[self.RESULT_KEY]: - self.assertEqual(self.ptp_instances[1].uuid, - result['foreign_uuid']) + uuid = self.ptp_instances[1].uuid + self._create_test_ptp_parameters(owner_uuid=uuid) + response = self.get_json(self.get_instance_scoped_url(uuid)) + for result in response[self.PARAMETER_KEY]: + self.assertIn(uuid, str(result['owners'])) def test_list_ptp_parameter_by_interface(self): - self._create_test_ptp_parameters( - constants.PTP_PARAMETER_OWNER_INTERFACE, - foreign_uuid=self.ptp_interfaces[1].uuid) - response = self.get_json(self.get_interface_scoped_url( - self.ptp_interfaces[1].uuid)) - for result in response[self.RESULT_KEY]: - self.assertEqual(self.ptp_interfaces[1].uuid, - result['foreign_uuid']) + uuid = self.ptp_interfaces[1].uuid + self._create_test_ptp_parameters(owner_uuid=uuid) + response = self.get_json(self.get_interface_scoped_url(uuid)) + for result in response[self.PARAMETER_KEY]: + self.assertIn(uuid, str(result['owners'])) class TestUpdatePtpParameter(BasePtpParameterTestCase): @@ -249,12 +387,10 @@ class TestUpdatePtpParameter(BasePtpParameterTestCase): def test_update_ptp_parameter(self): ptp_parameter = dbutils.create_test_ptp_parameter( - name='fake-param', value='fake-value', - type=constants.PTP_PARAMETER_OWNER_INSTANCE, - foreign_uuid=self.ptp_instances[0].uuid) + name='fake-param', value='fake-value') uuid = ptp_parameter['uuid'] - response = self.patch_json(self.get_single_url(uuid), + response = self.patch_json(self.get_parameter_url(uuid), [{'path': '/value', 'value': 'changed-value', 'op': 'replace'}], @@ -263,7 +399,7 @@ class TestUpdatePtpParameter(BasePtpParameterTestCase): self.assertEqual(response.status_code, http_client.OK) # Check the parameter was indeed updated - response = self.get_json(self.get_single_url(uuid)) + response = self.get_json(self.get_parameter_url(uuid)) self.assertEqual(response['value'], 'changed-value') @@ -277,21 +413,32 @@ class TestDeletePtpParameter(BasePtpParameterTestCase): def setUp(self): super(TestDeletePtpParameter, self).setUp() - def test_delete_ptp_parameter(self): + def test_delete_ptp_parameter_ok(self): ptp_parameter = dbutils.create_test_ptp_parameter( - name='fake-param', value='fake-value', - type=constants.PTP_PARAMETER_OWNER_INSTANCE, - foreign_uuid=self.ptp_instances[0].uuid) + name='fake-param', value='fake-value') uuid = ptp_parameter['uuid'] - - response = self.delete(self.get_single_url(uuid), + response = self.delete(self.get_parameter_url(uuid), headers=self.API_HEADERS) self.assertEqual(response.status_code, http_client.NO_CONTENT) - # Check the instance was indeed removed + # Check the parameter was indeed removed error_message = 'No PTP parameter with id %s found' % uuid - response = self.get_json(self.get_single_url(uuid), + response = self.get_json(self.get_parameter_url(uuid), expect_errors=True) self.assertEqual('application/json', response.content_type) self.assertEqual(response.status_code, http_client.NOT_FOUND) self.assertIn(error_message, response.json['error_message']) + + def test_delete_ptp_parameter_with_owner_failed(self): + ptp_parameter = dbutils.create_test_ptp_parameter( + name='fake-param', value='fake-value') + uuid = ptp_parameter['uuid'] + owner_uuid = self.ptp_instances[0].uuid + dbutils.create_test_ptp_ownership(parameter_uuid=uuid, + owner_uuid=owner_uuid) + + response = self.delete(self.get_parameter_url(uuid), + headers=self.API_HEADERS, expect_errors=True) + self.assertEqual('application/json', response.content_type) + self.assertEqual(response.status_code, http_client.BAD_REQUEST) + self.assertIn('still associated with ', response.json['error_message']) diff --git a/sysinv/sysinv/sysinv/sysinv/tests/db/base.py b/sysinv/sysinv/sysinv/sysinv/tests/db/base.py index 87c7fba309..f40957dd28 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/db/base.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/db/base.py @@ -447,7 +447,7 @@ class BaseHostTestCase(BaseSystemTestCase): index = index + 1 return ifaces - def _create_test_ptp_instance(self, host): + def _create_test_ptp_instance(self): services = [constants.PTP_INSTANCE_TYPE_PTP4L, constants.PTP_INSTANCE_TYPE_PHC2SYS] names = [constants.PTP_INSTANCE_DEFAULT_PTP4L, @@ -455,18 +455,16 @@ class BaseHostTestCase(BaseSystemTestCase): ptp_instances = [] for svc, nm in zip(services, names): instance = dbutils.create_test_ptp_instance( - name=nm, service=svc, host_id=host['id']) + name=nm, service=svc) ptp_instances.append(instance) return ptp_instances def _create_test_ptp_interface(self, - ptp_instances, - platform_interfaces): + ptp_instances): ptp_interfaces = [] for ptp_instance in ptp_instances: ptp_interface = dbutils.create_test_ptp_interface( - ptp_instance_id=ptp_instance['id'], - interface_id=platform_interfaces[0]['id']) + ptp_instance_id=ptp_instance['id']) ptp_interfaces.append(ptp_interface) return ptp_interfaces diff --git a/sysinv/sysinv/sysinv/sysinv/tests/db/sqlalchemy/test_migrations.py b/sysinv/sysinv/sysinv/sysinv/tests/db/sqlalchemy/test_migrations.py index 60ea7ec928..bc25439f04 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/db/sqlalchemy/test_migrations.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/db/sqlalchemy/test_migrations.py @@ -1988,18 +1988,46 @@ class TestMigrations(BaseMigrationTestCase, WalkVersionsMixin): getattr(sqlalchemy.types, coltype))) def _check_120(self, engine, data): - ptp_instances = db_utils.get_table(engine, 'ptp_instances') - ptp_instance_columns = { + ptp_parameters = db_utils.get_table(engine, 'ptp_parameters') + ptp_parameters_columns = { 'created_at': 'DateTime', 'updated_at': 'DateTime', 'deleted_at': 'DateTime', 'id': 'Integer', 'uuid': 'String', 'name': 'String', - 'service': 'String', - 'host_id': 'Integer', + 'value': 'String' + } + for column, column_type in ptp_parameters_columns.items(): + self.assertTrue( + isinstance(ptp_parameters.c[column].type, + getattr(sqlalchemy.types, column_type))) + + ptp_parameter_owners = db_utils.get_table(engine, + 'ptp_parameter_owners') + ptp_parameter_owner_columns = { + 'created_at': 'DateTime', + 'updated_at': 'DateTime', + 'deleted_at': 'DateTime', + 'id': 'Integer', + 'uuid': 'String', + 'type': 'String', 'capabilities': 'Text' } + for column, column_type in ptp_parameter_owner_columns.items(): + self.assertTrue( + isinstance(ptp_parameter_owners.c[column].type, + getattr(sqlalchemy.types, column_type))) + + ptp_instances = db_utils.get_table(engine, 'ptp_instances') + ptp_instance_columns = { + 'created_at': 'DateTime', + 'updated_at': 'DateTime', + 'deleted_at': 'DateTime', + 'id': 'Integer', + 'name': 'String', + 'service': 'String' + } for column, column_type in ptp_instance_columns.items(): self.assertTrue( isinstance(ptp_instances.c[column].type, @@ -2011,29 +2039,25 @@ class TestMigrations(BaseMigrationTestCase, WalkVersionsMixin): 'updated_at': 'DateTime', 'deleted_at': 'DateTime', 'id': 'Integer', - 'uuid': 'String', - 'interface_id': 'Integer', - 'ptp_instance_id': 'Integer', - 'capabilities': 'Text' + 'ptp_instance_id': 'Integer' } for column, column_type in ptp_interface_columns.items(): self.assertTrue( isinstance(ptp_interfaces.c[column].type, getattr(sqlalchemy.types, column_type))) - ptp_parameters = db_utils.get_table(engine, 'ptp_parameters') - ptp_parameters_columns = { + ptp_parameter_ownerships = db_utils.get_table( + engine, 'ptp_parameter_ownerships') + ptp_parameter_ownership_columns = { 'created_at': 'DateTime', 'updated_at': 'DateTime', 'deleted_at': 'DateTime', 'id': 'Integer', 'uuid': 'String', - 'name': 'String', - 'value': 'String', - 'type': 'String', - 'foreign_uuid': 'String', + 'parameter_uuid': 'String', + 'owner_uuid': 'String' } - for column, column_type in ptp_parameters_columns.items(): + for column, column_type in ptp_parameter_ownership_columns.items(): self.assertTrue( - isinstance(ptp_parameters.c[column].type, + isinstance(ptp_parameter_ownerships.c[column].type, getattr(sqlalchemy.types, column_type))) diff --git a/sysinv/sysinv/sysinv/sysinv/tests/db/utils.py b/sysinv/sysinv/sysinv/sysinv/tests/db/utils.py index fec3ad7dd4..232e966a8b 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/db/utils.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/db/utils.py @@ -539,22 +539,16 @@ def create_test_ptp(**kw): # Utility functions to create a PTP instance for testing def get_test_ptp_instance(**kw): instance = { - 'id': kw.get('id'), - 'uuid': kw.get('uuid'), - 'name': kw.get('name', None), - 'service': kw.get('service', constants.PTP_INSTANCE_TYPE_PTP4L), - 'host_id': kw.get('host_id', None) + # TODO: check why this is needed for this specific child class/table + 'type': kw.get('type', constants.PTP_PARAMETER_OWNER_INSTANCE), + 'name': kw.get('name'), + 'service': kw.get('service', constants.PTP_INSTANCE_TYPE_PTP4L) } return instance def create_test_ptp_instance(**kw): instance = get_test_ptp_instance(**kw) - # Let DB generate ID if isn't specified - if 'id' not in kw: - del instance['id'] - if 'uuid' in kw: - del instance['uuid'] dbapi = db_api.get_instance() return dbapi.ptp_instance_create(instance) @@ -562,17 +556,14 @@ def create_test_ptp_instance(**kw): # Create test ptp_interface object def get_test_ptp_interface(**kw): ptp_interface = { - 'uuid': kw.get('uuid'), - 'interface_id': kw.get('interface_id'), - 'ptp_instance_id': kw.get('ptp_instance_id') + 'ptp_instance_id': kw.get('ptp_instance_id'), + 'ptp_instance_uuid': kw.get('ptp_instance_uuid', None) } return ptp_interface def create_test_ptp_interface(**kw): ptp_interface = get_test_ptp_interface(**kw) - if 'uuid' in kw: - del ptp_interface['uuid'] dbapi = db_api.get_instance() return dbapi.ptp_interface_create(ptp_interface) @@ -580,27 +571,32 @@ def create_test_ptp_interface(**kw): # Utility functions to create a PTP parameter for testing def get_test_ptp_parameter(**kw): parameter = { - 'id': kw.get('id'), - 'uuid': kw.get('uuid'), - 'name': kw.get('name', None), - 'value': kw.get('value', None), - 'type': kw.get('type', None), - 'foreign_uuid': kw.get('foreign_uuid', None) + 'name': kw.get('name'), + 'value': kw.get('value', None) } return parameter def create_test_ptp_parameter(**kw): parameter = get_test_ptp_parameter(**kw) - # Let DB generate ID if isn't specified - if 'id' not in kw: - del parameter['id'] - if 'uuid' in kw: - del parameter['uuid'] dbapi = db_api.get_instance() return dbapi.ptp_parameter_create(parameter) +def get_test_ptp_ownership(**kw): + ownership = { + 'parameter_uuid': kw.get('parameter_uuid', None), + 'owner_uuid': kw.get('owner_uuid', None) + } + return ownership + + +def create_test_ptp_ownership(**kw): + ownership = get_test_ptp_ownership(**kw) + dbapi = db_api.get_instance() + return dbapi.ptp_parameter_set_owner(ownership) + + # Create test dns object def get_test_dns(**kw): dns = {