Support for NTP/PTP coexistence
The NTP/PTP selection will now be done per host. NTP will the default selection. This commit; -Removes the enabled flag NTP and PTP API. Updates the CLI commands and the database. -Adds the parameter clock_synchronization to the host API. Valid values are ‘ntp’ and ‘ptp’. Updates the host CLI commands and the database. -Updates puppet to set NTP/PTP per host . -Updates the RestAPI documentation. Story: 2006499 Task: 36464 Change-Id: I37bbb30a014301f8786cb02e35f0a1bd39d2f4aa Signed-off-by: Kristine Bujold <kristine.bujold@windriver.com>
This commit is contained in:
parent
6f04c28cd4
commit
2d17e9849f
@ -4311,6 +4311,162 @@ badMediaType (415)
|
||||
"uuid":"81321749-5092-4faf-94ba-6a6853440725"
|
||||
}
|
||||
|
||||
|
||||
----
|
||||
PTP
|
||||
----
|
||||
|
||||
The PTP is the Precision Time Protocol entity for the system.
|
||||
|
||||
************************************
|
||||
Shows attributes of the PTP object
|
||||
************************************
|
||||
|
||||
.. rest_method:: GET /v1/ptp
|
||||
|
||||
**Normal response codes**
|
||||
|
||||
200
|
||||
|
||||
**Error response codes**
|
||||
|
||||
computeFault (400, 500, ...), serviceUnavailable (503), badRequest (400),
|
||||
unauthorized (401), forbidden (403), badMethod (405), overLimit (413),
|
||||
itemNotFound (404)
|
||||
|
||||
**Response parameters**
|
||||
|
||||
.. csv-table::
|
||||
:header: "Parameter", "Style", "Type", "Description"
|
||||
:widths: 20, 20, 20, 60
|
||||
|
||||
"mode (Optional)", "plain", "xsd:string", "PTP time stamping mode."
|
||||
"transport (Optional)", "plain", "xsd:string", "PTP transport protocol."
|
||||
"mechanism (Optional)", "plain", "xsd:string", "PTP delay mechanism."
|
||||
"isystem_uuid (Optional)", "plain", "csapi:UUID", "The System UUID which the PTP belongs to."
|
||||
"uuid (Optional)", "plain", "csapi:UUID", "The universally unique identifier for this object."
|
||||
"links (Optional)", "plain", "xsd:list", "For convenience, resources contain links to themselves. This allows a client to easily obtain rather than construct resource URIs. The following types of link relations are associated with resources: a self link containing a versioned link to the resource, and a bookmark link containing a permanent link to a resource that is appropriate for long term storage."
|
||||
"created_at (Optional)", "plain", "xsd:dateTime", "The time when the object was created."
|
||||
"updated_at (Optional)", "plain", "xsd:dateTime", "The time when the object was last updated."
|
||||
|
||||
::
|
||||
|
||||
{
|
||||
"ptp":[
|
||||
{
|
||||
"links":[
|
||||
{
|
||||
"href":"http://192.168.204.2:6385/v1/ptps/70649b44-b462-445a-9fa5-9233a1b5842d",
|
||||
"rel":"self"
|
||||
},
|
||||
{
|
||||
"href":"http://192.168.204.2:6385/ptps/70649b44-b462-445a-9fa5-9233a1b5842d",
|
||||
"rel":"bookmark"
|
||||
}
|
||||
],
|
||||
"created_at":"2019-09-30T14:42:16.693209+00:00",
|
||||
"updated_at":"2019-10-01T17:33:43.169595+00:00",
|
||||
"mechanism":"e2e",
|
||||
"mode":"hardware",
|
||||
"transport":"l2",
|
||||
"isystem_uuid":"ce178041-2b2c-405d-bf87-f19334a35582",
|
||||
"uuid":"70649b44-b462-445a-9fa5-9233a1b5842d"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
This operation does not accept a request body.
|
||||
|
||||
***************************************
|
||||
Modifies attributes of the PTP object
|
||||
***************************************
|
||||
|
||||
.. rest_method:: PATCH /v1/ptp/{ptp_id}
|
||||
|
||||
The attributes of the PTP object that are configurable are:
|
||||
|
||||
- mode
|
||||
- transport
|
||||
- mechanism
|
||||
|
||||
**Normal response codes**
|
||||
|
||||
200
|
||||
|
||||
**Error response codes**
|
||||
|
||||
badMediaType (415)
|
||||
|
||||
**Request parameters**
|
||||
|
||||
.. csv-table::
|
||||
:header: "Parameter", "Style", "Type", "Description"
|
||||
:widths: 20, 20, 20, 60
|
||||
|
||||
"ptp_id", "URI", "csapi:UUID", "The unique identifier of the PTP for this system."
|
||||
"mode (Optional)", "plain", "xsd:string", "PTP time stamping mode. Valid values are (is): ``hardware``, ``software`` or ``legacy``"
|
||||
"transport (Optional)", "plain", "xsd:string", "PTP transport protocol. Valid values are (is): ``udp`` or ``l2``"
|
||||
"mechanism (Optional)", "plain", "xsd:string", "PTP delay mechanism. Valid values are (is): ``e2e`` or ``p2p``"
|
||||
|
||||
**Response parameters**
|
||||
|
||||
.. csv-table::
|
||||
:header: "Parameter", "Style", "Type", "Description"
|
||||
:widths: 20, 20, 20, 60
|
||||
|
||||
"mode (Optional)", "plain", "xsd:string", "PTP time stamping mode."
|
||||
"transport (Optional)", "plain", "xsd:string", "PTP transport protocol."
|
||||
"mechanism (Optional)", "plain", "xsd:string", "PTP delay mechanism."
|
||||
"isystem_uuid (Optional)", "plain", "csapi:UUID", "The System UUID which the NTP belongs to."
|
||||
"uuid (Optional)", "plain", "csapi:UUID", "The universally unique identifier for this object."
|
||||
"links (Optional)", "plain", "xsd:list", "For convenience, resources contain links to themselves. This allows a client to easily obtain rather than construct resource URIs. The following types of link relations are associated with resources: a self link containing a versioned link to the resource, and a bookmark link containing a permanent link to a resource that is appropriate for long term storage."
|
||||
"created_at (Optional)", "plain", "xsd:dateTime", "The time when the object was created."
|
||||
"updated_at (Optional)", "plain", "xsd:dateTime", "The time when the object was last updated."
|
||||
|
||||
::
|
||||
|
||||
[
|
||||
{
|
||||
"path": "/mode",
|
||||
"value": "legacy",
|
||||
"op": "replace"
|
||||
},
|
||||
{
|
||||
"path": "/transport",
|
||||
"value": "udp",
|
||||
"op": "replace"
|
||||
},
|
||||
{
|
||||
"path": "/mechanism",
|
||||
"value": "p2p",
|
||||
"op": "replace"
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
::
|
||||
|
||||
{
|
||||
"links":[
|
||||
{
|
||||
"href":"http://192.168.204.2:6385/v1/ptps/70649b44-b462-445a-9fa5-9233a1b5842d",
|
||||
"rel":"self"
|
||||
},
|
||||
{
|
||||
"href":"http://192.168.204.2:6385/ptps/70649b44-b462-445a-9fa5-9233a1b5842d",
|
||||
"rel":"bookmark"
|
||||
}
|
||||
],
|
||||
"created_at":"2014-09-30T14:42:16.693209+00:00",
|
||||
"updated_at":"2014-10-01T17:35:43.162472+00:00",
|
||||
"mechanism": "p2p"
|
||||
"mode": "legacy"
|
||||
"transport": "udp"
|
||||
"isystem_uuid":"ce178041-2b2c-405d-bf87-f19334a35582",
|
||||
"forisystemid":1,
|
||||
"uuid":"70649b44-b462-445a-9fa5-9233a1b5842d"
|
||||
}
|
||||
|
||||
-------------
|
||||
External OAM
|
||||
-------------
|
||||
@ -10896,7 +11052,7 @@ itemNotFound (404)
|
||||
"registry_images": [
|
||||
{
|
||||
"tag": null,
|
||||
"name": "docker.io/starlingx/ceph-config-helper"
|
||||
"name": "docker.io/starlingx/ceph-config-helper"
|
||||
},
|
||||
{
|
||||
"tag": null,
|
||||
@ -10946,8 +11102,8 @@ itemNotFound (404)
|
||||
{
|
||||
"registry_images": [
|
||||
{
|
||||
"tag": "v1.15.0",
|
||||
"name": "docker.io/starlingx/ceph-config-helper"
|
||||
"tag": "v1.15.0",
|
||||
"name": "docker.io/starlingx/ceph-config-helper"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
SRC_DIR="cgts-client"
|
||||
TIS_PATCH_VER=70
|
||||
TIS_PATCH_VER=71
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (c) 2013-2017 Wind River Systems, Inc.
|
||||
# Copyright (c) 2013-2019 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
@ -35,7 +35,7 @@ def _print_ihost_show(ihost):
|
||||
'location', 'uptime', 'reserved', 'created_at', 'updated_at',
|
||||
'boot_device', 'rootfs_device', 'install_output', 'console',
|
||||
'tboot', 'vim_progress_status', 'software_load', 'install_state',
|
||||
'install_state_info', 'inv_state']
|
||||
'install_state_info', 'inv_state', 'clock_synchronization']
|
||||
optional_fields = ['vsc_controllers', 'ttys_dcd']
|
||||
if ihost.subfunctions != ihost.personality:
|
||||
fields.append('subfunctions')
|
||||
@ -141,13 +141,18 @@ def do_host_upgrade_list(cc, args):
|
||||
@utils.arg('-D', '--ttys_dcd',
|
||||
metavar='<true/false>',
|
||||
help='Enable/disable serial console data carrier detection')
|
||||
@utils.arg('-C', '--clock_synchronization',
|
||||
metavar='<clock_synchronization>',
|
||||
choices=['ntp', 'ptp'],
|
||||
help='Clock synchronization, ntp or ptp. Default: ntp')
|
||||
def do_host_add(cc, args):
|
||||
"""Add a new host."""
|
||||
field_list = ['hostname', 'personality', 'subfunctions',
|
||||
'mgmt_mac', 'mgmt_ip',
|
||||
'bm_ip', 'bm_type', 'bm_username', 'bm_password',
|
||||
'boot_device', 'rootfs_device', 'install_output', 'console',
|
||||
'vsc_controllers', 'location', 'ttys_dcd']
|
||||
'vsc_controllers', 'location', 'ttys_dcd',
|
||||
'clock_synchronization']
|
||||
fields = dict((k, v) for (k, v) in vars(args).items()
|
||||
if k in field_list and not (v is None))
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2013-2015 Wind River Systems, Inc.
|
||||
# Copyright (c) 2013-2019 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
@ -20,7 +20,7 @@ CREATION_ATTRIBUTES = ['hostname', 'personality', 'subfunctions',
|
||||
'boot_device', 'rootfs_device', 'install_output',
|
||||
'console', 'tboot', 'vsc_controllers', 'ttys_dcd',
|
||||
'administrative', 'operational', 'availability',
|
||||
'invprovision']
|
||||
'invprovision', 'clock_synchronization']
|
||||
|
||||
|
||||
class ihost(base.Resource):
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (c) 2013-2017 Wind River Systems, Inc.
|
||||
# Copyright (c) 2013-2019 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
@ -14,8 +14,7 @@ from cgtsclient import exc
|
||||
|
||||
|
||||
def _print_intp_show(intp):
|
||||
fields = ['uuid', 'enabled', 'ntpservers',
|
||||
'isystem_uuid', 'created_at', 'updated_at']
|
||||
fields = ['uuid', 'ntpservers', 'isystem_uuid', 'created_at', 'updated_at']
|
||||
data = [(f, getattr(intp, f, '')) for f in fields]
|
||||
utils.print_tuple_list(data)
|
||||
|
||||
@ -34,8 +33,8 @@ def donot_config_ntp_list(cc, args):
|
||||
|
||||
intps = cc.intp.list()
|
||||
|
||||
field_labels = ['uuid', 'enabled', 'ntpservers']
|
||||
fields = ['uuid', 'enabled', 'ntpservers']
|
||||
field_labels = ['uuid', 'ntpservers']
|
||||
fields = ['uuid', 'ntpservers']
|
||||
utils.print_list(intps, fields, field_labels, sortby=1)
|
||||
|
||||
|
||||
@ -70,9 +69,6 @@ def donot_ntp_add(cc, args):
|
||||
_print_intp_show(intp)
|
||||
|
||||
|
||||
@utils.arg('--enabled',
|
||||
metavar='<true/false>',
|
||||
help="NTP service enabled.")
|
||||
@utils.arg('attributes',
|
||||
metavar='<path=value>',
|
||||
nargs='*',
|
||||
@ -86,9 +82,6 @@ def do_ntp_modify(cc, args):
|
||||
intp = intps[0]
|
||||
op = "replace"
|
||||
|
||||
if args.enabled is not None:
|
||||
args.attributes[0].append('enabled=%s' % args.enabled)
|
||||
|
||||
for attribute in args.attributes:
|
||||
if 'ntpservers=' in attribute:
|
||||
ntpservers = attribute[0].split('=')[1]
|
||||
|
@ -1,6 +1,6 @@
|
||||
########################################################################
|
||||
#
|
||||
# Copyright (c) 2018 Wind River Systems, Inc.
|
||||
# Copyright (c) 2018-2019 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
@ -11,7 +11,7 @@ from cgtsclient import exc
|
||||
|
||||
|
||||
def _print_ptp_show(ptp):
|
||||
fields = ['uuid', 'enabled', 'mode', 'transport', 'mechanism',
|
||||
fields = ['uuid', 'mode', 'transport', 'mechanism',
|
||||
'isystem_uuid', 'created_at', 'updated_at']
|
||||
data = [(f, getattr(ptp, f, '')) for f in fields]
|
||||
utils.print_tuple_list(data)
|
||||
@ -30,14 +30,11 @@ def donot_config_ptp_list(cc, args):
|
||||
|
||||
ptps = cc.ptp.list()
|
||||
|
||||
field_labels = ['uuid', 'enabled', 'mode', 'transport', 'mechanism']
|
||||
fields = ['uuid', 'enabled', 'mode', 'transport', 'mechanism']
|
||||
field_labels = ['uuid', 'mode', 'transport', 'mechanism']
|
||||
fields = ['uuid', 'mode', 'transport', 'mechanism']
|
||||
utils.print_list(ptps, fields, field_labels, sortby=1)
|
||||
|
||||
|
||||
@utils.arg('--enabled',
|
||||
metavar='<true/false>',
|
||||
help="PTP service enabled.")
|
||||
@utils.arg('--mode',
|
||||
metavar='<mode>',
|
||||
default=None,
|
||||
@ -58,8 +55,7 @@ def do_ptp_modify(cc, args):
|
||||
op = "replace"
|
||||
|
||||
attributes = []
|
||||
if args.enabled is not None:
|
||||
attributes.append('enabled=%s' % args.enabled)
|
||||
|
||||
if args.mode is not None:
|
||||
attributes.append('mode=%s' % args.mode)
|
||||
if args.transport is not None:
|
||||
|
@ -1,2 +1,2 @@
|
||||
SRC_DIR="sysinv"
|
||||
TIS_PATCH_VER=331
|
||||
TIS_PATCH_VER=332
|
||||
|
@ -422,6 +422,9 @@ class Host(base.APIBase):
|
||||
config_target = wtypes.text
|
||||
"Represent the configuration which needs to be applied to this ihost."
|
||||
|
||||
clock_synchronization = wtypes.text
|
||||
"Represent the clock synchronization type of this ihost."
|
||||
|
||||
# Host uptime
|
||||
uptime = int
|
||||
|
||||
@ -563,7 +566,7 @@ class Host(base.APIBase):
|
||||
'software_load', 'target_load', 'peers', 'peer_id',
|
||||
'install_state', 'install_state_info',
|
||||
'iscsi_initiator_name',
|
||||
'inv_state']
|
||||
'inv_state', 'clock_synchronization']
|
||||
|
||||
fields = minimum_fields if not expand else None
|
||||
uhost = Host.from_rpc_object(rpc_ihost, fields)
|
||||
@ -1867,6 +1870,14 @@ class HostController(rest.RestController):
|
||||
LOG.exception(e)
|
||||
raise wsme.exc.ClientSideError(_("Patching Error: %s") % e)
|
||||
|
||||
if patched_ihost['clock_synchronization'] not in \
|
||||
constants.CLOCK_SYNCHRONIZATION:
|
||||
msg = _("Host update failed: clock_synchronization: "
|
||||
"invalid choice: '%s', choose from %s" %
|
||||
(patched_ihost['clock_synchronization'],
|
||||
constants.CLOCK_SYNCHRONIZATION))
|
||||
raise wsme.exc.ClientSideError(msg)
|
||||
|
||||
self._validate_capabilities(
|
||||
ihost_dict['capabilities'], patched_ihost['capabilities'])
|
||||
|
||||
@ -2203,6 +2214,11 @@ class HostController(rest.RestController):
|
||||
self._handle_ttys_dcd_change(hostupdate.ihost_orig,
|
||||
hostupdate.ihost_patch['ttys_dcd'])
|
||||
|
||||
if 'clock_synchronization' in hostupdate.delta:
|
||||
# perform rpc to conductor to perform config apply
|
||||
pecan.request.rpcapi.update_clock_synchronization_config(
|
||||
pecan.request.context, patched_ihost)
|
||||
|
||||
log_end = cutils.timestamped("ihost_patch_end")
|
||||
if uptime_update:
|
||||
LOG.debug("host %s %s patch" % (ihost_obj.hostname,
|
||||
@ -2212,8 +2228,8 @@ class HostController(rest.RestController):
|
||||
log_end))
|
||||
|
||||
if ('administrative' in hostupdate.delta and
|
||||
hostupdate.ihost_patch['administrative'] ==
|
||||
constants.ADMIN_LOCKED):
|
||||
hostupdate.ihost_patch['administrative'] ==
|
||||
constants.ADMIN_LOCKED):
|
||||
LOG.info("Update host memory for (%s)" % ihost_obj['hostname'])
|
||||
pecan.request.rpcapi.update_host_memory(pecan.request.context,
|
||||
ihost_obj['uuid'])
|
||||
|
@ -16,7 +16,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# Copyright (c) 2013-2017 Wind River Systems, Inc.
|
||||
# Copyright (c) 2013-2019 Wind River Systems, Inc.
|
||||
#
|
||||
|
||||
|
||||
@ -66,9 +66,6 @@ class NTP(base.APIBase):
|
||||
uuid = types.uuid
|
||||
"Unique UUID for this ntp"
|
||||
|
||||
enabled = types.boolean
|
||||
"Represent the status of the intp."
|
||||
|
||||
ntpservers = wtypes.text
|
||||
"Represent the ntpservers of the intp. csv list."
|
||||
|
||||
@ -105,7 +102,6 @@ class NTP(base.APIBase):
|
||||
ntp = NTP(**rpc_ntp.as_dict())
|
||||
if not expand:
|
||||
ntp.unset_fields_except(['uuid',
|
||||
'enabled',
|
||||
'ntpservers',
|
||||
'isystem_uuid',
|
||||
'created_at',
|
||||
@ -152,23 +148,12 @@ class intpCollection(collection.Collection):
|
||||
##############
|
||||
def _check_ntp_data(op, ntp):
|
||||
# Get data
|
||||
enabled = ntp['enabled']
|
||||
ntpservers = ntp['ntpservers']
|
||||
intp_ntpservers_list = []
|
||||
ntp_ntpservers = ""
|
||||
idns_nameservers_list = []
|
||||
|
||||
MAX_S = 3
|
||||
|
||||
ptp_list = pecan.request.dbapi.ptp_get_by_isystem(ntp['forisystemid'])
|
||||
|
||||
if ptp_list:
|
||||
if hasattr(ptp_list[0], 'enabled'):
|
||||
if ptp_list[0].enabled is True and enabled is True:
|
||||
raise wsme.exc.ClientSideError(_(
|
||||
"NTP cannot be configured alongside with PTP."
|
||||
" Please disable PTP before enabling NTP."))
|
||||
|
||||
dns_list = pecan.request.dbapi.idns_get_by_isystem(ntp['forisystemid'])
|
||||
|
||||
if dns_list:
|
||||
@ -184,7 +169,8 @@ def _check_ntp_data(op, ntp):
|
||||
|
||||
except (AddrFormatError, ValueError):
|
||||
if utils.is_valid_hostname(ntpserver):
|
||||
# If server address in FQDN, and no DNS servers, raise error
|
||||
# If server address in FQDN, and no DNS servers,
|
||||
# raise error
|
||||
if len(idns_nameservers_list) == 0 and ntpserver != 'NC':
|
||||
raise wsme.exc.ClientSideError(_(
|
||||
"A DNS server must be configured prior to "
|
||||
@ -200,9 +186,9 @@ def _check_ntp_data(op, ntp):
|
||||
raise wsme.exc.ClientSideError(_(
|
||||
"Invalid NTP server %s "
|
||||
"Please configure a valid NTP "
|
||||
"IP address or hostname.") % (ntpserver))
|
||||
"IP address or hostname.") % ntpserver)
|
||||
|
||||
if len(intp_ntpservers_list) == 0 and enabled is None:
|
||||
if len(intp_ntpservers_list) == 0:
|
||||
raise wsme.exc.ClientSideError(_("No NTP parameters provided."))
|
||||
|
||||
if len(intp_ntpservers_list) > MAX_S:
|
||||
@ -270,7 +256,7 @@ class NTPController(rest.RestController):
|
||||
"""Retrieve a list of ntps. Only one per system"""
|
||||
|
||||
return self._get_ntps_collection(isystem_uuid, marker, limit,
|
||||
sort_key, sort_dir)
|
||||
sort_key, sort_dir)
|
||||
|
||||
@wsme_pecan.wsexpose(intpCollection, types.uuid, types.uuid, int,
|
||||
wtypes.text, wtypes.text)
|
||||
@ -359,18 +345,13 @@ class NTPController(rest.RestController):
|
||||
rpc_ntp[field] = ntp[field]
|
||||
|
||||
delta = rpc_ntp.obj_what_changed()
|
||||
delta_handle = list(delta)
|
||||
if delta:
|
||||
rpc_ntp.save()
|
||||
|
||||
if 'enabled' in delta_handle:
|
||||
service_change = True
|
||||
else:
|
||||
service_change = False
|
||||
if action == constants.APPLY_ACTION:
|
||||
# perform rpc to conductor to perform config apply
|
||||
pecan.request.rpcapi.update_ntp_config(pecan.request.context,
|
||||
service_change)
|
||||
pecan.request.rpcapi.update_ntp_config(
|
||||
pecan.request.context)
|
||||
else:
|
||||
LOG.info("No NTP config changes")
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
########################################################################
|
||||
#
|
||||
# Copyright (c) 2018 Wind River Systems, Inc.
|
||||
# Copyright (c) 2018-2019 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
@ -48,9 +48,6 @@ class PTP(base.APIBase):
|
||||
uuid = types.uuid
|
||||
"Unique UUID for this ptp"
|
||||
|
||||
enabled = types.boolean
|
||||
"Represent the status of the ptp."
|
||||
|
||||
mode = wtypes.Enum(str, 'hardware', 'software', 'legacy')
|
||||
"Time stamping mode used by ptp."
|
||||
|
||||
@ -80,7 +77,6 @@ class PTP(base.APIBase):
|
||||
ptp = PTP(**rpc_ptp.as_dict())
|
||||
if not expand:
|
||||
ptp.unset_fields_except(['uuid',
|
||||
'enabled',
|
||||
'mode',
|
||||
'transport',
|
||||
'mechanism',
|
||||
@ -118,21 +114,6 @@ class ptpCollection(collection.Collection):
|
||||
return collection
|
||||
|
||||
|
||||
##############
|
||||
# UTILS
|
||||
##############
|
||||
def _check_ptp_data(op, ptp):
|
||||
enabled = ptp['enabled']
|
||||
ntp_list = pecan.request.dbapi.intp_get_by_isystem(ptp['isystem_uuid'])
|
||||
if ntp_list:
|
||||
if hasattr(ntp_list[0], 'enabled'):
|
||||
if ntp_list[0].enabled is True and enabled is True:
|
||||
raise wsme.exc.ClientSideError(_(
|
||||
"PTP cannot be configured alongside with NTP."
|
||||
" Please disable NTP before enabling PTP."))
|
||||
return ptp
|
||||
|
||||
|
||||
LOCK_NAME = 'PTPController'
|
||||
|
||||
|
||||
@ -223,7 +204,7 @@ class PTPController(rest.RestController):
|
||||
except utils.JSONPATCH_EXCEPTIONS as e:
|
||||
raise exception.PatchError(patch=patch, reason=e)
|
||||
|
||||
ptp = _check_ptp_data("modify", ptp.as_dict())
|
||||
ptp = ptp.as_dict()
|
||||
|
||||
try:
|
||||
# Update only the fields that have changed
|
||||
@ -242,9 +223,8 @@ class PTPController(rest.RestController):
|
||||
return PTP.convert_with_links(rpc_ptp)
|
||||
|
||||
except exception.HTTPNotFound:
|
||||
msg = _("PTP update failed: enabled %s : %s %s %s : patch %s"
|
||||
% (ptp['enabled'], ptp['mode'], ptp['transport'],
|
||||
ptp['mechanism'], patch))
|
||||
msg = _("PTP update failed: %s %s %s : patch %s" %
|
||||
(ptp['mode'], ptp['transport'], ptp['mechanism'], patch))
|
||||
raise wsme.exc.ClientSideError(msg)
|
||||
|
||||
@wsme_pecan.wsexpose(None, types.uuid, status_code=204)
|
||||
|
@ -1457,3 +1457,12 @@ DEFAULT_DNS_SERVICE_DOMAIN = 'cluster.local'
|
||||
ANSIBLE_BOOTSTRAP_FLAG = os.path.join(tsc.VOLATILE_PATH, ".ansible_bootstrap")
|
||||
UNLOCK_READY_FLAG = os.path.join(tsc.PLATFORM_CONF_PATH, ".unlock_ready")
|
||||
INVENTORY_WAIT_TIMEOUT_IN_SECS = 90
|
||||
|
||||
# Clock synchronization types
|
||||
NTP = 'ntp'
|
||||
PTP = 'ptp'
|
||||
|
||||
CLOCK_SYNCHRONIZATION = [
|
||||
NTP,
|
||||
PTP
|
||||
]
|
||||
|
@ -1621,7 +1621,7 @@ class ConductorManager(service.PeriodicService):
|
||||
:param do_worker_apply: configure the worker subfunctions of the host.
|
||||
"""
|
||||
|
||||
LOG.debug("configure_ihost %s" % host.hostname)
|
||||
LOG.info("configure_ihost %s" % host.hostname)
|
||||
|
||||
# Generate system configuration files
|
||||
# TODO(mpeters): remove this once all system reconfigurations properly
|
||||
@ -5385,14 +5385,17 @@ class ConductorManager(service.PeriodicService):
|
||||
config_uuid = self._config_update_hosts(context, personalities)
|
||||
self._update_resolv_file(context, config_uuid, personalities)
|
||||
|
||||
def update_ntp_config(self, context, service_change=False):
|
||||
def update_clock_synchronization_config(self, context, host):
|
||||
"""Update clock_synchronization configuration of a host"""
|
||||
personalities = [host.get('personality')]
|
||||
self._config_update_hosts(context, personalities, [host.get('uuid')],
|
||||
reboot=True)
|
||||
|
||||
def update_ntp_config(self, context):
|
||||
"""Update the NTP configuration"""
|
||||
if service_change:
|
||||
personalities = [constants.CONTROLLER,
|
||||
constants.WORKER,
|
||||
constants.STORAGE]
|
||||
else:
|
||||
personalities = [constants.CONTROLLER]
|
||||
personalities = [constants.CONTROLLER,
|
||||
constants.WORKER,
|
||||
constants.STORAGE]
|
||||
self._config_update_hosts(context, personalities, reboot=True)
|
||||
|
||||
def update_ptp_config(self, context):
|
||||
|
@ -726,13 +726,23 @@ class ConductorAPI(sysinv.openstack.common.rpc.proxy.RpcProxy):
|
||||
"""
|
||||
return self.call(context, self.make_msg('update_dns_config'))
|
||||
|
||||
def update_ntp_config(self, context, service_change=False):
|
||||
def update_clock_synchronization_config(self, context, host):
|
||||
"""Synchronously, have the conductor update the
|
||||
clock_synchronization configuration of a host.
|
||||
|
||||
:param context: request context.
|
||||
:param host: the host to be modified.
|
||||
"""
|
||||
return self.call(context,
|
||||
self.make_msg('update_clock_synchronization_config',
|
||||
host=host))
|
||||
|
||||
def update_ntp_config(self, context):
|
||||
"""Synchronously, have the conductor update the NTP configuration.
|
||||
|
||||
:param context: request context.
|
||||
"""
|
||||
return self.call(context, self.make_msg('update_ntp_config',
|
||||
service_change=service_change))
|
||||
return self.call(context, self.make_msg('update_ntp_config'))
|
||||
|
||||
def update_ptp_config(self, context):
|
||||
"""Synchronously, have the conductor update the PTP configuration.
|
||||
|
@ -0,0 +1,43 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright (c) 2019 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
from sqlalchemy import Column, MetaData, Table
|
||||
from sqlalchemy import String
|
||||
from sysinv.common import constants
|
||||
|
||||
ENGINE = 'InnoDB'
|
||||
CHARSET = 'utf8'
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
"""
|
||||
This database upgrade creates a new host clock_synchronization attribute
|
||||
for storing the clock_synchronization type (ntp/ptp) for a host.
|
||||
"""
|
||||
|
||||
meta = MetaData()
|
||||
meta.bind = migrate_engine
|
||||
|
||||
host = Table('i_host', meta, autoload=True)
|
||||
host.create_column(Column('clock_synchronization', String(32)),
|
||||
default=constants.NTP)
|
||||
|
||||
ntp = Table('i_ntp', meta, autoload=True)
|
||||
ntp.drop_column(Column('enabled'))
|
||||
|
||||
ptp = Table('ptp', meta, autoload=True)
|
||||
ptp.drop_column(Column('enabled'))
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def downgrade(migrate_engine):
|
||||
meta = MetaData()
|
||||
meta.bind = migrate_engine
|
||||
|
||||
# Downgrade is unsupported.
|
||||
raise NotImplementedError('SysInv database downgrade is unsupported.')
|
@ -223,6 +223,8 @@ class ihost(Base):
|
||||
config_applied = Column(String(255))
|
||||
config_target = Column(String(255))
|
||||
|
||||
clock_synchronization = Column(String(32), default=constants.NTP)
|
||||
|
||||
boot_device = Column(String(255), default="/dev/sda")
|
||||
rootfs_device = Column(String(255), default="/dev/sda")
|
||||
install_output = Column(String(255), default="text")
|
||||
@ -777,7 +779,6 @@ class intp(Base):
|
||||
id = Column(Integer, primary_key=True)
|
||||
uuid = Column(String(36))
|
||||
|
||||
enabled = Column(Boolean, default=True)
|
||||
ntpservers = Column(String(255)) # csv list of ntp servers
|
||||
|
||||
forisystemid = Column(Integer,
|
||||
@ -792,13 +793,12 @@ class PTP(Base):
|
||||
id = Column(Integer, primary_key=True)
|
||||
uuid = Column(String(36))
|
||||
|
||||
enabled = Column(Boolean, default=False)
|
||||
mode = Column(String(16), default='hardware')
|
||||
transport = Column(String(4), default='l2')
|
||||
mechanism = Column(String(4), default='e2e')
|
||||
|
||||
system_id = Column(Integer,
|
||||
ForeignKey('i_system.id', ondelete='CASCADE'))
|
||||
ForeignKey('i_system.id', ondelete='CASCADE'))
|
||||
|
||||
system = relationship("isystem", lazy="joined", join_depth=1)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2013-2017 Wind River Systems, Inc.
|
||||
# Copyright (c) 2013-2019 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
@ -75,6 +75,7 @@ class Host(base.SysinvObject):
|
||||
'config_applied': utils.str_or_none,
|
||||
'config_target': utils.str_or_none,
|
||||
'capabilities': utils.dict_or_none,
|
||||
'clock_synchronization': utils.str_or_none,
|
||||
|
||||
'boot_device': utils.str_or_none,
|
||||
'rootfs_device': utils.str_or_none,
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2013-2016 Wind River Systems, Inc.
|
||||
# Copyright (c) 2013-2019 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
@ -21,7 +21,6 @@ class NTP(base.SysinvObject):
|
||||
'id': int,
|
||||
'uuid': utils.str_or_none,
|
||||
|
||||
'enabled': utils.bool_or_none,
|
||||
'ntpservers': utils.str_or_none,
|
||||
|
||||
'forisystemid': utils.int_or_none,
|
||||
|
@ -1,6 +1,6 @@
|
||||
########################################################################
|
||||
#
|
||||
# Copyright (c) 2018 Wind River Systems, Inc.
|
||||
# Copyright (c) 2018-2019 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
@ -19,7 +19,6 @@ class PTP(base.SysinvObject):
|
||||
'id': int,
|
||||
'uuid': utils.str_or_none,
|
||||
|
||||
'enabled': utils.bool_or_none,
|
||||
'mode': utils.str_or_none,
|
||||
'transport': utils.str_or_none,
|
||||
'mechanism': utils.str_or_none,
|
||||
|
@ -411,8 +411,13 @@ class PlatformPuppet(base.BasePuppet):
|
||||
else:
|
||||
ntpdate_timeout = "30"
|
||||
|
||||
if host.clock_synchronization == constants.NTP:
|
||||
ntp_enabled = True
|
||||
else:
|
||||
ntp_enabled = False
|
||||
|
||||
return {
|
||||
'platform::ntp::enabled': ntp.enabled,
|
||||
'platform::ntp::enabled': ntp_enabled,
|
||||
'platform::ntp::servers': servers,
|
||||
'platform::ntp::ntpdate_timeout': ntpdate_timeout,
|
||||
}
|
||||
@ -420,9 +425,14 @@ class PlatformPuppet(base.BasePuppet):
|
||||
def _get_host_ptp_config(self, host):
|
||||
ptp = self.dbapi.ptp_get_one()
|
||||
|
||||
if host.clock_synchronization == constants.PTP:
|
||||
ptp_enabled = True
|
||||
else:
|
||||
ptp_enabled = False
|
||||
|
||||
return {
|
||||
'platform::ptp::enabled':
|
||||
ptp.enabled,
|
||||
ptp_enabled,
|
||||
'platform::ptp::mode':
|
||||
ptp.mode,
|
||||
'platform::ptp::transport':
|
||||
|
@ -33,6 +33,7 @@ class FakeConductorAPI(object):
|
||||
self.delete_barbican_secret = mock.MagicMock()
|
||||
self.iplatform_update_by_ihost = mock.MagicMock()
|
||||
self.evaluate_app_reapply = mock.MagicMock()
|
||||
self.update_clock_synchronization_config = mock.MagicMock()
|
||||
|
||||
def create_ihost(self, context, values):
|
||||
# Create the host in the DB as the code under test expects this
|
||||
@ -691,6 +692,38 @@ class TestPatch(TestHost):
|
||||
result = self.get_json('/ihosts/%s' % ndict['hostname'])
|
||||
self.assertEqual(new_location, result['location'])
|
||||
|
||||
def test_update_clock_synchronization(self):
|
||||
# Create controller-0
|
||||
ndict = dbutils.post_get_test_ihost(hostname='controller-0',
|
||||
mgmt_ip=None,
|
||||
serialid='serial1')
|
||||
self.post_json('/ihosts', ndict,
|
||||
headers={'User-Agent': 'sysinv-test'})
|
||||
|
||||
# Update clock_synchronization
|
||||
|
||||
response = self.patch_json('/ihosts/%s' % ndict['hostname'],
|
||||
[{'path': '/clock_synchronization',
|
||||
'value': constants.PTP,
|
||||
'op': 'replace'}],
|
||||
headers={'User-Agent': 'sysinv-test'})
|
||||
self.assertEqual(response.content_type, 'application/json')
|
||||
self.assertEqual(response.status_code, http_client.OK)
|
||||
|
||||
# Verify that the host was configured
|
||||
self.fake_conductor_api.configure_ihost.assert_called_once()
|
||||
|
||||
# Verify that the app reapply was checked
|
||||
self.fake_conductor_api.evaluate_app_reapply.assert_not_called()
|
||||
|
||||
# Verify that update_clock_synchronization_config was called
|
||||
self.fake_conductor_api.update_clock_synchronization_config.\
|
||||
assert_called_once()
|
||||
|
||||
# Verify that the host was updated with the new clock_synchronization
|
||||
result = self.get_json('/ihosts/%s' % ndict['hostname'])
|
||||
self.assertEqual(constants.PTP, result['clock_synchronization'])
|
||||
|
||||
def test_unlock_action_controller(self):
|
||||
self._configure_networks()
|
||||
# Create controller-0
|
||||
@ -768,7 +801,7 @@ class TestPatch(TestHost):
|
||||
administrative=constants.ADMIN_LOCKED,
|
||||
operational=constants.OPERATIONAL_ENABLED,
|
||||
availability=constants.AVAILABILITY_ONLINE,
|
||||
inv_state=None)
|
||||
inv_state=None, clock_synchronization=constants.NTP)
|
||||
|
||||
# Unlock host
|
||||
response = self._patch_host_action(c0_host['hostname'],
|
||||
|
@ -15,7 +15,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# Copyright (c) 2013-2018 Wind River Systems, Inc.
|
||||
# Copyright (c) 2013-2019 Wind River Systems, Inc.
|
||||
#
|
||||
|
||||
"""Sysinv test utilities."""
|
||||
@ -162,6 +162,7 @@ def get_test_ihost(**kw):
|
||||
'install_state_info': kw.get('install_state_info', None),
|
||||
'iscsi_initiator_name': kw.get('iscsi_initiator_name', None),
|
||||
'inv_state': kw.get('inv_state', 'inventoried'),
|
||||
'clock_synchronization': kw.get('clock_synchronization', constants.NTP),
|
||||
}
|
||||
return inv
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user