Deploy steps - API & notifications

Adds a 'deploy_step' field to the nodes API.

Co-Authored-By: Ruby Loo <rloo@oath.com>

Change-Id: I1baeeaaa6ed521e4189958fd7624cd6c5de96707
Story: #1753128
Task: #22592
This commit is contained in:
Mark Goddard 2018-07-03 19:37:39 +01:00 committed by Ruby Loo
parent 65a68e4e96
commit 5a14eed467
15 changed files with 84 additions and 24 deletions

View File

@ -86,6 +86,9 @@ supplied when the Node is created, or the resource may be updated later.
Introduced the ``rescue_interface`` field. If this field is not supplied Introduced the ``rescue_interface`` field. If this field is not supplied
when creating the Node, the default value will be used. when creating the Node, the default value will be used.
.. versionadded:: 1.44
Introduced the ``deploy_step`` field.
Normal response codes: 201 Normal response codes: 201
Error codes: 400,403,406 Error codes: 400,403,406
@ -132,7 +135,7 @@ and any defaults added for non-specified fields. Most fields default to "null"
or "". or "".
The list and example below are representative of the response as of API The list and example below are representative of the response as of API
microversion 1.43. microversion 1.44.
.. rest_parameters:: parameters.yaml .. rest_parameters:: parameters.yaml
@ -159,6 +162,7 @@ microversion 1.43.
- raid_config: raid_config - raid_config: raid_config
- target_raid_config: target_raid_config - target_raid_config: target_raid_config
- clean_step: clean_step - clean_step: clean_step
- deploy_step: deploy_step
- links: links - links: links
- ports: n_ports - ports: n_ports
- portgroups: n_portgroups - portgroups: n_portgroups
@ -333,6 +337,7 @@ Response
- raid_config: raid_config - raid_config: raid_config
- target_raid_config: target_raid_config - target_raid_config: target_raid_config
- clean_step: clean_step - clean_step: clean_step
- deploy_step: deploy_step
- links: links - links: links
- ports: n_ports - ports: n_ports
- portgroups: n_portgroups - portgroups: n_portgroups
@ -416,6 +421,7 @@ Response
- raid_config: raid_config - raid_config: raid_config
- target_raid_config: target_raid_config - target_raid_config: target_raid_config
- clean_step: clean_step - clean_step: clean_step
- deploy_step: deploy_step
- links: links - links: links
- ports: n_ports - ports: n_ports
- portgroups: n_portgroups - portgroups: n_portgroups
@ -500,6 +506,7 @@ Response
- raid_config: raid_config - raid_config: raid_config
- target_raid_config: target_raid_config - target_raid_config: target_raid_config
- clean_step: clean_step - clean_step: clean_step
- deploy_step: deploy_step
- links: links - links: links
- ports: n_ports - ports: n_ports
- portgroups: n_portgroups - portgroups: n_portgroups

View File

@ -492,6 +492,12 @@ deploy_interface:
in: body in: body
required: true required: true
type: string type: string
deploy_step:
description: |
The current deploy step.
in: body
required: false
type: string
description: description:
description: | description: |
Descriptive text about the Ironic service. Descriptive text about the Ironic service.

View File

