From: Zhang Rong(Jon) Date: Sun, 6 Nov 2022 15:28:49 +0000 (+0800) Subject: Add Accelerator resource watcher; fix bug of the alarm dictionary X-Git-Tag: 2.0.0-rc1~4^2 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=8ce7973df58d75f63dca57264d4934089a8629c5;p=pti%2Fo2.git Add Accelerator resource watcher; fix bug of the alarm dictionary Issue-ID: INF-325 Signed-off-by: Zhang Rong(Jon) Change-Id: Ib8a31aec10a323b56216662ad88df4b309c1b7eb --- diff --git a/o2app/entrypoints/resource_watcher.py b/o2app/entrypoints/resource_watcher.py index 99d5595..909e86c 100644 --- a/o2app/entrypoints/resource_watcher.py +++ b/o2app/entrypoints/resource_watcher.py @@ -40,12 +40,17 @@ from o2ims.adapter.clients.ocloud_client import StxMemClient from o2ims.service.watcher.pserver_if_watcher import PServerIfWatcher from o2ims.adapter.clients.ocloud_client import StxIfClient -from o2ims.service.watcher.pserver_port_watcher import PServerIfPortWatcher -from o2ims.adapter.clients.ocloud_client import StxIfPortClient +# from o2ims.service.watcher.pserver_port_watcher import PServerIfPortWatcher +# from o2ims.adapter.clients.ocloud_client import StxIfPortClient from o2ims.service.watcher.pserver_eth_watcher import PServerEthWatcher from o2ims.adapter.clients.ocloud_client import StxEthClient +# from o2ims.service.watcher.pserver_dev_watcher import PServerDevWatcher +# from o2ims.adapter.clients.ocloud_client import StxDevClient +from o2ims.service.watcher.pserver_acc_watcher import PServerAccWatcher +from o2ims.adapter.clients.ocloud_client import StxAccClient + from o2common.helper import o2logging logger = o2logging.get_logger(__name__) @@ -79,10 +84,14 @@ class WatcherService(cotyledon.Service): PServerMemWatcher(StxMemClient(), self.bus)) child_pserver.addchild( PServerEthWatcher(StxEthClient(), self.bus)) - child_if = child_pserver.addchild( + child_pserver.addchild( PServerIfWatcher(StxIfClient(), self.bus)) # child_if.addchild( # PServerIfPortWatcher(StxIfPortClient(), self.bus)) + # child_pserver.addchild( + # PServerDevWatcher(StxDevClient(), self.bus)) + child_pserver.addchild( + PServerAccWatcher(StxAccClient(), self.bus)) self.worker.add_watcher(root) diff --git a/o2app/service/handlers.py b/o2app/service/handlers.py index cc69fc5..ad75098 100644 --- a/o2app/service/handlers.py +++ b/o2app/service/handlers.py @@ -26,7 +26,8 @@ from o2dms.domain import events as o2dms_events from o2ims.service.auditor import ocloud_handler, dms_handler, \ resourcepool_handler, pserver_handler, pserver_cpu_handler, \ pserver_mem_handler, pserver_port_handler, pserver_if_handler,\ - pserver_eth_handler, alarm_handler + pserver_eth_handler, pserver_acc_handler, alarm_handler, \ + pserver_dev_handler from o2ims.service.command import notify_handler, registration_handler,\ notify_alarm_handler from o2ims.service.event import ocloud_event, resource_event, \ @@ -72,6 +73,8 @@ COMMAND_HANDLERS = { commands.UpdatePserverIf: pserver_if_handler.update_pserver_if, commands.UpdatePserverIfPort: pserver_port_handler.update_pserver_port, commands.UpdatePserverEth: pserver_eth_handler.update_pserver_eth, + commands.UpdatePserverDev: pserver_dev_handler.update_pserver_dev, + commands.UpdatePserverAcc: pserver_acc_handler.update_pserver_acc, o2dms_cmmands.HandleNfDeploymentStateChanged: nfdeployment_handler.handle_nfdeployment_statechanged, o2dms_cmmands.InstallNfDeployment: diff --git a/o2ims/adapter/alarm_loader.py b/o2ims/adapter/alarm_loader.py index 823d0d5..1e73e44 100644 --- a/o2ims/adapter/alarm_loader.py +++ b/o2ims/adapter/alarm_loader.py @@ -29,7 +29,8 @@ class AlarmDictionaryConfigFileRepository(AlarmDictionaryRepository): self.dictionary[alarm_dict.entityType] = alarm_dict def _get(self, alarm_entity_type) -> alarm_obj.AlarmDictionary: - return self.dictionary[alarm_entity_type] + return self.dictionary[alarm_entity_type] \ + if alarm_entity_type in self.dictionary else None def _list(self) -> List[alarm_obj.AlarmDictionary]: return [alarm_dict for alarm_dict in self.dictionary.items()] diff --git a/o2ims/adapter/clients/ocloud_client.py b/o2ims/adapter/clients/ocloud_client.py index ddc644e..7307bcc 100644 --- a/o2ims/adapter/clients/ocloud_client.py +++ b/o2ims/adapter/clients/ocloud_client.py @@ -172,7 +172,37 @@ class StxIfPortClient(BaseClient): self.driver.setStxClient(self._pool_id) -# internal driver which implement client call to Stx Standalone instance +class StxDevClient(BaseClient): + def __init__(self): + super().__init__() + self.driver = StxClientImp() + + def _get(self, id) -> ocloudModel.StxGenericModel: + return self.driver.getDevice(id) + + def _list(self, **filters) -> List[ocloudModel.StxGenericModel]: + return self.driver.getDeviceList(**filters) + + def _set_stx_client(self): + self.driver.setStxClient(self._pool_id) + + +class StxAccClient(BaseClient): + def __init__(self): + super().__init__() + self.driver = StxClientImp() + + def _get(self, id) -> ocloudModel.StxGenericModel: + return self.driver.getAccelerator(id) + + def _list(self, **filters) -> List[ocloudModel.StxGenericModel]: + return self.driver.getAcceleratorList(**filters) + + def _set_stx_client(self): + self.driver.setStxClient(self._pool_id) + + +# internal driver which implement client call to Stx Standalone and DC instance class StxClientImp(object): def __init__(self, stx_client=None, dc_client=None): super().__init__() @@ -446,6 +476,41 @@ class StxClientImp(object): return ocloudModel.StxGenericModel( ResourceTypeEnum.PSERVER_IF_PORT, portinfo) + def getDeviceList(self, **filters) -> List[ocloudModel.StxGenericModel]: + hostid = filters.get('hostid', None) + assert (hostid is not None), 'missing hostid to query pci device list' + pci_dev_list = self.stxclient.pci_device.list(hostid) + return [ocloudModel.StxGenericModel( + ResourceTypeEnum.PSERVER_PCI_DEV, + self._devconverter(pci_dev)) + for pci_dev in pci_dev_list if pci_dev] + + def getDevice(self, id) -> ocloudModel.StxGenericModel: + pciinfo = self.stxclient.pci_device.get(id) + return ocloudModel.StxGenericModel( + ResourceTypeEnum.PSERVER_PCI_DEV, self._devconverter(pciinfo)) + + def getAcceleratorList(self, **filters) -> \ + List[ocloudModel.StxGenericModel]: + hostid = filters.get('hostid', None) + assert (hostid is not None), 'missing hostid to query accelerator list' + pci_dev_list = self.stxclient.pci_device.list(hostid) + acc_list = [] + for pci_dev in pci_dev_list: + if pci_dev.pvendor_id in ['8086']: + if pci_dev.pdevice_id in ['0d5c', '0d5d']: + logger.info('Accelerator vendor ID: {}, device ID: {}'. + format(pci_dev.pvendor_id, pci_dev.pdevice_id)) + acc_list.append(ocloudModel.StxGenericModel( + ResourceTypeEnum.PSERVER_ACC, + self._devconverter(pci_dev))) + return acc_list + + def getAccelerator(self, id) -> ocloudModel.StxGenericModel: + pciinfo = self.stxclient.pci_device.get(id) + return ocloudModel.StxGenericModel( + ResourceTypeEnum.PSERVER_ACC, self._devconverter(pciinfo)) + def _getIsystems(self): return self.stxclient.isystem.list() @@ -490,6 +555,11 @@ class StxClientImp(object): setattr(ifs, 'created_at', None) return ifs + @ staticmethod + def _devconverter(dev): + setattr(dev, 'name', dev.host_uuid.split('-', 1)[0] + '-'+dev.name) + return dev + @ staticmethod def _k8sconverter(cluster): setattr(cluster, 'name', cluster.cloud_name + diff --git a/o2ims/domain/commands.py b/o2ims/domain/commands.py index 25c9629..5d58e4c 100644 --- a/o2ims/domain/commands.py +++ b/o2ims/domain/commands.py @@ -104,6 +104,16 @@ class UpdatePserverIfPort(UpdateResource): pass +@dataclass +class UpdatePserverDev(UpdateResource): + pass + + +@dataclass +class UpdatePserverAcc(UpdateResource): + pass + + @dataclass class UpdateAlarm(UpdateFaultObject): pass diff --git a/o2ims/domain/ocloud.py b/o2ims/domain/ocloud.py index c6f5fd8..bdc07d9 100644 --- a/o2ims/domain/ocloud.py +++ b/o2ims/domain/ocloud.py @@ -105,8 +105,10 @@ class ResourceType(AgRoot, Serializer): def serialize(self): d = Serializer.serialize(self) - d["alarmDictionary"] = CONF.alarm_dictionaries.get( - d['name']).serialize() + if CONF.alarm_dictionaries.get(d['name']) is not None: + d["alarmDictionary"] = CONF.alarm_dictionaries.get( + d['name']).serialize() + return d diff --git a/o2ims/domain/resource_type.py b/o2ims/domain/resource_type.py index 3a2271a..076d6ae 100644 --- a/o2ims/domain/resource_type.py +++ b/o2ims/domain/resource_type.py @@ -12,6 +12,8 @@ class ResourceTypeEnum(Enum): PSERVER_IF = 14 PSERVER_IF_PORT = 15 PSERVER_ETH = 16 + PSERVER_PCI_DEV = 17 + PSERVER_ACC = 18 class ResourceKindEnum(Enum): diff --git a/o2ims/service/auditor/pserver_acc_handler.py b/o2ims/service/auditor/pserver_acc_handler.py new file mode 100644 index 0000000..fc289ee --- /dev/null +++ b/o2ims/service/auditor/pserver_acc_handler.py @@ -0,0 +1,127 @@ +# Copyright (C) 2021 Wind River Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# pylint: disable=unused-argument +from __future__ import annotations +import uuid +# import json + +from o2ims.domain import commands, events +from o2ims.domain.stx_object import StxGenericModel +from o2ims.domain.subscription_obj import NotificationEventEnum +from o2common.service.unit_of_work import AbstractUnitOfWork +from o2ims.domain.resource_type import MismatchedModel +from o2ims.domain.ocloud import Resource, ResourceType + +from o2common.helper import o2logging +logger = o2logging.get_logger(__name__) + + +class InvalidResourceType(Exception): + pass + + +def update_pserver_acc( + cmd: commands.UpdatePserverAcc, + uow: AbstractUnitOfWork +): + stxobj = cmd.data + with uow: + p_resource = uow.resources.get(cmd.parentid) + resourcepool = uow.resource_pools.get(p_resource.resourcePoolId) + + res = uow.session.execute( + ''' + SELECT "resourceTypeId", "oCloudId", "name" + FROM "resourceType" + WHERE "resourceTypeEnum" = :resource_type_enum + ''', + dict(resource_type_enum=stxobj.type.name) + ) + first = res.first() + if first is None: + res_type_name = 'pserver_acc' + resourcetype_id = str(uuid.uuid3( + uuid.NAMESPACE_URL, res_type_name)) + uow.resource_types.add(ResourceType( + resourcetype_id, + res_type_name, stxobj.type, + resourcepool.oCloudId, + description='An Accelerator resource type of Physical Server')) + else: + resourcetype_id = first['resourceTypeId'] + + resource = uow.resources.get(stxobj.id) + if not resource: + logger.info("add the accelerator of pserver:" + stxobj.name + + " update_at: " + str(stxobj.updatetime) + + " id: " + str(stxobj.id) + + " hash: " + str(stxobj.hash)) + localmodel = create_by(stxobj, p_resource, resourcetype_id) + uow.resources.add(localmodel) + + logger.info("Add the accelerator of pserver: " + stxobj.id + + ", name: " + stxobj.name) + else: + localmodel = resource + if is_outdated(localmodel, stxobj): + logger.info("update accelerator of pserver:" + stxobj.name + + " update_at: " + str(stxobj.updatetime) + + " id: " + str(stxobj.id) + + " hash: " + str(stxobj.hash)) + update_by(localmodel, stxobj, p_resource) + uow.resources.update(localmodel) + + logger.info("Update the accelerator of pserver: " + stxobj.id + + ", name: " + stxobj.name) + uow.commit() + + +def is_outdated(resource: Resource, stxobj: StxGenericModel): + return True if resource.hash != stxobj.hash else False + + +def create_by(stxobj: StxGenericModel, parent: Resource, resourcetype_id: str)\ + -> Resource: + # content = json.loads(stxobj.content) + resourcetype_id = resourcetype_id + resourcepool_id = parent.resourcePoolId + parent_id = parent.resourceId + gAssetId = '' # TODO: global ID + description = "%s : An Accelerator resource of the physical server"\ + % stxobj.name + resource = Resource(stxobj.id, resourcetype_id, resourcepool_id, + stxobj.name, parent_id, gAssetId, stxobj.content, + description) + resource.createtime = stxobj.createtime + resource.updatetime = stxobj.updatetime + resource.hash = stxobj.hash + + return resource + + +def update_by(target: Resource, stxobj: StxGenericModel, + parentid: str) -> None: + if target.resourceId != stxobj.id: + raise MismatchedModel("Mismatched Id") + target.createtime = stxobj.createtime + target.updatetime = stxobj.updatetime + target.hash = stxobj.hash + target.version_number = target.version_number + 1 + target.events.append(events.ResourceChanged( + id=stxobj.id, + resourcePoolId=target.resourcePoolId, + notificationEventType=NotificationEventEnum.MODIFY, + updatetime=stxobj.updatetime + )) diff --git a/o2ims/service/auditor/pserver_dev_handler.py b/o2ims/service/auditor/pserver_dev_handler.py new file mode 100644 index 0000000..da94d8a --- /dev/null +++ b/o2ims/service/auditor/pserver_dev_handler.py @@ -0,0 +1,127 @@ +# Copyright (C) 2021 Wind River Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# pylint: disable=unused-argument +from __future__ import annotations +import uuid +# import json + +from o2ims.domain import commands, events +from o2ims.domain.stx_object import StxGenericModel +from o2ims.domain.subscription_obj import NotificationEventEnum +from o2common.service.unit_of_work import AbstractUnitOfWork +from o2ims.domain.resource_type import MismatchedModel +from o2ims.domain.ocloud import Resource, ResourceType + +from o2common.helper import o2logging +logger = o2logging.get_logger(__name__) + + +class InvalidResourceType(Exception): + pass + + +def update_pserver_dev( + cmd: commands.UpdatePserverDev, + uow: AbstractUnitOfWork +): + stxobj = cmd.data + with uow: + p_resource = uow.resources.get(cmd.parentid) + resourcepool = uow.resource_pools.get(p_resource.resourcePoolId) + + res = uow.session.execute( + ''' + SELECT "resourceTypeId", "oCloudId", "name" + FROM "resourceType" + WHERE "resourceTypeEnum" = :resource_type_enum + ''', + dict(resource_type_enum=stxobj.type.name) + ) + first = res.first() + if first is None: + res_type_name = 'pserver_dev' + resourcetype_id = str(uuid.uuid3( + uuid.NAMESPACE_URL, res_type_name)) + uow.resource_types.add(ResourceType( + resourcetype_id, + res_type_name, stxobj.type, + resourcepool.oCloudId, + description='A Device resource type of Physical Server')) + else: + resourcetype_id = first['resourceTypeId'] + + resource = uow.resources.get(stxobj.id) + if not resource: + logger.info("add the device of pserver:" + stxobj.name + + " update_at: " + str(stxobj.updatetime) + + " id: " + str(stxobj.id) + + " hash: " + str(stxobj.hash)) + localmodel = create_by(stxobj, p_resource, resourcetype_id) + uow.resources.add(localmodel) + + logger.info("Add the device of pserver: " + stxobj.id + + ", name: " + stxobj.name) + else: + localmodel = resource + if is_outdated(localmodel, stxobj): + logger.info("update device of pserver:" + stxobj.name + + " update_at: " + str(stxobj.updatetime) + + " id: " + str(stxobj.id) + + " hash: " + str(stxobj.hash)) + update_by(localmodel, stxobj, p_resource) + uow.resources.update(localmodel) + + logger.info("Update the device of pserver: " + stxobj.id + + ", name: " + stxobj.name) + uow.commit() + + +def is_outdated(resource: Resource, stxobj: StxGenericModel): + return True if resource.hash != stxobj.hash else False + + +def create_by(stxobj: StxGenericModel, parent: Resource, resourcetype_id: str)\ + -> Resource: + # content = json.loads(stxobj.content) + resourcetype_id = resourcetype_id + resourcepool_id = parent.resourcePoolId + parent_id = parent.resourceId + gAssetId = '' # TODO: global ID + description = "%s : A device resource of the physical server"\ + % stxobj.name + resource = Resource(stxobj.id, resourcetype_id, resourcepool_id, + stxobj.name, parent_id, gAssetId, stxobj.content, + description) + resource.createtime = stxobj.createtime + resource.updatetime = stxobj.updatetime + resource.hash = stxobj.hash + + return resource + + +def update_by(target: Resource, stxobj: StxGenericModel, + parentid: str) -> None: + if target.resourceId != stxobj.id: + raise MismatchedModel("Mismatched Id") + target.createtime = stxobj.createtime + target.updatetime = stxobj.updatetime + target.hash = stxobj.hash + target.version_number = target.version_number + 1 + target.events.append(events.ResourceChanged( + id=stxobj.id, + resourcePoolId=target.resourcePoolId, + notificationEventType=NotificationEventEnum.MODIFY, + updatetime=stxobj.updatetime + )) diff --git a/o2ims/service/watcher/pserver_acc_watcher.py b/o2ims/service/watcher/pserver_acc_watcher.py new file mode 100644 index 0000000..eef23ce --- /dev/null +++ b/o2ims/service/watcher/pserver_acc_watcher.py @@ -0,0 +1,42 @@ +# Copyright (C) 2021 Wind River Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from o2ims.domain.stx_object import StxGenericModel +from o2common.service.client.base_client import BaseClient +# from o2common.service.unit_of_work import AbstractUnitOfWork +from o2ims.service.watcher.resource_watcher import ResourceWatcher +from o2ims.domain import commands +from o2common.service.messagebus import MessageBus + +from o2common.helper import o2logging +logger = o2logging.get_logger(__name__) + + +class PServerAccWatcher(ResourceWatcher): + def __init__(self, client: BaseClient, + bus: MessageBus) -> None: + super().__init__(client, bus) + + def _targetname(self): + return "pserver_acc" + + def _probe(self, parent: StxGenericModel, tags): + # Set a tag for children resource + self._tags.pool = tags.pool + self._set_respool_client() + + hostid = parent.id + newmodels = self._client.list(hostid=hostid) + return [commands.UpdatePserverAcc(data=m, parentid=hostid) + for m in newmodels] diff --git a/o2ims/service/watcher/pserver_dev_watcher.py b/o2ims/service/watcher/pserver_dev_watcher.py new file mode 100644 index 0000000..446aa26 --- /dev/null +++ b/o2ims/service/watcher/pserver_dev_watcher.py @@ -0,0 +1,42 @@ +# Copyright (C) 2021 Wind River Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from o2ims.domain.stx_object import StxGenericModel +from o2common.service.client.base_client import BaseClient +# from o2common.service.unit_of_work import AbstractUnitOfWork +from o2ims.service.watcher.resource_watcher import ResourceWatcher +from o2ims.domain import commands +from o2common.service.messagebus import MessageBus + +from o2common.helper import o2logging +logger = o2logging.get_logger(__name__) + + +class PServerDevWatcher(ResourceWatcher): + def __init__(self, client: BaseClient, + bus: MessageBus) -> None: + super().__init__(client, bus) + + def _targetname(self): + return "pserver_dev" + + def _probe(self, parent: StxGenericModel, tags): + # Set a tag for children resource + self._tags.pool = tags.pool + self._set_respool_client() + + hostid = parent.id + newmodels = self._client.list(hostid=hostid) + return [commands.UpdatePserverDev(data=m, parentid=hostid) + for m in newmodels] diff --git a/tests/integration-ocloud/test_clientdriver_stx.py b/tests/integration-ocloud/test_clientdriver_stx.py index 24de6c4..8ca1780 100644 --- a/tests/integration-ocloud/test_clientdriver_stx.py +++ b/tests/integration-ocloud/test_clientdriver_stx.py @@ -162,6 +162,20 @@ def test_get_if_port_list(real_stx_aio_client): assert port1.id == port2.id +def test_get_device_list(real_stx_aio_client): + stxClientImp = StxClientImp(real_stx_aio_client) + assert stxClientImp is not None + hostlist = stxClientImp.getPserverList() + assert len(hostlist) > 0 + + devicelist = stxClientImp.getDeviceList(hostid=hostlist[0].id) + assert len(devicelist) > 0 + dev1 = devicelist[0] + dev2 = stxClientImp.getDevice(dev1.id) + assert dev1 != dev2 + assert dev1.id == dev2.id + + def test_get_res_pool_list(real_stx_aio_client, real_stx_dc_client): stxClientImp = StxClientImp(real_stx_aio_client, real_stx_dc_client) assert stxClientImp is not None