Merge "[PTP dual NIC config] PTP parameter: CLI, REST API"
This commit is contained in:
commit
da6d199d95
@ -71,6 +71,7 @@ from cgtsclient.v1 import port
|
|||||||
from cgtsclient.v1 import ptp
|
from cgtsclient.v1 import ptp
|
||||||
from cgtsclient.v1 import ptp_instance
|
from cgtsclient.v1 import ptp_instance
|
||||||
from cgtsclient.v1 import ptp_interface
|
from cgtsclient.v1 import ptp_interface
|
||||||
|
from cgtsclient.v1 import ptp_parameter
|
||||||
from cgtsclient.v1 import registry_image
|
from cgtsclient.v1 import registry_image
|
||||||
from cgtsclient.v1 import remotelogging
|
from cgtsclient.v1 import remotelogging
|
||||||
from cgtsclient.v1 import restore
|
from cgtsclient.v1 import restore
|
||||||
@ -122,6 +123,7 @@ class Client(http.HTTPClient):
|
|||||||
self.ptp = ptp.ptpManager(self)
|
self.ptp = ptp.ptpManager(self)
|
||||||
self.ptp_instance = ptp_instance.PtpInstanceManager(self)
|
self.ptp_instance = ptp_instance.PtpInstanceManager(self)
|
||||||
self.ptp_interface = ptp_interface.PtpInterfaceManager(self)
|
self.ptp_interface = ptp_interface.PtpInterfaceManager(self)
|
||||||
|
self.ptp_parameter = ptp_parameter.PtpParameterManager(self)
|
||||||
self.iextoam = iextoam.iextoamManager(self)
|
self.iextoam = iextoam.iextoamManager(self)
|
||||||
self.controller_fs = controller_fs.ControllerFsManager(self)
|
self.controller_fs = controller_fs.ControllerFsManager(self)
|
||||||
self.storage_backend = storage_backend.StorageBackendManager(self)
|
self.storage_backend = storage_backend.StorageBackendManager(self)
|
||||||
|
@ -25,10 +25,6 @@ def _print_ptp_instance_show(ptp_instance_obj):
|
|||||||
def do_ptp_instance_list(cc, args):
|
def do_ptp_instance_list(cc, args):
|
||||||
"""List all PTP instances, in any host."""
|
"""List all PTP instances, in any host."""
|
||||||
ptp_instances = cc.ptp_instance.list()
|
ptp_instances = cc.ptp_instance.list()
|
||||||
for instance in ptp_instances[:]:
|
|
||||||
ihost = ihost_utils._find_ihost(cc, instance.host_uuid)
|
|
||||||
setattr(instance, 'hostname', ihost.hostname)
|
|
||||||
|
|
||||||
field_labels = ['uuid', 'name', 'service', 'hostname']
|
field_labels = ['uuid', 'name', 'service', 'hostname']
|
||||||
fields = ['uuid', 'name', 'service', 'hostname']
|
fields = ['uuid', 'name', 'service', 'hostname']
|
||||||
utils.print_list(ptp_instances, fields, field_labels)
|
utils.print_list(ptp_instances, fields, field_labels)
|
||||||
@ -53,8 +49,6 @@ def do_host_ptp_instance_list(cc, args):
|
|||||||
def do_ptp_instance_show(cc, args):
|
def do_ptp_instance_show(cc, args):
|
||||||
"""Show PTP instance attributes."""
|
"""Show PTP instance attributes."""
|
||||||
ptp_instance = ptp_instance_utils._find_ptp_instance(cc, args.nameoruuid)
|
ptp_instance = ptp_instance_utils._find_ptp_instance(cc, args.nameoruuid)
|
||||||
ihost = ihost_utils._find_ihost(cc, ptp_instance.host_uuid)
|
|
||||||
setattr(ptp_instance, 'hostname', ihost.hostname)
|
|
||||||
_print_ptp_instance_show(ptp_instance)
|
_print_ptp_instance_show(ptp_instance)
|
||||||
|
|
||||||
|
|
||||||
@ -87,8 +81,6 @@ def do_ptp_instance_add(cc, args):
|
|||||||
except exc.HTTPNotFound:
|
except exc.HTTPNotFound:
|
||||||
raise exc.CommandError('PTP instance just created not found: %s' %
|
raise exc.CommandError('PTP instance just created not found: %s' %
|
||||||
uuid)
|
uuid)
|
||||||
if ptp_instance:
|
|
||||||
setattr(ptp_instance, 'hostname', ihost.hostname)
|
|
||||||
_print_ptp_instance_show(ptp_instance)
|
_print_ptp_instance_show(ptp_instance)
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
########################################################################
|
||||||
|
#
|
||||||
|
# Copyright (c) 2021 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
from cgtsclient.common import base
|
||||||
|
from cgtsclient import exc
|
||||||
|
from cgtsclient.v1 import options
|
||||||
|
|
||||||
|
|
||||||
|
CREATION_ATTRIBUTES = ['name', 'value', 'type', 'foreign_uuid']
|
||||||
|
|
||||||
|
|
||||||
|
class PtpParameter(base.Resource):
|
||||||
|
def __repr__(self):
|
||||||
|
return "<PtpParameter %s>" % self._info
|
||||||
|
|
||||||
|
|
||||||
|
class PtpParameterManager(base.Manager):
|
||||||
|
resource_class = PtpParameter
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _path(ptp_parameter_id=None):
|
||||||
|
return '/v1/ptp_parameters/%s' % ptp_parameter_id if ptp_parameter_id \
|
||||||
|
else '/v1/ptp_parameters'
|
||||||
|
|
||||||
|
def list(self, q=None):
|
||||||
|
return self._list(options.build_url(self._path(), q), "ptp_parameters")
|
||||||
|
|
||||||
|
def list_by_ptp_instance(self, ptp_instance_uuid):
|
||||||
|
path = '/v1/ptp_instances/%s/ptp_parameters' % ptp_instance_uuid
|
||||||
|
return self._list(path, "ptp_parameters")
|
||||||
|
|
||||||
|
def list_by_interface(self, interface_uuid):
|
||||||
|
path = '/v1/iinterfaces/%s/ptp_parameters' % interface_uuid
|
||||||
|
return self._list(path, "ptp_parameters")
|
||||||
|
|
||||||
|
def get(self, ptp_parameter_id):
|
||||||
|
try:
|
||||||
|
return self._list(self._path(ptp_parameter_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 update(self, ptp_parameter_id, patch):
|
||||||
|
return self._update(self._path(ptp_parameter_id), patch)
|
||||||
|
|
||||||
|
def delete(self, ptp_parameter_id):
|
||||||
|
return self._delete(self._path(ptp_parameter_id))
|
||||||
|
|
||||||
|
|
||||||
|
def _find_ptp_parameter(cc, id):
|
||||||
|
try:
|
||||||
|
parameter = cc.ptp_parameter.get(id)
|
||||||
|
except exc.HTTPNotFound:
|
||||||
|
raise exc.CommandError('PTP parameter not found: %s' % id)
|
||||||
|
else:
|
||||||
|
return parameter
|
@ -0,0 +1,151 @@
|
|||||||
|
########################################################################
|
||||||
|
#
|
||||||
|
# Copyright (c) 2021 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
from cgtsclient.common import utils
|
||||||
|
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']
|
||||||
|
data = [(f, getattr(ptp_parameter_obj, f, '')) for f in fields]
|
||||||
|
utils.print_tuple_list(data, labels,
|
||||||
|
formatters={'owner': _owner_formatter})
|
||||||
|
|
||||||
|
|
||||||
|
@utils.arg('-t', '--type',
|
||||||
|
metavar='<owner type>',
|
||||||
|
choices=['ptp-instance', 'ptp-interface'],
|
||||||
|
help='List PTP parameters for a specific owner type')
|
||||||
|
@utils.arg('-u', '--foreign_uuid',
|
||||||
|
metavar='<owner uuid>',
|
||||||
|
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'])
|
||||||
|
|
||||||
|
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('uuid',
|
||||||
|
metavar='<uuid>',
|
||||||
|
help="UUID of PTP parameter")
|
||||||
|
def do_ptp_parameter_show(cc, args):
|
||||||
|
"""Show PTP parameter attributes."""
|
||||||
|
ptp_parameter = ptp_parameter_utils._find_ptp_parameter(cc, args.uuid)
|
||||||
|
_print_ptp_parameter_show(ptp_parameter)
|
||||||
|
|
||||||
|
|
||||||
|
@utils.arg('name',
|
||||||
|
metavar='<name>',
|
||||||
|
help="Name of PTP parameter [REQUIRED]")
|
||||||
|
@utils.arg('value',
|
||||||
|
metavar='<value>',
|
||||||
|
help="Value of PTP parameter [REQUIRED]")
|
||||||
|
@utils.arg('type',
|
||||||
|
metavar='<owner type>',
|
||||||
|
choices=['ptp-instance', 'ptp-interface'],
|
||||||
|
help="Type of parameter owner ('ptp-instance' or 'ptp-interface') "
|
||||||
|
"[REQUIRED]")
|
||||||
|
@utils.arg('foreign_uuid',
|
||||||
|
metavar='<owner uuid>',
|
||||||
|
help="UUID of parameter owner [REQUIRED]")
|
||||||
|
def do_ptp_parameter_add(cc, args):
|
||||||
|
"""Add a PTP parameter."""
|
||||||
|
|
||||||
|
field_list = ['name', 'value', 'type', 'foreign_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_parameter = cc.ptp_parameter.create(**data)
|
||||||
|
uuid = getattr(ptp_parameter, 'uuid', '')
|
||||||
|
try:
|
||||||
|
ptp_parameter = cc.ptp_parameter.get(uuid)
|
||||||
|
except exc.HTTPNotFound:
|
||||||
|
raise exc.CommandError('PTP parameter just created not found: %s' %
|
||||||
|
uuid)
|
||||||
|
_print_ptp_parameter_show(ptp_parameter)
|
||||||
|
|
||||||
|
|
||||||
|
@utils.arg('uuid',
|
||||||
|
metavar='<uuid>',
|
||||||
|
help="UUID of PTP parameter")
|
||||||
|
@utils.arg('value',
|
||||||
|
metavar='<new value>',
|
||||||
|
help="New value of parameter")
|
||||||
|
def do_ptp_parameter_modify(cc, args):
|
||||||
|
"""Change PTP parameter value."""
|
||||||
|
|
||||||
|
field_list = ['value']
|
||||||
|
|
||||||
|
data = dict((k, v) for (k, v) in vars(args).items()
|
||||||
|
if k in field_list and not (v is None))
|
||||||
|
|
||||||
|
patch = []
|
||||||
|
for (k, v) in data.items():
|
||||||
|
patch.append({'op': 'replace', 'path': '/' + k, 'value': v})
|
||||||
|
|
||||||
|
ptp_parameter = cc.ptp_parameter.update(args.uuid, patch)
|
||||||
|
_print_ptp_parameter_show(ptp_parameter)
|
||||||
|
|
||||||
|
|
||||||
|
@utils.arg('uuid',
|
||||||
|
metavar='<uuid>',
|
||||||
|
help="UUID of PTP parameter")
|
||||||
|
def do_ptp_parameter_delete(cc, args):
|
||||||
|
"""Delete a PTP parameter."""
|
||||||
|
cc.ptp_parameter.delete(args.uuid)
|
||||||
|
print('Deleted PTP parameter: %s' % args.uuid)
|
@ -56,6 +56,7 @@ from cgtsclient.v1 import pci_device_shell
|
|||||||
from cgtsclient.v1 import port_shell
|
from cgtsclient.v1 import port_shell
|
||||||
from cgtsclient.v1 import ptp_instance_shell
|
from cgtsclient.v1 import ptp_instance_shell
|
||||||
from cgtsclient.v1 import ptp_interface_shell
|
from cgtsclient.v1 import ptp_interface_shell
|
||||||
|
from cgtsclient.v1 import ptp_parameter_shell
|
||||||
from cgtsclient.v1 import ptp_shell
|
from cgtsclient.v1 import ptp_shell
|
||||||
from cgtsclient.v1 import registry_image_shell
|
from cgtsclient.v1 import registry_image_shell
|
||||||
from cgtsclient.v1 import remotelogging_shell
|
from cgtsclient.v1 import remotelogging_shell
|
||||||
@ -79,6 +80,7 @@ COMMAND_MODULES = [
|
|||||||
ptp_shell,
|
ptp_shell,
|
||||||
ptp_instance_shell,
|
ptp_instance_shell,
|
||||||
ptp_interface_shell,
|
ptp_interface_shell,
|
||||||
|
ptp_parameter_shell,
|
||||||
iextoam_shell,
|
iextoam_shell,
|
||||||
controller_fs_shell,
|
controller_fs_shell,
|
||||||
storage_backend_shell,
|
storage_backend_shell,
|
||||||
|
@ -67,6 +67,7 @@ from sysinv.api.controllers.v1 import port
|
|||||||
from sysinv.api.controllers.v1 import ptp
|
from sysinv.api.controllers.v1 import ptp
|
||||||
from sysinv.api.controllers.v1 import ptp_instance
|
from sysinv.api.controllers.v1 import ptp_instance
|
||||||
from sysinv.api.controllers.v1 import ptp_interface
|
from sysinv.api.controllers.v1 import ptp_interface
|
||||||
|
from sysinv.api.controllers.v1 import ptp_parameter
|
||||||
from sysinv.api.controllers.v1 import pv
|
from sysinv.api.controllers.v1 import pv
|
||||||
from sysinv.api.controllers.v1 import registry_image
|
from sysinv.api.controllers.v1 import registry_image
|
||||||
from sysinv.api.controllers.v1 import remotelogging
|
from sysinv.api.controllers.v1 import remotelogging
|
||||||
@ -154,6 +155,9 @@ class V1(base.APIBase):
|
|||||||
ptp_interfaces = [link.Link]
|
ptp_interfaces = [link.Link]
|
||||||
"Links to the ptp_interfaces resource"
|
"Links to the ptp_interfaces resource"
|
||||||
|
|
||||||
|
ptp_parameters = [link.Link]
|
||||||
|
"Links to the ptp_parameters resource"
|
||||||
|
|
||||||
iextoam = [link.Link]
|
iextoam = [link.Link]
|
||||||
"Links to the iextoam resource"
|
"Links to the iextoam resource"
|
||||||
|
|
||||||
@ -469,6 +473,13 @@ class V1(base.APIBase):
|
|||||||
bookmark=True)
|
bookmark=True)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
v1.ptp_parameters = [link.Link.make_link('self', pecan.request.host_url,
|
||||||
|
'ptp_parameters', ''),
|
||||||
|
link.Link.make_link('bookmark',
|
||||||
|
pecan.request.host_url,
|
||||||
|
'ptp_parameters', '',
|
||||||
|
bookmark=True)]
|
||||||
|
|
||||||
v1.iextoam = [link.Link.make_link('self', pecan.request.host_url,
|
v1.iextoam = [link.Link.make_link('self', pecan.request.host_url,
|
||||||
'iextoam', ''),
|
'iextoam', ''),
|
||||||
link.Link.make_link('bookmark',
|
link.Link.make_link('bookmark',
|
||||||
@ -913,6 +924,7 @@ class Controller(rest.RestController):
|
|||||||
ptp = ptp.PTPController()
|
ptp = ptp.PTPController()
|
||||||
ptp_instances = ptp_instance.PtpInstanceController()
|
ptp_instances = ptp_instance.PtpInstanceController()
|
||||||
ptp_interfaces = ptp_interface.PtpInterfaceController()
|
ptp_interfaces = ptp_interface.PtpInterfaceController()
|
||||||
|
ptp_parameters = ptp_parameter.PtpParameterController()
|
||||||
iextoam = network_oam.OAMNetworkController()
|
iextoam = network_oam.OAMNetworkController()
|
||||||
controller_fs = controller_fs.ControllerFsController()
|
controller_fs = controller_fs.ControllerFsController()
|
||||||
storage_backend = storage_backend.StorageBackendController()
|
storage_backend = storage_backend.StorageBackendController()
|
||||||
|
@ -46,6 +46,7 @@ from sysinv.api.controllers.v1 import types
|
|||||||
from sysinv.api.controllers.v1 import utils
|
from sysinv.api.controllers.v1 import utils
|
||||||
from sysinv.api.controllers.v1 import interface_network
|
from sysinv.api.controllers.v1 import interface_network
|
||||||
from sysinv.api.controllers.v1 import interface_datanetwork
|
from sysinv.api.controllers.v1 import interface_datanetwork
|
||||||
|
from sysinv.api.controllers.v1 import ptp_parameter
|
||||||
from sysinv.common import constants
|
from sysinv.common import constants
|
||||||
from sysinv.common import exception
|
from sysinv.common import exception
|
||||||
from sysinv.common import utils as cutils
|
from sysinv.common import utils as cutils
|
||||||
@ -302,6 +303,9 @@ class InterfaceController(rest.RestController):
|
|||||||
routes = route.RouteController(parent="iinterfaces")
|
routes = route.RouteController(parent="iinterfaces")
|
||||||
"Expose routes as a sub-element of interface"
|
"Expose routes as a sub-element of interface"
|
||||||
|
|
||||||
|
ptp_parameters = ptp_parameter.PtpParameterController(parent="iinterface")
|
||||||
|
"Expose PTP parameters as a sub-element of interface"
|
||||||
|
|
||||||
interface_networks = interface_network.InterfaceNetworkController(
|
interface_networks = interface_network.InterfaceNetworkController(
|
||||||
parent="iinterfaces")
|
parent="iinterfaces")
|
||||||
"Expose interface_networks as a sub-element of interface"
|
"Expose interface_networks as a sub-element of interface"
|
||||||
|
@ -15,8 +15,10 @@ from oslo_log import log
|
|||||||
from sysinv._i18n import _
|
from sysinv._i18n import _
|
||||||
from sysinv.api.controllers.v1 import base
|
from sysinv.api.controllers.v1 import base
|
||||||
from sysinv.api.controllers.v1 import collection
|
from sysinv.api.controllers.v1 import collection
|
||||||
|
from sysinv.api.controllers.v1 import ptp_parameter
|
||||||
from sysinv.api.controllers.v1 import types
|
from sysinv.api.controllers.v1 import types
|
||||||
from sysinv.api.controllers.v1 import utils
|
from sysinv.api.controllers.v1 import utils
|
||||||
|
from sysinv.common import constants
|
||||||
from sysinv.common import exception
|
from sysinv.common import exception
|
||||||
from sysinv.common import utils as cutils
|
from sysinv.common import utils as cutils
|
||||||
from sysinv import objects
|
from sysinv import objects
|
||||||
@ -53,10 +55,16 @@ class PtpInstance(base.APIBase):
|
|||||||
host_uuid = types.uuid
|
host_uuid = types.uuid
|
||||||
"UUID of the host the PTP instance is associated to"
|
"UUID of the host the PTP instance is associated to"
|
||||||
|
|
||||||
|
hostname = wtypes.text
|
||||||
|
"Name of the host the PTP instance is associated to"
|
||||||
|
|
||||||
name = wtypes.text
|
name = wtypes.text
|
||||||
"Name given to the PTP instance"
|
"Name given to the PTP instance"
|
||||||
|
|
||||||
service = wtypes.Enum(str, 'ptp4l', 'phc2sys', 'ts2phc')
|
service = wtypes.Enum(str,
|
||||||
|
constants.PTP_INSTANCE_TYPE_PTP4L,
|
||||||
|
constants.PTP_INSTANCE_TYPE_PHC2SYS,
|
||||||
|
constants.PTP_INSTANCE_TYPE_TS2PHC)
|
||||||
"Type of service of the PTP instance"
|
"Type of service of the PTP instance"
|
||||||
|
|
||||||
capabilities = {wtypes.text: utils.ValidTypes(wtypes.text,
|
capabilities = {wtypes.text: utils.ValidTypes(wtypes.text,
|
||||||
@ -76,6 +84,7 @@ class PtpInstance(base.APIBase):
|
|||||||
if not expand:
|
if not expand:
|
||||||
ptp_instance.unset_fields_except(['uuid',
|
ptp_instance.unset_fields_except(['uuid',
|
||||||
'host_uuid',
|
'host_uuid',
|
||||||
|
'hostname',
|
||||||
'name',
|
'name',
|
||||||
'service',
|
'service',
|
||||||
'capabilities',
|
'capabilities',
|
||||||
@ -114,11 +123,15 @@ LOCK_NAME = 'PtpInstanceController'
|
|||||||
class PtpInstanceController(rest.RestController):
|
class PtpInstanceController(rest.RestController):
|
||||||
"""REST controller for PTP instance."""
|
"""REST controller for PTP instance."""
|
||||||
|
|
||||||
|
ptp_parameters = ptp_parameter.PtpParameterController(
|
||||||
|
parent="ptp_instance")
|
||||||
|
"Expose PTP parameters as a sub-element of PTP instances"
|
||||||
|
|
||||||
def __init__(self, from_ihosts=False):
|
def __init__(self, from_ihosts=False):
|
||||||
self._from_ihosts = from_ihosts
|
self._from_ihosts = from_ihosts
|
||||||
|
|
||||||
def _get_ptp_instance_collection(
|
def _get_ptp_instance_collection(
|
||||||
self, host_uuid, marker=None, limit=None, sort_key=None,
|
self, host_uuid=None, marker=None, limit=None, sort_key=None,
|
||||||
sort_dir=None, expand=False, resource_url=None):
|
sort_dir=None, expand=False, resource_url=None):
|
||||||
LOG.debug("PtpInstanceController._get_ptp_instance_collection: "
|
LOG.debug("PtpInstanceController._get_ptp_instance_collection: "
|
||||||
"from_ihosts %s host_uuid %s" % (self._from_ihosts,
|
"from_ihosts %s host_uuid %s" % (self._from_ihosts,
|
||||||
@ -186,6 +199,13 @@ class PtpInstanceController(rest.RestController):
|
|||||||
ptp_instance_dict = ptp_instance.as_dict()
|
ptp_instance_dict = ptp_instance.as_dict()
|
||||||
LOG.debug("PtpInstanceController.post: %s" % ptp_instance_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
|
# Replace host UUID by host ID
|
||||||
host_uuid = ptp_instance_dict.pop('host_uuid')
|
host_uuid = ptp_instance_dict.pop('host_uuid')
|
||||||
try:
|
try:
|
||||||
@ -195,8 +215,8 @@ class PtpInstanceController(rest.RestController):
|
|||||||
raise wsme.exc.ClientSideError(msg)
|
raise wsme.exc.ClientSideError(msg)
|
||||||
|
|
||||||
ptp_instance_dict['host_id'] = ihost_obj['id']
|
ptp_instance_dict['host_id'] = ihost_obj['id']
|
||||||
result = pecan.request.dbapi.ptp_instance_create(ptp_instance_dict)
|
return PtpInstance.convert_with_links(
|
||||||
return PtpInstance.convert_with_links(result)
|
pecan.request.dbapi.ptp_instance_create(ptp_instance_dict))
|
||||||
|
|
||||||
@cutils.synchronized(LOCK_NAME)
|
@cutils.synchronized(LOCK_NAME)
|
||||||
@wsme_pecan.wsexpose(None, types.uuid, status_code=204)
|
@wsme_pecan.wsexpose(None, types.uuid, status_code=204)
|
||||||
@ -208,14 +228,24 @@ class PtpInstanceController(rest.RestController):
|
|||||||
|
|
||||||
# Only allow delete if there are no associated interfaces and
|
# Only allow delete if there are no associated interfaces and
|
||||||
# parameters
|
# parameters
|
||||||
parameters = pecan.request.dbapi.ptp_parameters_get_by_foreign_uuid(
|
parameters = pecan.request.dbapi.ptp_parameters_get_by_owner(
|
||||||
ptp_instance_uuid)
|
ptp_instance_uuid)
|
||||||
interfaces = pecan.request.dbapi.ptp_interfaces_get_by_instance(
|
if parameters:
|
||||||
ptp_instance_uuid)
|
names = [str(p['name']) for p in parameters]
|
||||||
if parameters or interfaces:
|
|
||||||
raise wsme.exc.ClientSideError(
|
raise wsme.exc.ClientSideError(
|
||||||
_("PTP instance %s has still parameters or associated "
|
"PTP instance %s is still associated with PTP parameter(s): %s"
|
||||||
"interfaces. Check both ptp-interfaces and ptp-parameters.")
|
% (ptp_instance_uuid, names))
|
||||||
% 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))
|
||||||
|
|
||||||
|
LOG.debug("PtpInstanceController.delete: all clear for %s" %
|
||||||
|
ptp_instance_uuid)
|
||||||
pecan.request.dbapi.ptp_instance_destroy(ptp_instance_uuid)
|
pecan.request.dbapi.ptp_instance_destroy(ptp_instance_uuid)
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
import pecan
|
import pecan
|
||||||
from pecan import rest
|
from pecan import rest
|
||||||
import six
|
import six
|
||||||
|
import wsme
|
||||||
from wsme import types as wtypes
|
from wsme import types as wtypes
|
||||||
import wsmeext.pecan as wsme_pecan
|
import wsmeext.pecan as wsme_pecan
|
||||||
|
|
||||||
@ -206,8 +207,20 @@ class PtpInterfaceController(rest.RestController):
|
|||||||
def delete(self, ptp_interface_uuid):
|
def delete(self, ptp_interface_uuid):
|
||||||
"""Delete a PTP interface."""
|
"""Delete a PTP interface."""
|
||||||
try:
|
try:
|
||||||
ptp_interface = objects.ptp_interface.get_by_uuid(pecan.request.context,
|
ptp_interface = objects.ptp_interface.get_by_uuid(
|
||||||
ptp_interface_uuid)
|
pecan.request.context, ptp_interface_uuid)
|
||||||
except exception.PtpInterfaceNotFound:
|
except exception.PtpInterfaceNotFound:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
# Only allow delete if there are no associated parameters
|
||||||
|
parameters = pecan.request.dbapi.ptp_parameters_get_by_owner(
|
||||||
|
ptp_interface_uuid)
|
||||||
|
if parameters:
|
||||||
|
names = [str(p['name']) for p in parameters]
|
||||||
|
raise wsme.exc.ClientSideError(
|
||||||
|
"PTP interface %s has PTP parameter(s): %s"
|
||||||
|
% (ptp_interface_uuid, names))
|
||||||
|
|
||||||
|
LOG.debug("PtpInterfaceController.delete: all clear for %s" %
|
||||||
|
ptp_interface_uuid)
|
||||||
pecan.request.dbapi.ptp_interface_destroy(ptp_interface.uuid)
|
pecan.request.dbapi.ptp_interface_destroy(ptp_interface.uuid)
|
||||||
|
262
sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ptp_parameter.py
Normal file
262
sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ptp_parameter.py
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
import jsonpatch
|
||||||
|
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.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
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class PtpParameterPatchType(types.JsonPatchType):
|
||||||
|
@staticmethod
|
||||||
|
def mandatory_attrs():
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class PtpParameter(base.APIBase):
|
||||||
|
"""API representation of a PTP parameter.
|
||||||
|
|
||||||
|
This class enforces type checking and value constraints, and converts
|
||||||
|
between the internal object model and the API representation of
|
||||||
|
a PTP parameter.
|
||||||
|
"""
|
||||||
|
|
||||||
|
created_at = wtypes.datetime.datetime
|
||||||
|
"Timestamp of creation of this PTP parameter"
|
||||||
|
|
||||||
|
updated_at = wtypes.datetime.datetime
|
||||||
|
"Timestamp of update of this PTP parameter"
|
||||||
|
|
||||||
|
id = int
|
||||||
|
"Unique ID for this PTP parameter"
|
||||||
|
|
||||||
|
uuid = types.uuid
|
||||||
|
"Unique UUID for this PTP parameter"
|
||||||
|
|
||||||
|
name = wtypes.text
|
||||||
|
"Name of PTP parameter"
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.fields = list(objects.ptp_parameter.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_parameter, expand=True):
|
||||||
|
ptp_parameter = PtpParameter(**rpc_ptp_parameter.as_dict())
|
||||||
|
if not expand:
|
||||||
|
ptp_parameter.unset_fields_except(['uuid',
|
||||||
|
'name',
|
||||||
|
'value',
|
||||||
|
'type',
|
||||||
|
'foreign_uuid',
|
||||||
|
'owner',
|
||||||
|
'created_at',
|
||||||
|
'updated_at'])
|
||||||
|
|
||||||
|
LOG.debug("PtpParameter.convert_with_links: converted %s" %
|
||||||
|
ptp_parameter.as_dict())
|
||||||
|
return ptp_parameter
|
||||||
|
|
||||||
|
|
||||||
|
class PtpParameterCollection(collection.Collection):
|
||||||
|
"""API representation of a collection of PTP parameters."""
|
||||||
|
|
||||||
|
ptp_parameters = [PtpParameter]
|
||||||
|
"A list containing PTP parameter objects"
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self._type = 'ptp_parameters'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def convert_with_links(cls, rpc_ptp_parameters, limit, url=None,
|
||||||
|
expand=False, **kwargs):
|
||||||
|
collection = PtpParameterCollection()
|
||||||
|
collection.ptp_parameters = [PtpParameter.convert_with_links(p, expand)
|
||||||
|
for p in rpc_ptp_parameters]
|
||||||
|
collection.next = collection.get_next(limit, url=url, **kwargs)
|
||||||
|
return collection
|
||||||
|
|
||||||
|
|
||||||
|
LOCK_NAME = 'PtpParameterController'
|
||||||
|
|
||||||
|
|
||||||
|
class PtpParameterController(rest.RestController):
|
||||||
|
"""REST controller for PTP parameter."""
|
||||||
|
|
||||||
|
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" %
|
||||||
|
(self._parent, parent_uuid, type))
|
||||||
|
if self._parent and not parent_uuid:
|
||||||
|
raise exception.InvalidParameterValue(_(
|
||||||
|
"Parent id not specified."))
|
||||||
|
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
|
||||||
|
@wsme_pecan.wsexpose(PtpParameter, types.uuid)
|
||||||
|
def get_one(self, ptp_parameter_uuid):
|
||||||
|
"""Retrieve a single PTP parameter."""
|
||||||
|
LOG.debug("PtpParameterController.get_one: uuid=%s" %
|
||||||
|
ptp_parameter_uuid)
|
||||||
|
try:
|
||||||
|
ptp_parameter = objects.ptp_parameter.get_by_uuid(
|
||||||
|
pecan.request.context,
|
||||||
|
ptp_parameter_uuid)
|
||||||
|
except exception.InvalidParameterValue:
|
||||||
|
raise wsme.exc.ClientSideError(
|
||||||
|
_("No PTP parameter found for %s" % ptp_parameter_uuid))
|
||||||
|
|
||||||
|
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):
|
||||||
|
"""Create a new PTP parameter."""
|
||||||
|
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')
|
||||||
|
except KeyError:
|
||||||
|
LOG.debug("PtpParameterController.post: no owner data in %s" %
|
||||||
|
ptp_parameter_dict)
|
||||||
|
|
||||||
|
result = pecan.request.dbapi.ptp_parameter_create(ptp_parameter_dict)
|
||||||
|
return PtpParameter.convert_with_links(result)
|
||||||
|
|
||||||
|
@cutils.synchronized(LOCK_NAME)
|
||||||
|
@wsme.validate(types.uuid, [PtpParameterPatchType])
|
||||||
|
@wsme_pecan.wsexpose(PtpParameter, types.uuid,
|
||||||
|
body=[PtpParameterPatchType])
|
||||||
|
def patch(self, uuid, patch):
|
||||||
|
"""Update the value of an existing PTP parameter."""
|
||||||
|
if self._parent:
|
||||||
|
raise exception.OperationNotPermitted
|
||||||
|
|
||||||
|
ptp_parameter = objects.ptp_parameter.get_by_uuid(
|
||||||
|
pecan.request.context, uuid)
|
||||||
|
|
||||||
|
patch_obj = jsonpatch.JsonPatch(patch)
|
||||||
|
try:
|
||||||
|
patched_parameter = PtpParameter(
|
||||||
|
**jsonpatch.apply_patch(ptp_parameter.as_dict(), patch_obj))
|
||||||
|
except utils.JSONPATCH_EXCEPTIONS as e:
|
||||||
|
raise exception.PatchError(patch=patch, reason=e)
|
||||||
|
|
||||||
|
# Update only the fields that have changed
|
||||||
|
for field in objects.ptp_parameter.fields:
|
||||||
|
if ptp_parameter[field] != getattr(patched_parameter, field):
|
||||||
|
ptp_parameter[field] = getattr(patched_parameter, field)
|
||||||
|
|
||||||
|
ptp_parameter.save()
|
||||||
|
return PtpParameter.convert_with_links(ptp_parameter)
|
||||||
|
|
||||||
|
@cutils.synchronized(LOCK_NAME)
|
||||||
|
@wsme_pecan.wsexpose(None, types.uuid, status_code=204)
|
||||||
|
def delete(self, ptp_parameter_uuid):
|
||||||
|
"""Delete a PTP parameter."""
|
||||||
|
LOG.debug("PtpParameterController.delete: %s" % ptp_parameter_uuid)
|
||||||
|
if self._parent:
|
||||||
|
raise exception.OperationNotPermitted
|
||||||
|
|
||||||
|
pecan.request.dbapi.ptp_parameter_destroy(ptp_parameter_uuid)
|
@ -1850,6 +1850,19 @@ PTP_TRANSPORT_UDP = 'udp'
|
|||||||
PTP_TRANSPORT_L2 = 'l2'
|
PTP_TRANSPORT_L2 = 'l2'
|
||||||
PTP_NETWORK_TRANSPORT_IEEE_802_3 = 'L2'
|
PTP_NETWORK_TRANSPORT_IEEE_802_3 = 'L2'
|
||||||
|
|
||||||
|
# PTP instance types
|
||||||
|
PTP_INSTANCE_TYPE_PTP4L = 'ptp4l'
|
||||||
|
PTP_INSTANCE_TYPE_PHC2SYS = 'phc2sys'
|
||||||
|
PTP_INSTANCE_TYPE_TS2PHC = 'ts2phc'
|
||||||
|
|
||||||
|
# PTP instances created during migration from service parameters
|
||||||
|
PTP_INSTANCE_DEFAULT_PTP4L = 'default-ptp4l'
|
||||||
|
PTP_INSTANCE_DEFAULT_PHC2SYS = 'default-phc2sys'
|
||||||
|
|
||||||
|
# PTP parameter: owner types
|
||||||
|
PTP_PARAMETER_OWNER_INSTANCE = 'ptp-instance'
|
||||||
|
PTP_PARAMETER_OWNER_INTERFACE = 'ptp-interface'
|
||||||
|
|
||||||
# Backup & Restore
|
# Backup & Restore
|
||||||
FIX_INSTALL_UUID_INTERVAL_SECS = 30
|
FIX_INSTALL_UUID_INTERVAL_SECS = 30
|
||||||
|
|
||||||
|
@ -2141,6 +2141,7 @@ class Connection(object):
|
|||||||
{
|
{
|
||||||
'name': 'domain',
|
'name': 'domain',
|
||||||
'value': '24',
|
'value': '24',
|
||||||
|
'type': 'ptp-instance',
|
||||||
'foreign_uuid': 'c2abca03-2f33-413e-b60d-85133a4a37b6'
|
'foreign_uuid': 'c2abca03-2f33-413e-b60d-85133a4a37b6'
|
||||||
}
|
}
|
||||||
:returns: A PTP parameter.
|
:returns: A PTP parameter.
|
||||||
@ -2177,18 +2178,35 @@ class Connection(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def ptp_parameters_get_by_foreign_uuid(self, uuid, limit=None, marker=None,
|
def ptp_parameters_get_by_type(self, type, limit=None, marker=None,
|
||||||
sort_key=None, sort_dir=None):
|
sort_key=None, sort_dir=None):
|
||||||
"""Returns a list of PTP parameters for a given foreign UUID.
|
"""Returns a list of all PTP parameters for a given owner type.
|
||||||
|
|
||||||
:param uuid: The uuid of a PTP instance or PTP interface association.
|
:param type: Type of the parameter owner (either 'ptp-instance' or
|
||||||
|
'ptp-interface')
|
||||||
:param limit: Maximum number of PTP parameters to return.
|
:param limit: Maximum number of PTP parameters to return.
|
||||||
:param marker: The last item of the previous page; we return the next
|
:param marker: The last item of the previous page; we return the next
|
||||||
result set.
|
result set.
|
||||||
:param sort_key: Attribute by which results should be sorted
|
:param sort_key: Attribute by which results should be sorted
|
||||||
:param sort_dir: direction in which results should be sorted
|
:param sort_dir: direction in which results should be sorted
|
||||||
(asc, desc)
|
(asc, desc)
|
||||||
:returns: A list of PTP parameters.
|
:returns: A list of PTP parameters for a specific owner type.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def ptp_parameters_get_by_owner(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.
|
||||||
|
|
||||||
|
:param uuid: UUID of the parameter owner.
|
||||||
|
:param limit: Maximum number of PTP parameters 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 parameters of the specified owner.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
|
@ -1178,6 +1178,43 @@ def add_deviceimage_filter(query, value):
|
|||||||
return add_identity_filter(query, value, use_name=True)
|
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):
|
class Connection(api.Connection):
|
||||||
"""SqlAlchemy connection."""
|
"""SqlAlchemy connection."""
|
||||||
|
|
||||||
@ -3758,7 +3795,7 @@ class Connection(api.Connection):
|
|||||||
query = model_query(models.PtpInstances)
|
query = model_query(models.PtpInstances)
|
||||||
if name is not None:
|
if name is not None:
|
||||||
query = query.filter_by(name=name)
|
query = query.filter_by(name=name)
|
||||||
if service is not None:
|
elif service is not None:
|
||||||
query = query.filter_by(service=service)
|
query = query.filter_by(service=service)
|
||||||
try:
|
try:
|
||||||
return query.one()
|
return query.one()
|
||||||
@ -3775,10 +3812,8 @@ class Connection(api.Connection):
|
|||||||
@objects.objectify(objects.ptp_instance)
|
@objects.objectify(objects.ptp_instance)
|
||||||
def ptp_instances_get_by_ihost(self, ihost_id, limit=None, marker=None,
|
def ptp_instances_get_by_ihost(self, ihost_id, limit=None, marker=None,
|
||||||
sort_key=None, sort_dir=None):
|
sort_key=None, sort_dir=None):
|
||||||
# ihost_get() to raise an exception if the ihost is not found
|
|
||||||
ihost_obj = self.ihost_get(ihost_id)
|
|
||||||
query = model_query(models.PtpInstances)
|
query = model_query(models.PtpInstances)
|
||||||
query = query.filter_by(host_id=ihost_obj.id)
|
query = add_ptp_instance_filter_by_host(query, ihost_id)
|
||||||
return _paginate_query(models.PtpInstances, limit, marker,
|
return _paginate_query(models.PtpInstances, limit, marker,
|
||||||
sort_key, sort_dir, query)
|
sort_key, sort_dir, query)
|
||||||
|
|
||||||
@ -3968,20 +4003,32 @@ class Connection(api.Connection):
|
|||||||
sort_key, sort_dir, query)
|
sort_key, sort_dir, query)
|
||||||
|
|
||||||
@objects.objectify(objects.ptp_parameter)
|
@objects.objectify(objects.ptp_parameter)
|
||||||
def ptp_parameters_get_by_foreign_uuid(self, uuid, limit=None, marker=None,
|
def ptp_parameters_get_by_type(self, type, limit=None, marker=None,
|
||||||
sort_key=None, sort_dir=None):
|
sort_key=None, sort_dir=None):
|
||||||
# Look for foreign UUID in PTP instances first, then in PTP interfaces
|
|
||||||
# if not found
|
|
||||||
try:
|
|
||||||
foreign_obj = self.ptp_instance_get(uuid)
|
|
||||||
except exception.PtpInstanceNotFound:
|
|
||||||
try:
|
|
||||||
foreign_obj = self.ptp_interface_get(uuid)
|
|
||||||
except exception.PtpInterfaceNotFound:
|
|
||||||
raise exception.NotFound()
|
|
||||||
|
|
||||||
query = model_query(models.PtpParameters)
|
query = model_query(models.PtpParameters)
|
||||||
query = query.filter_by(foreign_uuid=foreign_obj.uuid)
|
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
|
||||||
|
|
||||||
|
@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 []
|
||||||
|
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,
|
return _paginate_query(models.PtpParameters, limit, marker,
|
||||||
sort_key, sort_dir, query)
|
sort_key, sort_dir, query)
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
# from datetime import datetime
|
# from datetime import datetime
|
||||||
|
|
||||||
from sqlalchemy import Integer, String, DateTime, Text
|
from sqlalchemy import Integer, String, DateTime, Text
|
||||||
from sqlalchemy import Column, MetaData, Table, ForeignKey
|
from sqlalchemy import Column, MetaData, Table, ForeignKey, UniqueConstraint
|
||||||
|
|
||||||
from sysinv.db.sqlalchemy.models import UUID_LENGTH
|
from sysinv.db.sqlalchemy.models import UUID_LENGTH
|
||||||
|
|
||||||
@ -101,9 +101,12 @@ def upgrade(migrate_engine):
|
|||||||
Column('id', Integer, primary_key=True, nullable=False),
|
Column('id', Integer, primary_key=True, nullable=False),
|
||||||
Column('uuid', String(UUID_LENGTH), unique=True),
|
Column('uuid', String(UUID_LENGTH), unique=True),
|
||||||
|
|
||||||
Column('name', String(255)),
|
Column('name', String(255), nullable=False),
|
||||||
Column('value', String(255)),
|
Column('value', String(255)),
|
||||||
Column('foreign_uuid', String(UUID_LENGTH)),
|
Column('type', String(255)),
|
||||||
|
Column('foreign_uuid', String(UUID_LENGTH), nullable=False),
|
||||||
|
|
||||||
|
UniqueConstraint('name', 'foreign_uuid', name='u_paramnameforeign'),
|
||||||
|
|
||||||
mysql_engine=ENGINE,
|
mysql_engine=ENGINE,
|
||||||
mysql_charset=CHARSET,
|
mysql_charset=CHARSET,
|
||||||
|
@ -262,7 +262,7 @@ class inode(Base):
|
|||||||
|
|
||||||
forihostid = Column(Integer, ForeignKey('i_host.id', ondelete='CASCADE'))
|
forihostid = Column(Integer, ForeignKey('i_host.id', ondelete='CASCADE'))
|
||||||
|
|
||||||
host = relationship("ihost", backref="nodes", lazy="joined", join_depth=1)
|
host = relationship("ihost", backref="nodes", lazy="joined", cascade="all")
|
||||||
|
|
||||||
UniqueConstraint('numa_node', 'forihostid', name='u_hostnuma')
|
UniqueConstraint('numa_node', 'forihostid', name='u_hostnuma')
|
||||||
|
|
||||||
@ -369,7 +369,7 @@ class Interfaces(Base):
|
|||||||
join_depth=1)
|
join_depth=1)
|
||||||
|
|
||||||
host = relationship("ihost", backref="interfaces",
|
host = relationship("ihost", backref="interfaces",
|
||||||
lazy="joined", join_depth=1)
|
lazy="joined", cascade="all")
|
||||||
|
|
||||||
addresses = relationship("Addresses",
|
addresses = relationship("Addresses",
|
||||||
backref=backref("interface", lazy="joined"),
|
backref=backref("interface", lazy="joined"),
|
||||||
@ -481,10 +481,10 @@ class Ports(Base):
|
|||||||
capabilities = Column(JSONEncodedDict)
|
capabilities = Column(JSONEncodedDict)
|
||||||
# JSON{'speed':1000,'MTU':9600, 'duplex':'', 'autonegotiation':'false'}
|
# JSON{'speed':1000,'MTU':9600, 'duplex':'', 'autonegotiation':'false'}
|
||||||
|
|
||||||
node = relationship("inode", backref="ports", lazy="joined", join_depth=1)
|
node = relationship("inode", backref="ports", lazy="joined", cascade="all")
|
||||||
host = relationship("ihost", backref="ports", lazy="joined", join_depth=1)
|
host = relationship("ihost", backref="ports", lazy="joined", cascade="all")
|
||||||
interface = relationship("Interfaces", backref="port",
|
interface = relationship("Interfaces", backref="port",
|
||||||
lazy="joined", join_depth=1)
|
lazy="joined", cascade="all")
|
||||||
|
|
||||||
UniqueConstraint('pciaddr', 'dev_id', 'host_id', name='u_pciaddrdevihost')
|
UniqueConstraint('pciaddr', 'dev_id', 'host_id', name='u_pciaddrdevihost')
|
||||||
|
|
||||||
@ -798,8 +798,8 @@ class PtpInstances(Base):
|
|||||||
# capabilities not used yet: JSON{'':"", '':''}
|
# capabilities not used yet: JSON{'':"", '':''}
|
||||||
capabilities = Column(JSONEncodedDict)
|
capabilities = Column(JSONEncodedDict)
|
||||||
|
|
||||||
host = relationship("ihost", backref="ptp_instances", lazy="joined",
|
host = relationship("ihost", backref="ptp_instance", lazy="joined",
|
||||||
join_depth=1)
|
cascade="all")
|
||||||
|
|
||||||
|
|
||||||
class PtpInterfaces(Base):
|
class PtpInterfaces(Base):
|
||||||
@ -811,15 +811,16 @@ class PtpInterfaces(Base):
|
|||||||
interface_id = Column(Integer,
|
interface_id = Column(Integer,
|
||||||
ForeignKey('interfaces.id', ondelete='CASCADE'))
|
ForeignKey('interfaces.id', ondelete='CASCADE'))
|
||||||
ptp_instance_id = Column(Integer,
|
ptp_instance_id = Column(Integer,
|
||||||
ForeignKey('ptp_instances.id', ondelete='CASCADE'))
|
ForeignKey('ptp_instances.id',
|
||||||
|
ondelete='CASCADE'))
|
||||||
|
|
||||||
# capabilities not used yet: JSON{'':"", '':''}
|
# capabilities not used yet: JSON{'':"", '':''}
|
||||||
capabilities = Column(JSONEncodedDict)
|
capabilities = Column(JSONEncodedDict)
|
||||||
|
|
||||||
interface = relationship("Interfaces", backref="ptp_interfaces",
|
interface = relationship("Interfaces", backref="ptp_interface",
|
||||||
lazy="joined", join_depth=1)
|
lazy="joined", cascade="all")
|
||||||
ptp_instance = relationship("PtpInstances", backref="ptp_interfaces",
|
ptp_instance = relationship("PtpInstances", backref="ptp_interface",
|
||||||
lazy="joined", join_depth=1)
|
lazy="joined", cascade="all")
|
||||||
|
|
||||||
|
|
||||||
class PtpParameters(Base):
|
class PtpParameters(Base):
|
||||||
@ -829,10 +830,25 @@ class PtpParameters(Base):
|
|||||||
uuid = Column(String(UUID_LENGTH), unique=True)
|
uuid = Column(String(UUID_LENGTH), unique=True)
|
||||||
|
|
||||||
name = Column(String(255), nullable=False)
|
name = Column(String(255), nullable=False)
|
||||||
value = Column(String(255), nullable=False)
|
value = Column(String(255))
|
||||||
|
|
||||||
# Either a "PtpInstance" or "PtpInterface" uuid:
|
type = Column(String(255))
|
||||||
foreign_uuid = Column(String(UUID_LENGTH))
|
foreign_uuid = Column(String(UUID_LENGTH), nullable=False)
|
||||||
|
|
||||||
|
ptp_instance = relationship(
|
||||||
|
"PtpInstances",
|
||||||
|
primaryjoin="PtpParameters.foreign_uuid == foreign(PtpInstances.uuid)",
|
||||||
|
lazy="subquery",
|
||||||
|
cascade="all")
|
||||||
|
|
||||||
|
ptp_interface = relationship(
|
||||||
|
"PtpInterfaces",
|
||||||
|
primaryjoin="PtpParameters.foreign_uuid == "
|
||||||
|
"foreign(PtpInterfaces.uuid)",
|
||||||
|
lazy="subquery",
|
||||||
|
cascade="all")
|
||||||
|
|
||||||
|
UniqueConstraint('name', 'foreign_uuid', name='u_paramnameforeign')
|
||||||
|
|
||||||
|
|
||||||
class StorageTier(Base):
|
class StorageTier(Base):
|
||||||
|
@ -22,13 +22,17 @@ class PtpInstance(base.SysinvObject):
|
|||||||
'name': utils.str_or_none,
|
'name': utils.str_or_none,
|
||||||
'service': utils.str_or_none,
|
'service': utils.str_or_none,
|
||||||
|
|
||||||
'host_uuid': utils.str_or_none,
|
|
||||||
'host_id': utils.int_or_none,
|
'host_id': utils.int_or_none,
|
||||||
|
|
||||||
|
'host_uuid': utils.str_or_none,
|
||||||
|
'hostname': utils.str_or_none,
|
||||||
|
|
||||||
'capabilities': utils.dict_or_none
|
'capabilities': utils.dict_or_none
|
||||||
}
|
}
|
||||||
|
|
||||||
_foreign_fields = {
|
_foreign_fields = {
|
||||||
'host_uuid': 'host:uuid'
|
'host_uuid': 'host:uuid',
|
||||||
|
'hostname': 'host:hostname'
|
||||||
}
|
}
|
||||||
|
|
||||||
@base.remotable_classmethod
|
@base.remotable_classmethod
|
||||||
|
@ -6,11 +6,38 @@
|
|||||||
#
|
#
|
||||||
########################################################################
|
########################################################################
|
||||||
|
|
||||||
|
from sysinv.common import constants
|
||||||
from sysinv.db import api as db_api
|
from sysinv.db import api as db_api
|
||||||
from sysinv.objects import base
|
from sysinv.objects import base
|
||||||
from sysinv.objects import utils
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
return owner
|
||||||
|
|
||||||
|
|
||||||
class PtpParameter(base.SysinvObject):
|
class PtpParameter(base.SysinvObject):
|
||||||
|
|
||||||
dbapi = db_api.get_instance()
|
dbapi = db_api.get_instance()
|
||||||
@ -22,10 +49,14 @@ class PtpParameter(base.SysinvObject):
|
|||||||
'name': utils.str_or_none,
|
'name': utils.str_or_none,
|
||||||
'value': utils.str_or_none,
|
'value': utils.str_or_none,
|
||||||
|
|
||||||
'foreign_uuid': utils.str_or_none
|
'type': utils.str_or_none,
|
||||||
|
'foreign_uuid': utils.str_or_none,
|
||||||
|
|
||||||
|
'owner': dict
|
||||||
}
|
}
|
||||||
|
|
||||||
_foreign_fields = {
|
_foreign_fields = {
|
||||||
|
'owner': get_owner
|
||||||
}
|
}
|
||||||
|
|
||||||
@base.remotable_classmethod
|
@base.remotable_classmethod
|
||||||
|
@ -3,12 +3,11 @@
|
|||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
|
|
||||||
from oslo_utils import uuidutils
|
|
||||||
from six.moves import http_client
|
from six.moves import http_client
|
||||||
from sysinv.common import constants
|
from sysinv.common import constants
|
||||||
from sysinv.db import api as dbapi
|
|
||||||
from sysinv.tests.api import base
|
from sysinv.tests.api import base
|
||||||
from sysinv.tests.db import base as dbbase
|
from sysinv.tests.db import base as dbbase
|
||||||
|
from sysinv.tests.db import utils as dbutils
|
||||||
|
|
||||||
|
|
||||||
class BasePtpInstanceTestCase(base.FunctionalTest, dbbase.BaseHostTestCase):
|
class BasePtpInstanceTestCase(base.FunctionalTest, dbbase.BaseHostTestCase):
|
||||||
@ -27,32 +26,6 @@ class BasePtpInstanceTestCase(base.FunctionalTest, dbbase.BaseHostTestCase):
|
|||||||
# Can perform API operations on this object at a sublevel of host
|
# Can perform API operations on this object at a sublevel of host
|
||||||
HOST_PREFIX = '/ihosts'
|
HOST_PREFIX = '/ihosts'
|
||||||
|
|
||||||
# Attributes that should be populated by an API query
|
|
||||||
expected_api_fields = ['uuid', 'name', 'service']
|
|
||||||
|
|
||||||
# Attributes that should NOT be populated by an API query
|
|
||||||
hidden_api_fields = ['host_id']
|
|
||||||
|
|
||||||
def _get_ptp_instance(self, **kw):
|
|
||||||
instance = {
|
|
||||||
'id': kw.get('id'),
|
|
||||||
'uuid': kw.get('uuid'),
|
|
||||||
'name': kw.get('name', None),
|
|
||||||
'service': kw.get('service', 'ptp4l'),
|
|
||||||
'host_id': kw.get('host_id', None)
|
|
||||||
}
|
|
||||||
return instance
|
|
||||||
|
|
||||||
def _create_ptp_instance(self, **kw):
|
|
||||||
instance = self._get_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']
|
|
||||||
db_api = dbapi.get_instance()
|
|
||||||
return db_api.ptp_instance_create(instance)
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(BasePtpInstanceTestCase, self).setUp()
|
super(BasePtpInstanceTestCase, self).setUp()
|
||||||
self.controller = self._create_test_host(constants.CONTROLLER)
|
self.controller = self._create_test_host(constants.CONTROLLER)
|
||||||
@ -64,39 +37,38 @@ class BasePtpInstanceTestCase(base.FunctionalTest, dbbase.BaseHostTestCase):
|
|||||||
def get_host_scoped_url(self, host_uuid):
|
def get_host_scoped_url(self, host_uuid):
|
||||||
return '%s/%s%s' % (self.HOST_PREFIX, host_uuid, self.API_PREFIX)
|
return '%s/%s%s' % (self.HOST_PREFIX, host_uuid, self.API_PREFIX)
|
||||||
|
|
||||||
def get_post_object(self, name='test_instance', service='ptp4l',
|
def get_post_object(self, name='test_instance',
|
||||||
host_id=None, host_uuid=None):
|
service=constants.PTP_INSTANCE_TYPE_PTP4L,
|
||||||
ptp_instance_db = self._get_ptp_instance(name=name,
|
host_id=None, host_uuid=None, hostname=None):
|
||||||
service=service,
|
ptp_instance_db = dbutils.get_test_ptp_instance(name=name,
|
||||||
host_id=host_id)
|
service=service,
|
||||||
|
host_id=host_id)
|
||||||
ptp_instance_db['host_uuid'] = host_uuid
|
ptp_instance_db['host_uuid'] = host_uuid
|
||||||
|
ptp_instance_db['hostname'] = hostname
|
||||||
return ptp_instance_db
|
return ptp_instance_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 TestCreatePtpInstance(BasePtpInstanceTestCase):
|
class TestCreatePtpInstance(BasePtpInstanceTestCase):
|
||||||
name = 'ptp-name'
|
name = constants.PTP_INSTANCE_DEFAULT_PTP4L
|
||||||
service = 'ptp4l'
|
service = constants.PTP_INSTANCE_TYPE_PTP4L
|
||||||
host_id = None
|
host_id = None
|
||||||
host_uuid = None
|
host_uuid = None
|
||||||
|
hostname = None
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestCreatePtpInstance, self).setUp()
|
super(TestCreatePtpInstance, self).setUp()
|
||||||
self.host_id = self.controller.id
|
self.host_id = self.controller.id
|
||||||
self.host_uuid = self.controller.uuid
|
self.host_uuid = self.controller.uuid
|
||||||
self._create_ptp_instance(name=self.name, service=self.service,
|
self.hostname = self.controller.hostname
|
||||||
host_id=self.host_id)
|
dbutils.create_test_ptp_instance(name=self.name, service=self.service,
|
||||||
|
host_id=self.host_id)
|
||||||
|
|
||||||
def _create_ptp_instance_success(self, name, service, host_id, host_uuid):
|
def _create_ptp_instance_success(self, name, service, host_id, host_uuid,
|
||||||
|
hostname):
|
||||||
ptp_instance_db = self.get_post_object(name=name, service=service,
|
ptp_instance_db = self.get_post_object(name=name, service=service,
|
||||||
host_id=host_id,
|
host_id=host_id,
|
||||||
host_uuid=host_uuid)
|
host_uuid=host_uuid,
|
||||||
|
hostname=hostname)
|
||||||
response = self.post_json(self.API_PREFIX, ptp_instance_db,
|
response = self.post_json(self.API_PREFIX, ptp_instance_db,
|
||||||
headers=self.API_HEADERS)
|
headers=self.API_HEADERS)
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
@ -105,10 +77,11 @@ class TestCreatePtpInstance(BasePtpInstanceTestCase):
|
|||||||
ptp_instance_db[self.COMMON_FIELD])
|
ptp_instance_db[self.COMMON_FIELD])
|
||||||
|
|
||||||
def _create_ptp_instance_failed(self, name, service, host_id, host_uuid,
|
def _create_ptp_instance_failed(self, name, service, host_id, host_uuid,
|
||||||
status_code, error_message):
|
hostname, status_code, error_message):
|
||||||
ptp_instance_db = self.get_post_object(name=name, service=service,
|
ptp_instance_db = self.get_post_object(name=name, service=service,
|
||||||
host_id=host_id,
|
host_id=host_id,
|
||||||
host_uuid=host_uuid)
|
host_uuid=host_uuid,
|
||||||
|
hostname=hostname)
|
||||||
response = self.post_json(self.API_PREFIX, ptp_instance_db,
|
response = self.post_json(self.API_PREFIX, ptp_instance_db,
|
||||||
headers=self.API_HEADERS, expect_errors=True)
|
headers=self.API_HEADERS, expect_errors=True)
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
@ -116,9 +89,11 @@ class TestCreatePtpInstance(BasePtpInstanceTestCase):
|
|||||||
self.assertIn(error_message, response.json['error_message'])
|
self.assertIn(error_message, response.json['error_message'])
|
||||||
|
|
||||||
def test_create_ptp_instance_ok(self):
|
def test_create_ptp_instance_ok(self):
|
||||||
self._create_ptp_instance_success('test-instance', 'ptp4l',
|
self._create_ptp_instance_success('test-instance',
|
||||||
|
constants.PTP_INSTANCE_TYPE_PTP4L,
|
||||||
host_id=self.controller.id,
|
host_id=self.controller.id,
|
||||||
host_uuid=self.controller.uuid)
|
host_uuid=self.controller.uuid,
|
||||||
|
hostname=self.controller.hostname)
|
||||||
|
|
||||||
def test_create_ptp_instance_invalid_service(self):
|
def test_create_ptp_instance_invalid_service(self):
|
||||||
self._create_ptp_instance_failed(
|
self._create_ptp_instance_failed(
|
||||||
@ -126,6 +101,7 @@ class TestCreatePtpInstance(BasePtpInstanceTestCase):
|
|||||||
'invalid',
|
'invalid',
|
||||||
host_id=self.controller.id,
|
host_id=self.controller.id,
|
||||||
host_uuid=self.controller.uuid,
|
host_uuid=self.controller.uuid,
|
||||||
|
hostname=self.controller.hostname,
|
||||||
status_code=http_client.BAD_REQUEST,
|
status_code=http_client.BAD_REQUEST,
|
||||||
error_message='Invalid input for field/attribute service')
|
error_message='Invalid input for field/attribute service')
|
||||||
|
|
||||||
@ -137,6 +113,7 @@ class TestCreatePtpInstance(BasePtpInstanceTestCase):
|
|||||||
service=self.service,
|
service=self.service,
|
||||||
host_id=self.host_id,
|
host_id=self.host_id,
|
||||||
host_uuid=self.host_uuid,
|
host_uuid=self.host_uuid,
|
||||||
|
hostname=self.controller.hostname,
|
||||||
status_code=http_client.CONFLICT,
|
status_code=http_client.CONFLICT,
|
||||||
error_message=error_message)
|
error_message=error_message)
|
||||||
|
|
||||||
@ -145,9 +122,10 @@ class TestCreatePtpInstance(BasePtpInstanceTestCase):
|
|||||||
error_message = '%s could not be found' % bad_uuid
|
error_message = '%s could not be found' % bad_uuid
|
||||||
self._create_ptp_instance_failed(
|
self._create_ptp_instance_failed(
|
||||||
'test-invalid',
|
'test-invalid',
|
||||||
'phc2sys',
|
constants.PTP_INSTANCE_TYPE_PHC2SYS,
|
||||||
host_id=99,
|
host_id=99,
|
||||||
host_uuid='f4c56ddf-aef3-46ed-b9aa-126a1faafd40',
|
host_uuid=bad_uuid,
|
||||||
|
hostname='badhost',
|
||||||
status_code=http_client.NOT_FOUND,
|
status_code=http_client.NOT_FOUND,
|
||||||
error_message=error_message)
|
error_message=error_message)
|
||||||
|
|
||||||
@ -157,8 +135,10 @@ class TestGetPtpInstance(BasePtpInstanceTestCase):
|
|||||||
super(TestGetPtpInstance, self).setUp()
|
super(TestGetPtpInstance, self).setUp()
|
||||||
|
|
||||||
def test_get_ptp_instance_found(self):
|
def test_get_ptp_instance_found(self):
|
||||||
ptp_instance = self._create_ptp_instance(
|
ptp_instance = dbutils.create_test_ptp_instance(
|
||||||
name='fake-ptp4l', service='ptp4l', host_id=self.controller.id)
|
name=constants.PTP_INSTANCE_DEFAULT_PTP4L,
|
||||||
|
service=constants.PTP_INSTANCE_TYPE_PTP4L,
|
||||||
|
host_id=self.controller.id)
|
||||||
uuid = ptp_instance['uuid']
|
uuid = ptp_instance['uuid']
|
||||||
response = self.get_json(self.get_single_url(uuid))
|
response = self.get_json(self.get_single_url(uuid))
|
||||||
self.assertIn(self.COMMON_FIELD, response)
|
self.assertIn(self.COMMON_FIELD, response)
|
||||||
@ -180,13 +160,15 @@ class TestListPtpInstance(BasePtpInstanceTestCase):
|
|||||||
self._create_test_ptp_instances()
|
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', host_id=None):
|
||||||
services = ['ptp4l', 'phc2sys', 'ts2phc']
|
services = [constants.PTP_INSTANCE_TYPE_PTP4L,
|
||||||
|
constants.PTP_INSTANCE_TYPE_PHC2SYS,
|
||||||
|
constants.PTP_INSTANCE_TYPE_TS2PHC]
|
||||||
instances = []
|
instances = []
|
||||||
if not host_id:
|
if not host_id:
|
||||||
host_id = self.controller.id
|
host_id = self.controller.id
|
||||||
for service in services:
|
for service in services:
|
||||||
name = '%s-%s' % (name_prefix, service)
|
name = '%s-%s' % (name_prefix, service)
|
||||||
instance = self._create_ptp_instance(
|
instance = dbutils.create_test_ptp_instance(
|
||||||
name=name, service=service, host_id=host_id)
|
name=name, service=service, host_id=host_id)
|
||||||
instances.append(instance)
|
instances.append(instance)
|
||||||
return instances
|
return instances
|
||||||
@ -214,30 +196,57 @@ class TestDeletePtpInstance(BasePtpInstanceTestCase):
|
|||||||
python2 and python3 libraries may return different
|
python2 and python3 libraries may return different
|
||||||
content_type (None, or empty json) when NO_CONTENT returned.
|
content_type (None, or empty json) when NO_CONTENT returned.
|
||||||
"""
|
"""
|
||||||
|
ptp_instance = None
|
||||||
|
uuid = None
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestDeletePtpInstance, self).setUp()
|
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)
|
||||||
|
self.uuid = self.ptp_instance['uuid']
|
||||||
|
|
||||||
def test_delete_ptp_instance(self):
|
def test_delete_ptp_instance_ok(self):
|
||||||
ptp_instance = self._create_ptp_instance(
|
response = self.delete(self.get_single_url(self.uuid),
|
||||||
name='fake-phc2sys', service='phc2sys', host_id=self.controller.id)
|
|
||||||
uuid = ptp_instance['uuid']
|
|
||||||
response = self.delete(self.get_single_url(uuid),
|
|
||||||
headers=self.API_HEADERS)
|
headers=self.API_HEADERS)
|
||||||
self.assertEqual(response.status_code, http_client.NO_CONTENT)
|
self.assertEqual(response.status_code, http_client.NO_CONTENT)
|
||||||
|
|
||||||
# Check the instance was indeed removed
|
# Check the instance was indeed removed
|
||||||
error_message = 'No PTP instance with id %s found' % uuid
|
error_message = 'No PTP instance with id %s found' % self.uuid
|
||||||
response = self.get_json(self.get_single_url(uuid),
|
response = self.get_json(self.get_single_url(self.uuid),
|
||||||
expect_errors=True)
|
expect_errors=True)
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
self.assertEqual(response.status_code, http_client.NOT_FOUND)
|
self.assertEqual(response.status_code, http_client.NOT_FOUND)
|
||||||
self.assertIn(error_message, response.json['error_message'])
|
self.assertIn(error_message, response.json['error_message'])
|
||||||
|
|
||||||
def test_delete_ptp_instance_with_parameters_failed(self):
|
def test_delete_ptp_instance_with_parameters_failed(self):
|
||||||
# TODO: implement when PTP parameters API is available
|
ptp_parameter = dbutils.create_test_ptp_parameter(
|
||||||
pass
|
name='fake-param', value='fake-value',
|
||||||
|
type=constants.PTP_PARAMETER_OWNER_INSTANCE,
|
||||||
|
foreign_uuid=self.uuid)
|
||||||
|
self.assertEqual(self.uuid, ptp_parameter['foreign_uuid'])
|
||||||
|
|
||||||
|
response = self.delete(self.get_single_url(self.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 PTP parameter',
|
||||||
|
response.json['error_message'])
|
||||||
|
|
||||||
def test_delete_ptp_instance_with_interfaces_failed(self):
|
def test_delete_ptp_instance_with_interfaces_failed(self):
|
||||||
# TODO: implement when PTP interfaces API is available
|
interface = dbutils.create_test_interface(
|
||||||
pass
|
ifname='fake0', ifclass=constants.INTERFACE_CLASS_PLATFORM,
|
||||||
|
forihostid=self.controller.id, ihost_uuid=self.controller.uuid)
|
||||||
|
ptp_interface = dbutils.create_test_ptp_interface(
|
||||||
|
interface_id=interface['id'],
|
||||||
|
ptp_instance_id=self.ptp_instance['id'])
|
||||||
|
self.assertEqual(self.ptp_instance['id'],
|
||||||
|
ptp_interface['ptp_instance_id'])
|
||||||
|
|
||||||
|
response = self.delete(self.get_single_url(self.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 PTP interface',
|
||||||
|
response.json['error_message'])
|
||||||
|
@ -81,12 +81,12 @@ class TestCreatePtpInterface(BasePtpInterfaceTestCase):
|
|||||||
|
|
||||||
self.test_instance = dbutils.create_test_ptp_instance(
|
self.test_instance = dbutils.create_test_ptp_instance(
|
||||||
name='testInstance',
|
name='testInstance',
|
||||||
service='ptp4l',
|
service=constants.PTP_INSTANCE_TYPE_PTP4L,
|
||||||
host_id=self.controller.id)
|
host_id=self.controller.id)
|
||||||
|
|
||||||
def _create_ptp_interface_success(self, interface_uuid, ptp_instance_uuid):
|
def _create_ptp_interface_success(self, interface_uuid, ptp_instance_uuid):
|
||||||
ptp_interface_db = self.get_post_object(interface_uuid,
|
ptp_interface_db = self.get_post_object(interface_uuid,
|
||||||
ptp_instance_uuid)
|
ptp_instance_uuid)
|
||||||
response = self.post_json(self.API_PREFIX, ptp_interface_db,
|
response = self.post_json(self.API_PREFIX, ptp_interface_db,
|
||||||
headers=self.API_HEADERS)
|
headers=self.API_HEADERS)
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
@ -125,7 +125,7 @@ class TestCreatePtpInterface(BasePtpInterfaceTestCase):
|
|||||||
|
|
||||||
def test_create_ptp_interface_duplicate(self):
|
def test_create_ptp_interface_duplicate(self):
|
||||||
self._create_ptp_interface_success(self.test_interface.uuid,
|
self._create_ptp_interface_success(self.test_interface.uuid,
|
||||||
self.test_instance.uuid)
|
self.test_instance.uuid)
|
||||||
|
|
||||||
self._create_ptp_interface_failed(
|
self._create_ptp_interface_failed(
|
||||||
interface_uuid=self.test_interface.uuid,
|
interface_uuid=self.test_interface.uuid,
|
||||||
@ -145,16 +145,17 @@ class TestGetPtpInterface(BasePtpInterfaceTestCase):
|
|||||||
|
|
||||||
self.test_instance = dbutils.create_test_ptp_instance(
|
self.test_instance = dbutils.create_test_ptp_instance(
|
||||||
name='testInstance',
|
name='testInstance',
|
||||||
service='ptp4l',
|
service=constants.PTP_INSTANCE_TYPE_PTP4L,
|
||||||
host_id=self.controller.id)
|
host_id=self.controller.id)
|
||||||
|
|
||||||
self.test_ptp_interface = dbutils.create_test_ptp_interface(
|
self.test_ptp_interface = dbutils.create_test_ptp_interface(
|
||||||
interface_id=self.test_interface.id,
|
interface_id=self.test_interface.id,
|
||||||
ptp_instance_id=self.test_instance.id)
|
ptp_instance_id=self.test_instance.id)
|
||||||
|
|
||||||
def test_get_ptp_interface_found(self):
|
def test_get_ptp_interface_found(self):
|
||||||
|
|
||||||
response = self.get_json(self.get_single_url(self.test_ptp_interface.uuid))
|
response = self.get_json(
|
||||||
|
self.get_single_url(self.test_ptp_interface.uuid))
|
||||||
self.assertIn(self.COMMON_FIELD, response)
|
self.assertIn(self.COMMON_FIELD, response)
|
||||||
|
|
||||||
def test_get_ptp_interface_not_found(self):
|
def test_get_ptp_interface_not_found(self):
|
||||||
@ -185,7 +186,7 @@ class TestListPtpInterface(BasePtpInterfaceTestCase):
|
|||||||
|
|
||||||
self.test_instance_ptp4l = dbutils.create_test_ptp_instance(
|
self.test_instance_ptp4l = dbutils.create_test_ptp_instance(
|
||||||
name='ptp4lInstance',
|
name='ptp4lInstance',
|
||||||
service='ptp4l',
|
service=constants.PTP_INSTANCE_TYPE_PTP4L,
|
||||||
host_id=self.worker.id)
|
host_id=self.worker.id)
|
||||||
|
|
||||||
self.test_instance_phc2sys = dbutils.create_test_ptp_instance(
|
self.test_instance_phc2sys = dbutils.create_test_ptp_instance(
|
||||||
@ -194,28 +195,30 @@ class TestListPtpInterface(BasePtpInterfaceTestCase):
|
|||||||
host_id=self.worker.id)
|
host_id=self.worker.id)
|
||||||
|
|
||||||
self.ptp4l_ptp_interface = dbutils.create_test_ptp_interface(
|
self.ptp4l_ptp_interface = dbutils.create_test_ptp_interface(
|
||||||
interface_id=self.test_interface.id,
|
interface_id=self.test_interface.id,
|
||||||
ptp_instance_id=self.test_instance_ptp4l.id)
|
ptp_instance_id=self.test_instance_ptp4l.id)
|
||||||
self.phc2sys_ptp_interface = dbutils.create_test_ptp_interface(
|
self.phc2sys_ptp_interface = dbutils.create_test_ptp_interface(
|
||||||
interface_id=self.test_interface.id,
|
interface_id=self.test_interface.id,
|
||||||
ptp_instance_id=self.test_instance_phc2sys.id)
|
ptp_instance_id=self.test_instance_phc2sys.id)
|
||||||
self.dummy_ptp_interface = dbutils.create_test_ptp_interface(
|
self.dummy_ptp_interface = dbutils.create_test_ptp_interface(
|
||||||
interface_id=self.dummy_interface.id,
|
interface_id=self.dummy_interface.id,
|
||||||
ptp_instance_id=self.test_instance_ptp4l.id)
|
ptp_instance_id=self.test_instance_ptp4l.id)
|
||||||
|
|
||||||
def test_list_ptp_interface_host(self):
|
def test_list_ptp_interface_host(self):
|
||||||
response = self.get_json(self.get_host_scoped_url(self.worker.uuid))
|
response = self.get_json(self.get_host_scoped_url(self.worker.uuid))
|
||||||
for result in response[self.RESULT_KEY]:
|
for result in response[self.RESULT_KEY]:
|
||||||
self.assertEqual(self.worker.id, result['forihostid'])
|
self.assertEqual(self.worker.id, result['forihostid'])
|
||||||
if result['uuid'] == self.ptp4l_ptp_interface.uuid \
|
if result['uuid'] == self.ptp4l_ptp_interface.uuid \
|
||||||
or result['uuid'] == self.dummy_interface.uuid:
|
or result['uuid'] == self.dummy_interface.uuid:
|
||||||
self.assertEqual(self.test_instance_ptp4l.id, result['ptp_instance_id'])
|
self.assertEqual(self.test_instance_ptp4l.id,
|
||||||
|
result['ptp_instance_id'])
|
||||||
elif result['uuid'] == self.phc2sys_ptp_interface.uuid:
|
elif result['uuid'] == self.phc2sys_ptp_interface.uuid:
|
||||||
self.assertEqual(self.test_instance_phc2sys.id, result['ptp_instance_id'])
|
self.assertEqual(self.test_instance_phc2sys.id,
|
||||||
|
result['ptp_instance_id'])
|
||||||
|
|
||||||
def test_list_ptp_interface_interface(self):
|
def test_list_ptp_interface_interface(self):
|
||||||
response = self.get_json(self.get_host_scoped_url_interface(self.worker.uuid,
|
response = self.get_json(self.get_host_scoped_url_interface(
|
||||||
self.test_interface.uuid))
|
self.worker.uuid, self.test_interface.uuid))
|
||||||
for result in response[self.RESULT_KEY]:
|
for result in response[self.RESULT_KEY]:
|
||||||
self.assertIn(self.COMMON_FIELD, result)
|
self.assertIn(self.COMMON_FIELD, result)
|
||||||
self.assertNotIn(self.dummy_interface.uuid, result)
|
self.assertNotIn(self.dummy_interface.uuid, result)
|
||||||
@ -243,25 +246,39 @@ class TestDeletePtpInterface(BasePtpInterfaceTestCase):
|
|||||||
|
|
||||||
self.test_instance_ptp4l = dbutils.create_test_ptp_instance(
|
self.test_instance_ptp4l = dbutils.create_test_ptp_instance(
|
||||||
name='ptp4lInstance',
|
name='ptp4lInstance',
|
||||||
service='ptp4l',
|
service=constants.PTP_INSTANCE_TYPE_PTP4L,
|
||||||
host_id=self.worker.id)
|
host_id=self.worker.id)
|
||||||
|
|
||||||
self.test_ptp_interface = dbutils.create_test_ptp_interface(
|
self.test_ptp_interface = dbutils.create_test_ptp_interface(
|
||||||
interface_id=self.test_interface.id,
|
interface_id=self.test_interface.id,
|
||||||
ptp_instance_id=self.test_instance_ptp4l.id)
|
ptp_instance_id=self.test_instance_ptp4l.id)
|
||||||
|
|
||||||
def test_delete_ptp_interface(self):
|
def test_delete_ptp_interface(self):
|
||||||
response = self.delete(self.get_single_url(self.test_ptp_interface.uuid),
|
response = self.delete(
|
||||||
headers=self.API_HEADERS)
|
self.get_single_url(self.test_ptp_interface.uuid),
|
||||||
|
headers=self.API_HEADERS)
|
||||||
self.assertEqual(response.status_code, http_client.NO_CONTENT)
|
self.assertEqual(response.status_code, http_client.NO_CONTENT)
|
||||||
|
|
||||||
error_message = 'No PTP interface with id %s found' % self.test_ptp_interface.uuid
|
error_message = \
|
||||||
response = self.get_json(self.get_single_url(self.test_ptp_interface.uuid),
|
'No PTP interface with id %s found' % self.test_ptp_interface.uuid
|
||||||
expect_errors=True)
|
response = self.get_json(
|
||||||
|
self.get_single_url(self.test_ptp_interface.uuid),
|
||||||
|
expect_errors=True)
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
self.assertEqual(response.status_code, http_client.NOT_FOUND)
|
self.assertEqual(response.status_code, http_client.NOT_FOUND)
|
||||||
self.assertIn(error_message, response.json['error_message'])
|
self.assertIn(error_message, response.json['error_message'])
|
||||||
|
|
||||||
def test_delete_ptp_interface_with_parameters_failed(self):
|
def test_delete_ptp_interface_with_parameters_failed(self):
|
||||||
# TODO: implement when PTP parameters API is available
|
ptp_parameter = dbutils.create_test_ptp_parameter(
|
||||||
pass
|
name='fake-param', value='fake-value',
|
||||||
|
type=constants.PTP_PARAMETER_OWNER_INTERFACE,
|
||||||
|
foreign_uuid=self.test_ptp_interface.uuid)
|
||||||
|
self.assertEqual(self.test_ptp_interface.uuid,
|
||||||
|
ptp_parameter['foreign_uuid'])
|
||||||
|
|
||||||
|
response = self.delete(
|
||||||
|
self.get_single_url(self.test_ptp_interface.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('has PTP parameter', response.json['error_message'])
|
||||||
|
297
sysinv/sysinv/sysinv/sysinv/tests/api/test_ptp_parameter.py
Normal file
297
sysinv/sysinv/sysinv/sysinv/tests/api/test_ptp_parameter.py
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
# Copyright (c) 2021 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
from six.moves import http_client
|
||||||
|
from sysinv.common import constants
|
||||||
|
from sysinv.tests.api import base
|
||||||
|
from sysinv.tests.db import base as dbbase
|
||||||
|
from sysinv.tests.db import utils as dbutils
|
||||||
|
|
||||||
|
|
||||||
|
class BasePtpParameterTestCase(base.FunctionalTest, dbbase.BaseHostTestCase):
|
||||||
|
# Generic header passed to most API calls
|
||||||
|
API_HEADERS = {'User-Agent': 'sysinv-test'}
|
||||||
|
|
||||||
|
# Prefix for the URL
|
||||||
|
API_PREFIX = '/ptp_parameters'
|
||||||
|
|
||||||
|
# Python table key for the list of results
|
||||||
|
RESULT_KEY = 'ptp_parameters'
|
||||||
|
|
||||||
|
# Field that is known to exist for inputs and outputs
|
||||||
|
COMMON_FIELD = 'name'
|
||||||
|
|
||||||
|
# Can perform API operations on this object at a sublevel of PTP instances
|
||||||
|
PTP_INSTANCE_PREFIX = '/ptp_instances'
|
||||||
|
|
||||||
|
# Can perform API operations on this object at a sublevel of interfaces
|
||||||
|
INTERFACE_PREFIX = '/iinterfaces'
|
||||||
|
|
||||||
|
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_interfaces = self._create_test_ptp_interface(
|
||||||
|
self.ptp_instances, self.platform_interfaces)
|
||||||
|
|
||||||
|
def get_single_url(self, ptp_parameter_uuid):
|
||||||
|
return '%s/%s' % (self.API_PREFIX, ptp_parameter_uuid)
|
||||||
|
|
||||||
|
def get_instance_scoped_url(self, ptp_instance_uuid):
|
||||||
|
return '%s/%s%s' % (self.PTP_INSTANCE_PREFIX, ptp_instance_uuid,
|
||||||
|
self.API_PREFIX)
|
||||||
|
|
||||||
|
def get_interface_scoped_url(self, interface_uuid):
|
||||||
|
return '%s/%s%s' % (self.INTERFACE_PREFIX, interface_uuid,
|
||||||
|
self.API_PREFIX)
|
||||||
|
|
||||||
|
def get_post_object(self, name='test_parameter', value='test_value',
|
||||||
|
type=None, foreign_uuid=None):
|
||||||
|
return dbutils.get_test_ptp_parameter(name=name,
|
||||||
|
value=value,
|
||||||
|
type=type,
|
||||||
|
foreign_uuid=foreign_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)
|
||||||
|
|
||||||
|
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,
|
||||||
|
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])
|
||||||
|
|
||||||
|
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,
|
||||||
|
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_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)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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,
|
||||||
|
status_code=http_client.CONFLICT,
|
||||||
|
error_message='already exists')
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetPtpParameter(BasePtpParameterTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestGetPtpParameter, self).setUp()
|
||||||
|
|
||||||
|
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)
|
||||||
|
uuid = ptp_parameter['uuid']
|
||||||
|
response = self.get_json(self.get_single_url(uuid))
|
||||||
|
self.assertIn(self.COMMON_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),
|
||||||
|
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'])
|
||||||
|
|
||||||
|
|
||||||
|
class TestListPtpParameter(BasePtpParameterTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestListPtpParameter, self).setUp()
|
||||||
|
self._create_test_ptp_parameters(
|
||||||
|
type=constants.PTP_PARAMETER_OWNER_INSTANCE,
|
||||||
|
prefix='ptp')
|
||||||
|
self._create_test_ptp_parameters(
|
||||||
|
type=constants.PTP_PARAMETER_OWNER_INTERFACE,
|
||||||
|
prefix='iface')
|
||||||
|
|
||||||
|
def _create_test_ptp_parameters(self, type, prefix='test',
|
||||||
|
foreign_uuid=None):
|
||||||
|
parameters = []
|
||||||
|
|
||||||
|
if not foreign_uuid:
|
||||||
|
if type == constants.PTP_PARAMETER_OWNER_INSTANCE:
|
||||||
|
foreign_uuid = self.ptp_instances[0].uuid
|
||||||
|
elif type == constants.PTP_PARAMETER_OWNER_INTERFACE:
|
||||||
|
foreign_uuid = self.ptp_interfaces[0].uuid
|
||||||
|
else:
|
||||||
|
return parameters
|
||||||
|
|
||||||
|
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)
|
||||||
|
parameters.append(parameter)
|
||||||
|
return parameters
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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'])
|
||||||
|
"""
|
||||||
|
|
||||||
|
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'])
|
||||||
|
|
||||||
|
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'])
|
||||||
|
|
||||||
|
|
||||||
|
class TestUpdatePtpParameter(BasePtpParameterTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestUpdatePtpParameter, self).setUp()
|
||||||
|
|
||||||
|
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)
|
||||||
|
uuid = ptp_parameter['uuid']
|
||||||
|
|
||||||
|
response = self.patch_json(self.get_single_url(uuid),
|
||||||
|
[{'path': '/value',
|
||||||
|
'value': 'changed-value',
|
||||||
|
'op': 'replace'}],
|
||||||
|
headers=self.API_HEADERS)
|
||||||
|
self.assertEqual(response.content_type, 'application/json')
|
||||||
|
self.assertEqual(response.status_code, http_client.OK)
|
||||||
|
|
||||||
|
# Check the parameter was indeed updated
|
||||||
|
response = self.get_json(self.get_single_url(uuid))
|
||||||
|
self.assertEqual(response['value'], 'changed-value')
|
||||||
|
|
||||||
|
|
||||||
|
class TestDeletePtpParameter(BasePtpParameterTestCase):
|
||||||
|
""" Tests deletion.
|
||||||
|
Typically delete APIs return NO CONTENT.
|
||||||
|
python2 and python3 libraries may return different
|
||||||
|
content_type (None, or empty json) when NO_CONTENT returned.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestDeletePtpParameter, self).setUp()
|
||||||
|
|
||||||
|
def test_delete_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)
|
||||||
|
uuid = ptp_parameter['uuid']
|
||||||
|
|
||||||
|
response = self.delete(self.get_single_url(uuid),
|
||||||
|
headers=self.API_HEADERS)
|
||||||
|
self.assertEqual(response.status_code, http_client.NO_CONTENT)
|
||||||
|
|
||||||
|
# Check the instance was indeed removed
|
||||||
|
error_message = 'No PTP parameter with id %s found' % uuid
|
||||||
|
response = self.get_json(self.get_single_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'])
|
@ -447,6 +447,29 @@ class BaseHostTestCase(BaseSystemTestCase):
|
|||||||
index = index + 1
|
index = index + 1
|
||||||
return ifaces
|
return ifaces
|
||||||
|
|
||||||
|
def _create_test_ptp_instance(self, host):
|
||||||
|
services = [constants.PTP_INSTANCE_TYPE_PTP4L,
|
||||||
|
constants.PTP_INSTANCE_TYPE_PHC2SYS]
|
||||||
|
names = [constants.PTP_INSTANCE_DEFAULT_PTP4L,
|
||||||
|
constants.PTP_INSTANCE_DEFAULT_PHC2SYS]
|
||||||
|
ptp_instances = []
|
||||||
|
for svc, nm in zip(services, names):
|
||||||
|
instance = dbutils.create_test_ptp_instance(
|
||||||
|
name=nm, service=svc, host_id=host['id'])
|
||||||
|
ptp_instances.append(instance)
|
||||||
|
return ptp_instances
|
||||||
|
|
||||||
|
def _create_test_ptp_interface(self,
|
||||||
|
ptp_instances,
|
||||||
|
platform_interfaces):
|
||||||
|
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_interfaces.append(ptp_interface)
|
||||||
|
return ptp_interfaces
|
||||||
|
|
||||||
|
|
||||||
class ControllerHostTestCase(BaseHostTestCase):
|
class ControllerHostTestCase(BaseHostTestCase):
|
||||||
|
|
||||||
|
@ -2030,6 +2030,7 @@ class TestMigrations(BaseMigrationTestCase, WalkVersionsMixin):
|
|||||||
'uuid': 'String',
|
'uuid': 'String',
|
||||||
'name': 'String',
|
'name': 'String',
|
||||||
'value': 'String',
|
'value': 'String',
|
||||||
|
'type': 'String',
|
||||||
'foreign_uuid': 'String',
|
'foreign_uuid': 'String',
|
||||||
}
|
}
|
||||||
for column, column_type in ptp_parameters_columns.items():
|
for column, column_type in ptp_parameters_columns.items():
|
||||||
|
@ -536,25 +536,27 @@ def create_test_ptp(**kw):
|
|||||||
return dbapi.ptp_create(ptp)
|
return dbapi.ptp_create(ptp)
|
||||||
|
|
||||||
|
|
||||||
# Create test ptp_instance object
|
# Utility functions to create a PTP instance for testing
|
||||||
def get_test_ptp_instance(**kw):
|
def get_test_ptp_instance(**kw):
|
||||||
ptp_instance = {
|
instance = {
|
||||||
'id': kw.get('id'),
|
'id': kw.get('id'),
|
||||||
'uuid': kw.get('uuid'),
|
'uuid': kw.get('uuid'),
|
||||||
'name': kw.get('name'),
|
'name': kw.get('name', None),
|
||||||
'service': kw.get('service'),
|
'service': kw.get('service', constants.PTP_INSTANCE_TYPE_PTP4L),
|
||||||
'host_id': kw.get('host_id'),
|
'host_id': kw.get('host_id', None)
|
||||||
}
|
}
|
||||||
return ptp_instance
|
return instance
|
||||||
|
|
||||||
|
|
||||||
def create_test_ptp_instance(**kw):
|
def create_test_ptp_instance(**kw):
|
||||||
ptp_instance = get_test_ptp_instance(**kw)
|
instance = get_test_ptp_instance(**kw)
|
||||||
# Let DB generate ID if it isn't specified explicitly
|
# Let DB generate ID if isn't specified
|
||||||
if 'id' not in kw:
|
if 'id' not in kw:
|
||||||
del ptp_instance['id']
|
del instance['id']
|
||||||
|
if 'uuid' in kw:
|
||||||
|
del instance['uuid']
|
||||||
dbapi = db_api.get_instance()
|
dbapi = db_api.get_instance()
|
||||||
return dbapi.ptp_instance_create(ptp_instance)
|
return dbapi.ptp_instance_create(instance)
|
||||||
|
|
||||||
|
|
||||||
# Create test ptp_interface object
|
# Create test ptp_interface object
|
||||||
@ -575,6 +577,30 @@ def create_test_ptp_interface(**kw):
|
|||||||
return dbapi.ptp_interface_create(ptp_interface)
|
return dbapi.ptp_interface_create(ptp_interface)
|
||||||
|
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
# Create test dns object
|
# Create test dns object
|
||||||
def get_test_dns(**kw):
|
def get_test_dns(**kw):
|
||||||
dns = {
|
dns = {
|
||||||
|
Loading…
Reference in New Issue
Block a user