From f1946a1e90036bb8a758b49f94ac4d3b40bae66e Mon Sep 17 00:00:00 2001 From: Bin Yang Date: Thu, 28 Oct 2021 19:55:47 +0800 Subject: [PATCH] Add ocloud watcher and tests Issue-ID: INF-196 Signed-off-by: Bin Yang Change-Id: I3c0fb09913f5a064e84cecc3f6fdb6072c58be5a --- o2ims/adapter/ocloud_repository.py | 21 +++---- o2ims/domain/stx_object.py | 24 +++++--- o2ims/service/auditor/__init__.py | 13 ++++ o2ims/service/auditor/base.py | 13 ++++ o2ims/service/watcher/__init__.py | 13 ++++ o2ims/service/watcher/base.py | 68 +++++++++++++++++++++ tests/conftest.py | 4 +- tests/integration/test_clientdriver_fake_stx_sa.py | 1 + tests/unit/test_watcher.py | 71 ++++++++++++++++++++++ 9 files changed, 202 insertions(+), 26 deletions(-) create mode 100644 o2ims/service/auditor/__init__.py create mode 100644 o2ims/service/auditor/base.py create mode 100644 o2ims/service/watcher/__init__.py create mode 100644 o2ims/service/watcher/base.py create mode 100644 tests/unit/test_watcher.py diff --git a/o2ims/adapter/ocloud_repository.py b/o2ims/adapter/ocloud_repository.py index 8a547fe..ca90209 100644 --- a/o2ims/adapter/ocloud_repository.py +++ b/o2ims/adapter/ocloud_repository.py @@ -13,7 +13,7 @@ # limitations under the License. import abc -from typing import Set +from typing import List, Set # from o2ims.adapter import orm from o2ims.domain import ocloud @@ -32,6 +32,9 @@ class OcloudRepository(abc.ABC): self.seen.add(ocloud) return ocloud + def list(self) -> List[ocloud.Ocloud]: + return self._list() + def update(self, ocloud: ocloud.Ocloud): self._update(ocloud) @@ -64,18 +67,8 @@ class OcloudSqlAlchemyRepository(OcloudRepository): return self.session.query(ocloud.Ocloud).filter_by( oCloudId=ocloudid).first() + def _list(self) -> List[ocloud.Ocloud]: + return self.session.query() + def _update(self, ocloud: ocloud.Ocloud): self.session.add(ocloud) - - # def _update_fields(self, ocloudid: str, updatefields: dict): - # dmslist = updatefields.pop("deploymentManagers", None) - # if dmslist: - # self._update_dms_list(dmslist) - # if updatefields: - # self.session.query(ocloud.Ocloud).filter_by( - # oCloudId=ocloudid).update(updatefields) - - # def _update_dms_list(self, dms_list: list): - # for dms in dms_list or []: - # self.session.query(ocloud.DeploymentManager).filter_by( - # deploymentManagerId=dms.deploymentManagerId).update(dms) diff --git a/o2ims/domain/stx_object.py b/o2ims/domain/stx_object.py index 0a17092..7345694 100644 --- a/o2ims/domain/stx_object.py +++ b/o2ims/domain/stx_object.py @@ -13,10 +13,14 @@ # limitations under the License. # from dataclasses import dataclass -import datetime +# import datetime import json +class MismatchedModel(Exception): + pass + + class StxGenericModel: def __init__(self, api_response: dict = None) -> None: if api_response: @@ -26,12 +30,14 @@ class StxGenericModel: self.createtime = api_response.created_at self.name = api_response.name - # def __init__(self, id: str, name: str, - # lastupdate: datetime, content: str) -> None: - # self.id = id - # self.name = name - # self.lastupdate = lastupdate - # self.content = content + def is_outdated(self, newmodel) -> bool: + return self.updatetime < newmodel.updatetime + + def update_by(self, newmodel) -> None: + if self.id != newmodel.id: + raise MismatchedModel("Mismatched model") + self.name = newmodel.name - def isChanged(self, updatetime: datetime) -> bool: - return True if self.updatetime > updatetime else False + self.content = newmodel.content + self.createtime = newmodel.createtime + self.updatetime = newmodel.updatetime diff --git a/o2ims/service/auditor/__init__.py b/o2ims/service/auditor/__init__.py new file mode 100644 index 0000000..b514342 --- /dev/null +++ b/o2ims/service/auditor/__init__.py @@ -0,0 +1,13 @@ +# 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. diff --git a/o2ims/service/auditor/base.py b/o2ims/service/auditor/base.py new file mode 100644 index 0000000..b514342 --- /dev/null +++ b/o2ims/service/auditor/base.py @@ -0,0 +1,13 @@ +# 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. diff --git a/o2ims/service/watcher/__init__.py b/o2ims/service/watcher/__init__.py new file mode 100644 index 0000000..b514342 --- /dev/null +++ b/o2ims/service/watcher/__init__.py @@ -0,0 +1,13 @@ +# 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. diff --git a/o2ims/service/watcher/base.py b/o2ims/service/watcher/base.py new file mode 100644 index 0000000..4ea23ff --- /dev/null +++ b/o2ims/service/watcher/base.py @@ -0,0 +1,68 @@ +# 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.service.client.base_client import BaseClient +from o2ims.domain.stx_object import StxGenericModel +from o2ims.adapter.ocloud_repository import OcloudRepository + + +class InvalidOcloudState(Exception): + pass + + +class BaseWatcher(object): + def __init__(self, client: BaseClient) -> None: + super().__init__() + self._client = client + + def probe(self): + self._probe() + + def _probe(self): + pass + + +class OcloudWather(BaseWatcher): + def __init__(self, ocloud_client: BaseClient, + repo: OcloudRepository) -> None: + super().__init__(ocloud_client) + self._repo = repo + + def _probe(self): + ocloudmodel = self._client.get(None) + if ocloudmodel: + self._compare_and_update(ocloudmodel) + + def _compare_and_update(self, ocloudmodel: StxGenericModel) -> bool: + # localmodel = self._repo.get(ocloudmodel.id) + oclouds = self._repo.list() + if len(oclouds) > 1: + raise InvalidOcloudState("More than 1 ocloud is found") + if len(oclouds) == 0: + self._repo.add(ocloudmodel) + else: + localmodel = oclouds.pop() + if localmodel.is_outdated(ocloudmodel): + localmodel.update_by(ocloudmodel) + self._repo.update(localmodel) + + +class ResourcePoolWatcher(object): + def __init__(self) -> None: + super().__init__() + + +class ResourceWatcher(object): + def __init__(self) -> None: + super().__init__() diff --git a/tests/conftest.py b/tests/conftest.py index c6b0904..211ad3e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -14,6 +14,7 @@ from tenacity import retry, stop_after_delay from o2ims.adapter.orm import metadata, start_o2ims_mappers from o2ims.adapter.clients.orm_stx import start_o2ims_stx_mappers from o2ims import config +from o2ims.domain import stx_object as ocloudModel @pytest.fixture @@ -36,9 +37,6 @@ def mappers(): yield clear_mappers() -@pytest.fixture -def fake_stx_client(): - pass @retry(stop=stop_after_delay(10)) def wait_for_postgres_to_come_up(engine): diff --git a/tests/integration/test_clientdriver_fake_stx_sa.py b/tests/integration/test_clientdriver_fake_stx_sa.py index 177546c..8f262b8 100644 --- a/tests/integration/test_clientdriver_fake_stx_sa.py +++ b/tests/integration/test_clientdriver_fake_stx_sa.py @@ -26,6 +26,7 @@ from o2ims.domain import stx_object as ocloudModel # pytestmark = pytest.mark.usefixtures("mappers") + class FakeStxSaClientImp(object): def __init__(self): super().__init__() diff --git a/tests/unit/test_watcher.py b/tests/unit/test_watcher.py new file mode 100644 index 0000000..ec28519 --- /dev/null +++ b/tests/unit/test_watcher.py @@ -0,0 +1,71 @@ +# 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 datetime import datetime +import json +from typing import List +from o2ims.service.client.base_client import BaseClient +import pytest +from o2ims.domain import ocloud +from o2ims import config +import uuid +from o2ims.service.watcher.base import OcloudWather +from o2ims.domain import stx_object as ocloudModel +from o2ims.adapter.ocloud_repository import OcloudRepository + +class FakeOcloudClient(BaseClient): + def __init__(self): + super().__init__() + fakeCloud = ocloudModel.StxGenericModel() + fakeCloud.id = uuid.uuid4() + fakeCloud.name = 'stx1' + fakeCloud.content = json.dumps({}) + fakeCloud.createtime = datetime.now() + fakeCloud.updatetime = datetime.now + self.fakeCloud = fakeCloud + + def _get(self, id) -> ocloudModel.StxGenericModel: + return self.fakeCloud + + def _list(self): + return [self.fakeCloud] + +class FakeOcloudRepo(OcloudRepository): + def __init__(self): + super().__init__() + self.oclouds = [] + + def _add(self, ocloud: ocloud.Ocloud): + self.oclouds.append(ocloud) + + def _get(self, ocloudid) -> ocloud.Ocloud: + filtered = [o for o in self.oclouds if o.id == ocloudid] + return filtered.pop() + + def _list(self) -> List[ocloud.Ocloud]: + return [x for x in self.oclouds] + + def _update(self, ocloud: ocloud.Ocloud): + filtered = [o for o in self.oclouds if o.id == ocloud.id] + assert len(filtered) == 1 + ocloud1 = filtered.pop() + ocloud1.update_by(ocloud) + +def test_probe_new_ocloud(): + fakeRepo = FakeOcloudRepo() + fakeClient = FakeOcloudClient() + ocloudwatcher = OcloudWather(fakeClient, fakeRepo) + ocloudwatcher.probe() + assert len(fakeRepo.oclouds) == 1 + assert fakeRepo.oclouds[0].name == "stx1" -- 2.16.6