@ -6,6 +6,7 @@
"console_interface": null, "console_interface": null,
"created_at": "2016-08-18T22:28:48.643434+11:11", "created_at": "2016-08-18T22:28:48.643434+11:11",
"deploy_interface": null, "deploy_interface": null,
"deploy_step": {},
"driver": "agent_ipmitool", "driver": "agent_ipmitool",
"driver_info": { "driver_info": {
"ipmi_password": "******", "ipmi_password": "******",

View File

@ -6,6 +6,7 @@
"console_interface": null, "console_interface": null,
"created_at": "2016-08-18T22:28:48.643434+11:11", "created_at": "2016-08-18T22:28:48.643434+11:11",
"deploy_interface": null, "deploy_interface": null,
"deploy_step": {},
"driver": "fake", "driver": "fake",
"driver_info": { "driver_info": {
"ipmi_password": "******", "ipmi_password": "******",

View File

@ -6,6 +6,7 @@
"console_interface": null, "console_interface": null,
"created_at": "2016-08-18T22:28:48.643434+11:11", "created_at": "2016-08-18T22:28:48.643434+11:11",
"deploy_interface": null, "deploy_interface": null,
"deploy_step": {},
"driver": "fake", "driver": "fake",
"driver_info": { "driver_info": {
"deploy_kernel": "http://127.0.0.1/images/kernel", "deploy_kernel": "http://127.0.0.1/images/kernel",

View File

@ -8,6 +8,7 @@
"console_interface": null, "console_interface": null,
"created_at": "2016-08-18T22:28:48.643434+11:11", "created_at": "2016-08-18T22:28:48.643434+11:11",
"deploy_interface": null, "deploy_interface": null,
"deploy_step": {},
"driver": "fake", "driver": "fake",
"driver_info": { "driver_info": {
"ipmi_password": "******", "ipmi_password": "******",
@ -105,6 +106,7 @@
"console_interface": "no-console", "console_interface": "no-console",
"created_at": "2016-08-18T22:28:48.643434+11:11", "created_at": "2016-08-18T22:28:48.643434+11:11",
"deploy_interface": "iscsi", "deploy_interface": "iscsi",
"deploy_step": {},
"driver": "ipmi", "driver": "ipmi",
"driver_info": { "driver_info": {
"ipmi_password": "******", "ipmi_password": "******",

View File

@ -132,12 +132,13 @@ Example of node CRUD notification::
"payload":{ "payload":{
"ironic_object.namespace":"ironic", "ironic_object.namespace":"ironic",
"ironic_object.name":"NodeCRUDPayload", "ironic_object.name":"NodeCRUDPayload",
"ironic_object.version":"1.5", "ironic_object.version":"1.6",
"ironic_object.data":{ "ironic_object.data":{
"chassis_uuid": "db0eef9d-45b2-4dc0-94a8-fc283c01171f", "chassis_uuid": "db0eef9d-45b2-4dc0-94a8-fc283c01171f",
"clean_step": None, "clean_step": None,
"console_enabled": False, "console_enabled": False,
"created_at": "2016-01-26T20:41:03+00:00", "created_at": "2016-01-26T20:41:03+00:00",
"deploy_step": None,
"driver": "ipmi", "driver": "ipmi",
"driver_info": { "driver_info": {
"ipmi_address": "192.168.0.111", "ipmi_address": "192.168.0.111",
@ -359,7 +360,7 @@ node maintenance notification::
"payload":{ "payload":{
"ironic_object.namespace":"ironic", "ironic_object.namespace":"ironic",
"ironic_object.name":"NodePayload", "ironic_object.name":"NodePayload",
"ironic_object.version":"1.8", "ironic_object.version":"1.9",
"ironic_object.data":{ "ironic_object.data":{
"clean_step": None, "clean_step": None,
"console_enabled": False, "console_enabled": False,
@ -440,7 +441,7 @@ level, "error" has ERROR. Example of node console notification::
"payload":{ "payload":{
"ironic_object.namespace":"ironic", "ironic_object.namespace":"ironic",
"ironic_object.name":"NodePayload", "ironic_object.name":"NodePayload",
"ironic_object.version":"1.8", "ironic_object.version":"1.9",
"ironic_object.data":{ "ironic_object.data":{
"clean_step": None, "clean_step": None,
"console_enabled": True, "console_enabled": True,
@ -515,11 +516,12 @@ ironic-conductor is attempting to change the node::
"payload":{ "payload":{
"ironic_object.namespace":"ironic", "ironic_object.namespace":"ironic",
"ironic_object.name":"NodeSetPowerStatePayload", "ironic_object.name":"NodeSetPowerStatePayload",
"ironic_object.version":"1.7", "ironic_object.version":"1.9",
"ironic_object.data":{ "ironic_object.data":{
"clean_step": None, "clean_step": None,
"console_enabled": False, "console_enabled": False,
"created_at": "2016-01-26T20:41:03+00:00", "created_at": "2016-01-26T20:41:03+00:00",
"deploy_step": None,
"driver": "ipmi", "driver": "ipmi",
"extra": {}, "extra": {},
"inspection_finished_at": None, "inspection_finished_at": None,
@ -583,11 +585,12 @@ prior to the correction::
"payload":{ "payload":{
"ironic_object.namespace":"ironic", "ironic_object.namespace":"ironic",
"ironic_object.name":"NodeCorrectedPowerStatePayload", "ironic_object.name":"NodeCorrectedPowerStatePayload",
"ironic_object.version":"1.7", "ironic_object.version":"1.9",
"ironic_object.data":{ "ironic_object.data":{
"clean_step": None, "clean_step": None,
"console_enabled": False, "console_enabled": False,
"created_at": "2016-01-26T20:41:03+00:00", "created_at": "2016-01-26T20:41:03+00:00",
"deploy_step": None,
"driver": "ipmi", "driver": "ipmi",
"extra": {}, "extra": {},
"inspection_finished_at": None, "inspection_finished_at": None,
@ -662,11 +665,12 @@ indicate a node's provision states before state change, "event" is the FSM
"payload":{ "payload":{
"ironic_object.namespace":"ironic", "ironic_object.namespace":"ironic",
"ironic_object.name":"NodeSetProvisionStatePayload", "ironic_object.name":"NodeSetProvisionStatePayload",
"ironic_object.version":"1.7", "ironic_object.version":"1.9",
"ironic_object.data":{ "ironic_object.data":{
"clean_step": None, "clean_step": None,
"console_enabled": False, "console_enabled": False,
"created_at": "2016-01-26T20:41:03+00:00", "created_at": "2016-01-26T20:41:03+00:00",
"deploy_step": None,
"driver": "ipmi", "driver": "ipmi",
"extra": {}, "extra": {},
"inspection_finished_at": None, "inspection_finished_at": None,

View File

@ -2,6 +2,12 @@
REST API Version History REST API Version History
======================== ========================
1.44 (Rocky, master)
--------------------
Added ``deploy_step`` to the node object, to indicate the current deploy
step (if any) being performed on the node.
1.43 (Rocky, 11.0.0) 1.43 (Rocky, 11.0.0)
-------------------- --------------------

View File

@ -150,6 +150,9 @@ def hide_fields_in_newer_versions(obj):
if pecan.request.version.minor < versions.MINOR_42_FAULT: if pecan.request.version.minor < versions.MINOR_42_FAULT:
obj.fault = wsme.Unset obj.fault = wsme.Unset
if pecan.request.version.minor < versions.MINOR_44_NODE_DEPLOY_STEP:
obj.deploy_step = wsme.Unset
if not api_utils.allow_resource_class(): if not api_utils.allow_resource_class():
obj.resource_class = wsme.Unset obj.resource_class = wsme.Unset
@ -990,6 +993,9 @@ class Node(base.APIBase):
clean_step = wsme.wsattr({wtypes.text: types.jsontype}, readonly=True) clean_step = wsme.wsattr({wtypes.text: types.jsontype}, readonly=True)
"""The current clean step""" """The current clean step"""
deploy_step = wsme.wsattr({wtypes.text: types.jsontype}, readonly=True)
"""The current deploy step"""
raid_config = wsme.wsattr({wtypes.text: types.jsontype}, readonly=True) raid_config = wsme.wsattr({wtypes.text: types.jsontype}, readonly=True)
"""Represents the current RAID configuration of the node """ """Represents the current RAID configuration of the node """
@ -1215,7 +1221,7 @@ class Node(base.APIBase):
provision_updated_at=time, instance_info={}, provision_updated_at=time, instance_info={},
maintenance=False, maintenance_reason=None, fault=None, maintenance=False, maintenance_reason=None, fault=None,
inspection_finished_at=None, inspection_started_at=time, inspection_finished_at=None, inspection_started_at=time,
console_enabled=False, clean_step={}, console_enabled=False, clean_step={}, deploy_step={},
raid_config=None, target_raid_config=None, raid_config=None, target_raid_config=None,
network_interface='flat', resource_class='baremetal-gold', network_interface='flat', resource_class='baremetal-gold',
boot_interface=None, console_interface=None, boot_interface=None, console_interface=None,
@ -1247,6 +1253,7 @@ class NodePatchType(types.JsonPatchType):
'/provision_updated_at', '/maintenance_reason', '/provision_updated_at', '/maintenance_reason',
'/driver_internal_info', '/inspection_finished_at', '/driver_internal_info', '/inspection_finished_at',
'/inspection_started_at', '/clean_step', '/inspection_started_at', '/clean_step',
'/deploy_step',
'/raid_config', '/target_raid_config', '/raid_config', '/target_raid_config',
'/fault'] '/fault']
@ -1484,7 +1491,8 @@ class NodesController(rest.RestController):
invalid_sort_key_list = ['properties', 'driver_info', 'extra', invalid_sort_key_list = ['properties', 'driver_info', 'extra',
'instance_info', 'driver_internal_info', 'instance_info', 'driver_internal_info',
'clean_step', 'raid_config', 'target_raid_config', 'clean_step', 'deploy_step',
'raid_config', 'target_raid_config',
'traits'] 'traits']
_subcontroller_map = { _subcontroller_map = {

View File

@ -81,6 +81,7 @@ BASE_VERSION = 1
# v1.41: Add inspection abort support. # v1.41: Add inspection abort support.
# v1.42: Expose fault field to node. # v1.42: Expose fault field to node.
# v1.43: Add detail=True flag to all API endpoints # v1.43: Add detail=True flag to all API endpoints
# v1.44: Add node deploy_step field
MINOR_0_JUNO = 0 MINOR_0_JUNO = 0
MINOR_1_INITIAL_VERSION = 1 MINOR_1_INITIAL_VERSION = 1
@ -126,6 +127,7 @@ MINOR_40_BIOS_INTERFACE = 40
MINOR_41_INSPECTION_ABORT = 41 MINOR_41_INSPECTION_ABORT = 41
MINOR_42_FAULT = 42 MINOR_42_FAULT = 42
MINOR_43_ENABLE_DETAIL_QUERY = 43 MINOR_43_ENABLE_DETAIL_QUERY = 43
MINOR_44_NODE_DEPLOY_STEP = 44
# When adding another version, update: # When adding another version, update:
# - MINOR_MAX_VERSION # - MINOR_MAX_VERSION
@ -133,7 +135,7 @@ MINOR_43_ENABLE_DETAIL_QUERY = 43
# explanation of what changed in the new version # explanation of what changed in the new version
# - common/release_mappings.py, RELEASE_MAPPING['master']['api'] # - common/release_mappings.py, RELEASE_MAPPING['master']['api']
MINOR_MAX_VERSION = MINOR_43_ENABLE_DETAIL_QUERY MINOR_MAX_VERSION = MINOR_44_NODE_DEPLOY_STEP
# String representations of the minor and maximum versions # String representations of the minor and maximum versions
_MIN_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_1_INITIAL_VERSION) _MIN_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_1_INITIAL_VERSION)

View File

@ -115,7 +115,7 @@ RELEASE_MAPPING = {
} }
}, },
'master': { 'master': {
'api': '1.43', 'api': '1.44',
'rpc': '1.45', 'rpc': '1.45',
'objects': { 'objects': {
'Node': ['1.26'], 'Node': ['1.26'],

View File

@ -633,11 +633,13 @@ class NodePayload(notification.NotificationPayloadBase):
# Version 1.6: Add traits field exposed via API. # Version 1.6: Add traits field exposed via API.
# Version 1.7: Add fault field exposed via API. # Version 1.7: Add fault field exposed via API.
# Version 1.8: Add bios interface field exposed via API. # Version 1.8: Add bios interface field exposed via API.
VERSION = '1.8' # Version 1.9: Add deploy_step field exposed via API.
VERSION = '1.9'
fields = { fields = {
'clean_step': object_fields.FlexibleDictField(nullable=True), 'clean_step': object_fields.FlexibleDictField(nullable=True),
'console_enabled': object_fields.BooleanField(nullable=True), 'console_enabled': object_fields.BooleanField(nullable=True),
'created_at': object_fields.DateTimeField(nullable=True), 'created_at': object_fields.DateTimeField(nullable=True),
'deploy_step': object_fields.FlexibleDictField(nullable=True),
'driver': object_fields.StringField(nullable=True), 'driver': object_fields.StringField(nullable=True),
'extra': object_fields.FlexibleDictField(nullable=True), 'extra': object_fields.FlexibleDictField(nullable=True),
'inspection_finished_at': object_fields.DateTimeField(nullable=True), 'inspection_finished_at': object_fields.DateTimeField(nullable=True),
@ -706,7 +708,8 @@ class NodeSetPowerStatePayload(NodePayload):
# Version 1.6: Parent NodePayload version 1.6 # Version 1.6: Parent NodePayload version 1.6
# Version 1.7: Parent NodePayload version 1.7 # Version 1.7: Parent NodePayload version 1.7
# Version 1.8: Parent NodePayload version 1.8 # Version 1.8: Parent NodePayload version 1.8
VERSION = '1.8' # Version 1.9: Parent NodePayload version 1.9
VERSION = '1.9'
fields = { fields = {
# "to_power" indicates the future target_power_state of the node. A # "to_power" indicates the future target_power_state of the node. A
@ -755,7 +758,8 @@ class NodeCorrectedPowerStatePayload(NodePayload):
# Version 1.6: Parent NodePayload version 1.6 # Version 1.6: Parent NodePayload version 1.6
# Version 1.7: Parent NodePayload version 1.7 # Version 1.7: Parent NodePayload version 1.7
# Version 1.8: Parent NodePayload version 1.8 # Version 1.8: Parent NodePayload version 1.8
VERSION = '1.8' # Version 1.9: Parent NodePayload version 1.9
VERSION = '1.9'
fields = { fields = {
'from_power': object_fields.StringField(nullable=True) 'from_power': object_fields.StringField(nullable=True)
@ -788,7 +792,8 @@ class NodeSetProvisionStatePayload(NodePayload):
# Version 1.6: Parent NodePayload version 1.6 # Version 1.6: Parent NodePayload version 1.6
# Version 1.7: Parent NodePayload version 1.7 # Version 1.7: Parent NodePayload version 1.7
# Version 1.8: Parent NodePayload version 1.8 # Version 1.8: Parent NodePayload version 1.8
VERSION = '1.8' # Version 1.9: Parent NodePayload version 1.9
VERSION = '1.9'
SCHEMA = dict(NodePayload.SCHEMA, SCHEMA = dict(NodePayload.SCHEMA,
**{'instance_info': ('node', 'instance_info')}) **{'instance_info': ('node', 'instance_info')})
@ -828,7 +833,8 @@ class NodeCRUDPayload(NodePayload):
# Version 1.4: Parent NodePayload version 1.6 # Version 1.4: Parent NodePayload version 1.6
# Version 1.5: Parent NodePayload version 1.7 # Version 1.5: Parent NodePayload version 1.7
# Version 1.6: Parent NodePayload version 1.8 # Version 1.6: Parent NodePayload version 1.8
VERSION = '1.6' # Version 1.7: Parent NodePayload version 1.9
VERSION = '1.7'
SCHEMA = dict(NodePayload.SCHEMA, SCHEMA = dict(NodePayload.SCHEMA,
**{'instance_info': ('node', 'instance_info'), **{'instance_info': ('node', 'instance_info'),

View File

@ -122,6 +122,7 @@ class TestListNodes(test_api_base.BaseApiTest):
# never expose the chassis_id # never expose the chassis_id
self.assertNotIn('chassis_id', data['nodes'][0]) self.assertNotIn('chassis_id', data['nodes'][0])
self.assertNotIn('bios_interface', data['nodes'][0]) self.assertNotIn('bios_interface', data['nodes'][0])
self.assertNotIn('deploy_step', data['nodes'][0])
def test_get_one(self): def test_get_one(self):
node = obj_utils.create_test_node(self.context, node = obj_utils.create_test_node(self.context,
@ -158,6 +159,7 @@ class TestListNodes(test_api_base.BaseApiTest):
# never expose the chassis_id # never expose the chassis_id
self.assertNotIn('chassis_id', data) self.assertNotIn('chassis_id', data)
self.assertIn('bios_interface', data) self.assertIn('bios_interface', data)
self.assertIn('deploy_step', data)
def test_get_one_with_json(self): def test_get_one_with_json(self):
# Test backward compatibility with guess_content_type_from_ext # Test backward compatibility with guess_content_type_from_ext
@ -250,6 +252,10 @@ class TestListNodes(test_api_base.BaseApiTest):
self._test_node_field_hidden_in_lower_version('fault', self._test_node_field_hidden_in_lower_version('fault',
'1.41', '1.42') '1.41', '1.42')
def test_node_deploy_step_hidden_in_lower_version(self):
self._test_node_field_hidden_in_lower_version('deploy_step',
'1.43', '1.44')
def test_get_one_custom_fields(self): def test_get_one_custom_fields(self):
node = obj_utils.create_test_node(self.context, node = obj_utils.create_test_node(self.context,
chassis_id=self.chassis.id) chassis_id=self.chassis.id)
@ -2419,6 +2425,19 @@ class TestPatch(test_api_base.BaseApiTest):
self.assertEqual(http_client.BAD_REQUEST, response.status_code) self.assertEqual(http_client.BAD_REQUEST, response.status_code)
self.assertTrue(response.json['error_message']) self.assertTrue(response.json['error_message'])
def test_patch_deploy_step_forbidden(self):
node = obj_utils.create_test_node(self.context,
uuid=uuidutils.generate_uuid())
response = self.patch_json('/nodes/%s' % node.uuid,
[{'path': '/deploy_step',
'op': 'replace',
'value': 'deploy this'}],
headers={api_base.Version.string: "1.43"},
expect_errors=True)
self.assertEqual('application/json', response.content_type)
self.assertEqual(http_client.BAD_REQUEST, response.status_code)
self.assertTrue(response.json['error_message'])
def _create_node_locally(node): def _create_node_locally(node):
driver_factory.check_and_update_node_interfaces(node) driver_factory.check_and_update_node_interfaces(node)

View File

@ -100,9 +100,6 @@ def node_post_data(**kw):
node.pop('chassis_id') node.pop('chassis_id')
node.pop('tags') node.pop('tags')
node.pop('traits') node.pop('traits')
# TODO(mgoddard): Remove this once the deploy_step field is supported in
# the API.
node.pop('deploy_step')
# NOTE(jroll): pop out fields that were introduced in later API versions, # NOTE(jroll): pop out fields that were introduced in later API versions,
# unless explicitly requested. Otherwise, these will cause tests using # unless explicitly requested. Otherwise, these will cause tests using

View File

@ -672,21 +672,21 @@ expected_object_fingerprints = {
'Conductor': '1.2-5091f249719d4a465062a1b3dc7f860d', 'Conductor': '1.2-5091f249719d4a465062a1b3dc7f860d',
'EventType': '1.1-aa2ba1afd38553e3880c267404e8d370', 'EventType': '1.1-aa2ba1afd38553e3880c267404e8d370',
'NotificationPublisher': '1.0-51a09397d6c0687771fb5be9a999605d', 'NotificationPublisher': '1.0-51a09397d6c0687771fb5be9a999605d',
'NodePayload': '1.8-2c327dfc77ce8c7a28b02eafaed509f0', 'NodePayload': '1.9-c0aa5dd602adca3a28f091ca7848a41b',
'NodeSetPowerStateNotification': '1.0-59acc533c11d306f149846f922739c15', 'NodeSetPowerStateNotification': '1.0-59acc533c11d306f149846f922739c15',
'NodeSetPowerStatePayload': '1.8-916c39939609254de1f8050a1c8da7d1', 'NodeSetPowerStatePayload': '1.9-07cd9053faa76199ffeaa45db78728a2',
'NodeCorrectedPowerStateNotification': 'NodeCorrectedPowerStateNotification':
'1.0-59acc533c11d306f149846f922739c15', '1.0-59acc533c11d306f149846f922739c15',
'NodeCorrectedPowerStatePayload': '1.8-1afef2b5c0538941defa00232302cd89', 'NodeCorrectedPowerStatePayload': '1.9-321b389cd4aa2552da25a5001f7fcb71',
'NodeSetProvisionStateNotification': 'NodeSetProvisionStateNotification':
'1.0-59acc533c11d306f149846f922739c15', '1.0-59acc533c11d306f149846f922739c15',
'NodeSetProvisionStatePayload': '1.8-d4aa7eb5a449e9f8271b3127a2d2b6ea', 'NodeSetProvisionStatePayload': '1.9-995f311c21e5e54bf2183db4056542a5',
'VolumeConnector': '1.0-3e0252c0ab6e6b9d158d09238a577d97', 'VolumeConnector': '1.0-3e0252c0ab6e6b9d158d09238a577d97',
'VolumeTarget': '1.0-0b10d663d8dae675900b2c7548f76f5e', 'VolumeTarget': '1.0-0b10d663d8dae675900b2c7548f76f5e',
'ChassisCRUDNotification': '1.0-59acc533c11d306f149846f922739c15', 'ChassisCRUDNotification': '1.0-59acc533c11d306f149846f922739c15',
'ChassisCRUDPayload': '1.0-dce63895d8186279a7dd577cffccb202', 'ChassisCRUDPayload': '1.0-dce63895d8186279a7dd577cffccb202',
'NodeCRUDNotification': '1.0-59acc533c11d306f149846f922739c15', 'NodeCRUDNotification': '1.0-59acc533c11d306f149846f922739c15',
'NodeCRUDPayload': '1.6-3ab7db0fc4574999fca91a1f04b4998f', 'NodeCRUDPayload': '1.7-af856321c0531f52be431217214d203a',
'PortCRUDNotification': '1.0-59acc533c11d306f149846f922739c15', 'PortCRUDNotification': '1.0-59acc533c11d306f149846f922739c15',
'PortCRUDPayload': '1.2-233d259df442eb15cc584fae1fe81504', 'PortCRUDPayload': '1.2-233d259df442eb15cc584fae1fe81504',
'NodeMaintenanceNotification': '1.0-59acc533c11d306f149846f922739c15', 'NodeMaintenanceNotification': '1.0-59acc533c11d306f149846f922739c15',