Add o2dms api endpoint 01/7101/4
authorBin Yang <bin.yang@windriver.com>
Tue, 23 Nov 2021 01:09:36 +0000 (09:09 +0800)
committerBin Yang <bin.yang@windriver.com>
Tue, 23 Nov 2021 06:09:56 +0000 (14:09 +0800)
Signed-off-by: Bin Yang <bin.yang@windriver.com>
Change-Id: Ic624aeda9f9bc8aba86e81b8e43b2ee3a89a009f

50 files changed:
Dockerfile
Dockerfile.localtest
README-o2imsbuilder.md
charts/resources/scripts/init/o2pubsub_start.sh
charts/resources/scripts/init/o2watcher_start.sh
charts/templates/deployment.yaml
docker-compose.yml
o2app/__init__.py [new file with mode: 0644]
o2app/adapter/__init__.py [new file with mode: 0644]
o2app/adapter/unit_of_work.py [new file with mode: 0644]
o2app/bootstrap.py [new file with mode: 0644]
o2app/entrypoints/__init__.py [new file with mode: 0644]
o2app/entrypoints/flask_application.py [new file with mode: 0644]
o2app/entrypoints/redis_eventconsumer.py [new file with mode: 0644]
o2app/entrypoints/resource_watcher.py [new file with mode: 0644]
o2app/service/__init__.py [new file with mode: 0644]
o2app/service/handlers.py [new file with mode: 0644]
o2app/service/messagebus.py [new file with mode: 0644]
o2common/adapter/__init__.py [new file with mode: 0644]
o2common/adapter/notifications.py [new file with mode: 0644]
o2common/adapter/redis_eventpublisher.py [new file with mode: 0644]
o2common/config/__init__.py [new file with mode: 0644]
o2common/config/config.py [new file with mode: 0644]
o2common/domain/__init__.py [new file with mode: 0644]
o2common/domain/base.py [new file with mode: 0644]
o2common/domain/commands.py [new file with mode: 0644]
o2common/domain/events.py [new file with mode: 0644]
o2common/service/__init__.py [new file with mode: 0644]
o2common/service/unit_of_work.py [new file with mode: 0644]
o2common/service/watcher/__init__.py [new file with mode: 0644]
o2common/service/watcher/base.py [new file with mode: 0644]
o2dms/adapter/__init__.py [new file with mode: 0644]
o2dms/adapter/dms_repository.py [new file with mode: 0644]
o2dms/adapter/orm.py [new file with mode: 0644]
o2dms/domain/dms.py [new file with mode: 0644]
o2dms/domain/dms_repo.py [new file with mode: 0644]
o2dms/service/__init__.py [new file with mode: 0644]
o2dms/views/__init__.py [new file with mode: 0644]
o2dms/views/dms_dto.py [new file with mode: 0644]
o2dms/views/dms_lcm_view.py [new file with mode: 0644]
o2dms/views/dms_route.py [new file with mode: 0644]
o2ims/adapter/__init__.py [new file with mode: 0644]
o2ims/adapter/orm.py
o2ims/config.py
o2ims/entrypoints/flask_application.py
o2ims/service/auditor/dms_handler.py
o2ims/views/__init__.py [new file with mode: 0644]
tests/o2app-api-entry.sh [new file with mode: 0644]
tests/o2app-redis-entry.sh [moved from tests/o2ims-watcher-entry.sh with 54% similarity]
tests/o2app-watcher-entry.sh [moved from tests/o2ims-redis-entry.sh with 55% similarity]

index a4ca721..3cbe00a 100644 (file)
@@ -31,6 +31,9 @@ RUN mkdir -p /src
 COPY o2ims/ /src/o2ims/\r
 COPY o2dms/ /src/o2dms/\r
 COPY o2common/ /src/o2common/\r
+\r
+RUN mkdir -p /src/o2app/\r
+COPY o2app/ /src/o2app/\r
 COPY setup.py /src/\r
 \r
 RUN pip install -e /src\r
index 16d399d..109ce75 100644 (file)
@@ -26,6 +26,9 @@ RUN mkdir -p /src
 COPY o2ims/ /src/o2ims/\r
 COPY o2dms/ /src/o2dms/\r
 COPY o2common/ /src/o2common/\r
+\r
+RUN mkdir -p /src/o2app/\r
+COPY o2app/ /src/o2app/\r
 COPY setup.py /src/\r
 \r
 COPY configs/ /etc/o2/\r
index e451723..a143301 100644 (file)
@@ -94,6 +94,7 @@ kubectl -n ${NAMESPACE} get pods
 ### test api endpoint\r
 \r
 ```sh\r
+curl -k http(s)://<Node IP>:30205\r
 curl -k http(s)://<Node IP>:30205/o2ims_infrastructureInventory/v1\r
 ```\r
 \r
@@ -116,7 +117,7 @@ kubectl -n ${NAMESPACE} exec -it o2api-<xxx> -c postgres -- bash
 \r
         \d\r
 \r
-        select * from stxcache;\r
+        select * from ocloud;\r
 \r
         \q\r
 \r
index e39329b..5dff1b3 100644 (file)
@@ -19,6 +19,6 @@ cd /root/
 git clone "https://gerrit.o-ran-sc.org/r/pti/o2"
 pip install -e /root/o2
 
-python /root/o2/o2ims/entrypoints/redis_eventconsumer.py
+python /root/o2/o2app/entrypoints/redis_eventconsumer.py
 
 sleep infinity
index 53fd670..643c27d 100644 (file)
@@ -19,6 +19,6 @@ cd /root/
 git clone "https://gerrit.o-ran-sc.org/r/pti/o2"
 pip install -e /root/o2
 
-python /root/o2/o2ims/entrypoints/resource_watcher.py
+python /root/o2/o2app/entrypoints/resource_watcher.py
 
 sleep infinity
index 7748f3e..cdb54d6 100644 (file)
@@ -62,7 +62,7 @@ spec:
             - name: DB_PASSWORD\r
               value: o2ims123\r
             - name: FLASK_APP\r
-              value: /root/o2/o2ims/entrypoints/flask_application.py\r
+              value: /root/o2/o2app/entrypoints/flask_application.py\r
             - name: FLASK_DEBUG\r
               value: {{ .Values.o2ims.logginglevel }}\r
             - name: LOGGING_CONFIG_LEVEL\r
index 64334b7..552154d 100644 (file)
@@ -24,10 +24,11 @@ services:
       - ./o2ims:/o2ims
       - ./o2dms:/o2dms
       - ./o2common:/o2common
+      - ./o2app:/o2app
       - ./tests:/tests
     entrypoint:
       - /bin/sh
-      - /tests/o2ims-redis-entry.sh
+      - /tests/o2app-redis-entry.sh
 
   api:
     image: o2imsdms
@@ -39,7 +40,7 @@ services:
       - API_HOST=api
       - REDIS_HOST=redis
       - PYTHONDONTWRITEBYTECODE=1
-      - FLASK_APP=/o2ims/entrypoints/flask_application.py
+      - FLASK_APP=/o2app/entrypoints/flask_application.py
       - FLASK_DEBUG=1
       - PYTHONUNBUFFERED=1
       - OS_AUTH_URL=${OS_AUTH_URL}
@@ -51,12 +52,11 @@ services:
       - ./o2ims:/o2ims
       - ./o2dms:/o2dms
       - ./o2common:/o2common
+      - ./o2app:/o2app
       - ./tests:/tests
     entrypoint:
-      - flask
-      - run
-      - --host=0.0.0.0
-      - --port=80
+      - /bin/sh
+      - /tests/o2app-api-entry.sh
     ports:
       - "5005:80"
 
@@ -81,10 +81,11 @@ services:
       - ./o2ims:/o2ims
       - ./o2dms:/o2dms
       - ./o2common:/o2common
+      - ./o2app:/o2app
       - ./tests:/tests
     entrypoint:
       - /bin/sh
-      - /tests/o2ims-watcher-entry.sh
+      - /tests/o2app-watcher-entry.sh
 
   postgres:
     image: postgres:9.6
diff --git a/o2app/__init__.py b/o2app/__init__.py
new file mode 100644 (file)
index 0000000..b514342
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
diff --git a/o2app/adapter/__init__.py b/o2app/adapter/__init__.py
new file mode 100644 (file)
index 0000000..b514342
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
diff --git a/o2app/adapter/unit_of_work.py b/o2app/adapter/unit_of_work.py
new file mode 100644 (file)
index 0000000..0faba56
--- /dev/null
@@ -0,0 +1,83 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
+\r
+# pylint: disable=attribute-defined-outside-init\r
+from __future__ import annotations\r
+from sqlalchemy import create_engine\r
+from sqlalchemy.orm import sessionmaker\r
+from sqlalchemy.orm.session import Session\r
+\r
+from o2common.config import config\r
+from o2common.service.unit_of_work import AbstractUnitOfWork\r
+\r
+from o2ims.adapter import ocloud_repository\r
+from o2dms.adapter import dms_repository\r
+\r
+DEFAULT_SESSION_FACTORY = sessionmaker(\r
+    bind=create_engine(\r
+        config.get_postgres_uri(),\r
+        isolation_level="REPEATABLE READ",\r
+    )\r
+)\r
+\r
+\r
+class SqlAlchemyUnitOfWork(AbstractUnitOfWork):\r
+    def __init__(self, session_factory=DEFAULT_SESSION_FACTORY):\r
+        self.session_factory = session_factory\r
+\r
+    def __enter__(self):\r
+        self.session = self.session_factory()  # type: Session\r
+        self.oclouds = ocloud_repository\\r
+            .OcloudSqlAlchemyRepository(self.session)\r
+        self.resource_types = ocloud_repository\\r
+            .ResouceTypeSqlAlchemyRepository(self.session)\r
+        self.resource_pools = ocloud_repository\\r
+            .ResourcePoolSqlAlchemyRepository(self.session)\r
+        self.resources = ocloud_repository\\r
+            .ResourceSqlAlchemyRepository(self.session)\r
+        self.deployment_managers = ocloud_repository\\r
+            .DeploymentManagerSqlAlchemyRepository(self.session)\r
+        self.nfdeployment_descs = dms_repository\\r
+            .NfDeploymentDescSqlAlchemyRepository(self.session)\r
+        return super().__enter__()\r
+\r
+    def __exit__(self, *args):\r
+        super().__exit__(*args)\r
+        self.session.close()\r
+\r
+    def _commit(self):\r
+        self.session.commit()\r
+\r
+    def rollback(self):\r
+        self.session.rollback()\r
+\r
+    def _collect_new_events(self):\r
+        for entry in self.oclouds.seen:\r
+            while entry.events:\r
+                yield entry.events.pop(0)\r
+        for entry in self.resource_pools.seen:\r
+            while entry.events:\r
+                yield entry.events.pop(0)\r
+        for entry in self.resources.seen:\r
+            while entry.events:\r
+                yield entry.events.pop(0)\r
+        for entry in self.resource_types.seen:\r
+            while entry.events:\r
+                yield entry.events.pop(0)\r
+        for entry in self.deployment_managers.seen:\r
+            while entry.events:\r
+                yield entry.events.pop(0)\r
+        for entry in self.nfdeployment_descs.seen:\r
+            while entry.events:\r
+                yield entry.events.pop(0)\r
diff --git a/o2app/bootstrap.py b/o2app/bootstrap.py
new file mode 100644 (file)
index 0000000..7a074f6
--- /dev/null
@@ -0,0 +1,88 @@
+# 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 retry import retry
+import inspect
+from typing import Callable
+
+from o2common.adapter.notifications import AbstractNotifications,\
+    SmoO2Notifications
+from o2common.adapter import redis_eventpublisher
+from o2common.service import unit_of_work
+
+from o2app.service import handlers, messagebus
+from o2app.adapter.unit_of_work import SqlAlchemyUnitOfWork
+
+from o2ims.adapter import orm as o2ims_orm
+from o2dms.adapter import orm as o2dms_orm
+
+from o2common.helper import o2logging
+logger = o2logging.get_logger(__name__)
+
+
+@retry(tries=100, delay=2, backoff=1)
+def wait_for_db_ready(engine):
+    # wait for db up
+    logger.info("Wait for DB ready ...")
+    engine.connect()
+    logger.info("DB is ready")
+
+
+def bootstrap(
+    start_orm: bool = True,
+    uow: unit_of_work.AbstractUnitOfWork = SqlAlchemyUnitOfWork(),
+    notifications: AbstractNotifications = None,
+    publish: Callable = redis_eventpublisher.publish,
+) -> messagebus.MessageBus:
+
+    if notifications is None:
+        notifications = SmoO2Notifications()
+
+    if start_orm:
+        with uow:
+            # get default engine if uow is by default
+            engine = uow.session.get_bind()
+            wait_for_db_ready(engine)
+            o2ims_orm.start_o2ims_mappers(engine)
+            o2dms_orm.start_o2dms_mappers(engine)
+
+    dependencies = {"uow": uow, "notifications": notifications,
+                    "publish": publish}
+    injected_event_handlers = {
+        event_type: [
+            inject_dependencies(handler, dependencies)
+            for handler in event_handlers
+        ]
+        for event_type, event_handlers in handlers.EVENT_HANDLERS.items()
+    }
+    injected_command_handlers = {
+        command_type: inject_dependencies(handler, dependencies)
+        for command_type, handler in handlers.COMMAND_HANDLERS.items()
+    }
+
+    return messagebus.MessageBus(
+        uow=uow,
+        event_handlers=injected_event_handlers,
+        command_handlers=injected_command_handlers,
+    )
+
+
+def inject_dependencies(handler, dependencies):
+    params = inspect.signature(handler).parameters
+    deps = {
+        name: dependency
+        for name, dependency in dependencies.items()
+        if name in params
+    }
+    return lambda message: handler(message, **deps)
diff --git a/o2app/entrypoints/__init__.py b/o2app/entrypoints/__init__.py
new file mode 100644 (file)
index 0000000..b514342
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
diff --git a/o2app/entrypoints/flask_application.py b/o2app/entrypoints/flask_application.py
new file mode 100644 (file)
index 0000000..45c0436
--- /dev/null
@@ -0,0 +1,35 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
+\r
+from flask import Flask\r
+from flask_restx import Api\r
+\r
+from o2app import bootstrap\r
+# from o2ims import config\r
+# from o2ims.views.ocloud_route import configure_routes\r
+from o2ims.views import ocloud_route as ims_route\r
+from o2dms.views import dms_route\r
+\r
+\r
+# apibase = config.get_o2ims_api_base()\r
+app = Flask(__name__)\r
+api = Api(app, version='1.0.0',\r
+          title='O-Cloud O2 Services',\r
+          description='Swagger OpenAPI document for \\r
+          O-Cloud O2 Services',\r
+          )\r
+bus = bootstrap.bootstrap()\r
+\r
+ims_route.configure_namespace(api, bus)\r
+dms_route.configure_namespace(api, bus)\r
diff --git a/o2app/entrypoints/redis_eventconsumer.py b/o2app/entrypoints/redis_eventconsumer.py
new file mode 100644 (file)
index 0000000..188eb87
--- /dev/null
@@ -0,0 +1,46 @@
+# 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.
+
+# import json
+import redis
+
+from o2app import bootstrap
+from o2common.config import config
+# from o2common.domain import commands
+
+from o2common.helper import o2logging
+logger = o2logging.get_logger(__name__)
+
+r = redis.Redis(**config.get_redis_host_and_port())
+
+
+def main():
+    logger.info("Redis pubsub starting")
+    bus = bootstrap.bootstrap()
+    pubsub = r.pubsub(ignore_subscribe_messages=True)
+    pubsub.subscribe("dms_changed")
+
+    for m in pubsub.listen():
+        handle_dms_changed(m, bus)
+
+
+def handle_dms_changed(m, bus):
+    logger.info("handling %s", m)
+    # data = json.loads(m["data"])
+    # cmd = commands.UpdateDms(ref=data["dmsid"])
+    # bus.handle(cmd)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/o2app/entrypoints/resource_watcher.py b/o2app/entrypoints/resource_watcher.py
new file mode 100644 (file)
index 0000000..036596c
--- /dev/null
@@ -0,0 +1,83 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
+\r
+import cotyledon\r
+\r
+from o2app import bootstrap\r
+from o2common.service.watcher.base import WatcherTree\r
+\r
+from o2ims.service.watcher.worker import PollWorker\r
+from o2ims.service.watcher.ocloud_watcher import OcloudWatcher\r
+from o2ims.service.watcher.ocloud_watcher import DmsWatcher\r
+from o2ims.service.watcher.resourcepool_watcher import ResourcePoolWatcher\r
+from o2ims.adapter.clients.ocloud_sa_client import StxSaDmsClient\r
+from o2ims.adapter.clients.ocloud_sa_client import StxSaOcloudClient\r
+from o2ims.adapter.clients.ocloud_sa_client import StxSaResourcePoolClient\r
+\r
+from o2ims.service.watcher.pserver_watcher import PServerWatcher\r
+from o2ims.adapter.clients.ocloud_sa_client import StxPserverClient\r
+\r
+from o2ims.service.watcher.pserver_cpu_watcher import PServerCpuWatcher\r
+from o2ims.adapter.clients.ocloud_sa_client import StxCpuClient\r
+\r
+from o2common.helper import o2logging\r
+logger = o2logging.get_logger(__name__)\r
+\r
+# r = redis.Redis(**config.get_redis_host_and_port())\r
+\r
+\r
+class WatcherService(cotyledon.Service):\r
+    def __init__(self, worker_id, args=None) -> None:\r
+        super().__init__(worker_id)\r
+        self.args = args\r
+        self.bus = bootstrap.bootstrap()\r
+        self.worker = PollWorker()\r
+\r
+    def run(self):\r
+        try:\r
+            root = WatcherTree(OcloudWatcher(\r
+                StxSaOcloudClient(), self.bus))\r
+            root.addchild(\r
+                DmsWatcher(StxSaDmsClient(), self.bus))\r
+\r
+            child_respool = root.addchild(\r
+                ResourcePoolWatcher(StxSaResourcePoolClient(),\r
+                                    self.bus))\r
+            child_pserver = child_respool.addchild(\r
+                PServerWatcher(StxPserverClient(), self.bus))\r
+            child_pserver.addchild(\r
+                PServerCpuWatcher(StxCpuClient(), self.bus))\r
+\r
+            self.worker.add_watcher(root)\r
+\r
+            self.worker.start()\r
+        except Exception as ex:\r
+            logger.warning("WorkerService Exception:" + str(ex))\r
+        finally:\r
+            self.worker.stop()\r
+\r
+\r
+def start_watchers(sm: cotyledon.ServiceManager = None):\r
+    watchersm = sm if sm else cotyledon.ServiceManager()\r
+    watchersm.add(WatcherService, workers=1, args=())\r
+    watchersm.run()\r
+\r
+\r
+def main():\r
+    logger.info("Resource watcher starting")\r
+    start_watchers()\r
+\r
+\r
+if __name__ == "__main__":\r
+    main()\r
diff --git a/o2app/service/__init__.py b/o2app/service/__init__.py
new file mode 100644 (file)
index 0000000..b514342
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
diff --git a/o2app/service/handlers.py b/o2app/service/handlers.py
new file mode 100644 (file)
index 0000000..830e1ff
--- /dev/null
@@ -0,0 +1,39 @@
+# 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
+# from dataclasses import asdict
+from typing import List, Dict, Callable, Type
+from o2ims.service.auditor import dms_handler
+# TYPE_CHECKING
+from o2ims.domain import commands, events
+from o2ims.service.auditor import ocloud_handler
+
+# if TYPE_CHECKING:
+#     from . import unit_of_work
+
+
+class InvalidResourceType(Exception):
+    pass
+
+
+EVENT_HANDLERS = {
+}  # type: Dict[Type[events.Event], List[Callable]]
+
+
+COMMAND_HANDLERS = {
+    commands.UpdateOCloud: ocloud_handler.update_ocloud,
+    commands.UpdateDms: dms_handler.update_dms
+}  # type: Dict[Type[commands.Command], Callable]
diff --git a/o2app/service/messagebus.py b/o2app/service/messagebus.py
new file mode 100644 (file)
index 0000000..297aa8f
--- /dev/null
@@ -0,0 +1,72 @@
+# 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=broad-except, attribute-defined-outside-init
+from __future__ import annotations
+from typing import Callable, Dict, List, Union, Type, TYPE_CHECKING
+from o2ims.domain import commands, events
+
+if TYPE_CHECKING:
+    from . import unit_of_work
+
+from o2common.helper import o2logging
+logger = o2logging.get_logger(__name__)
+
+Message = Union[commands.Command, events.Event]
+
+
+class MessageBus:
+    def __init__(
+        self,
+        uow: unit_of_work.AbstractUnitOfWork,
+        event_handlers: Dict[Type[events.Event], List[Callable]],
+        command_handlers: Dict[Type[commands.Command], Callable],
+    ):
+        self.uow = uow
+        self.event_handlers = event_handlers
+        self.command_handlers = command_handlers
+
+    def handle(self, message: Message):
+        self.queue = [message]
+        while self.queue:
+            message = self.queue.pop(0)
+            if not message:
+                continue
+            elif isinstance(message, events.Event):
+                self.handle_event(message)
+            elif isinstance(message, commands.Command):
+                self.handle_command(message)
+            else:
+                raise Exception(f"{message} was not an Event or Command")
+
+    def handle_event(self, event: events.Event):
+        for handler in self.event_handlers[type(event)]:
+            try:
+                logger.debug("handling event %s with handler %s",
+                             event, handler)
+                handler(event)
+                self.queue.extend(self.uow.collect_new_events())
+            except Exception:
+                logger.exception("Exception handling event %s", event)
+                continue
+
+    def handle_command(self, command: commands.Command):
+        logger.debug("handling command %s", command)
+        try:
+            handler = self.command_handlers[type(command)]
+            handler(command)
+            self.queue.extend(self.uow.collect_new_events())
+        except Exception as ex:
+            logger.exception("Exception handling command %s", command)
+            raise ex
diff --git a/o2common/adapter/__init__.py b/o2common/adapter/__init__.py
new file mode 100644 (file)
index 0000000..b514342
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
diff --git a/o2common/adapter/notifications.py b/o2common/adapter/notifications.py
new file mode 100644 (file)
index 0000000..4c49c1b
--- /dev/null
@@ -0,0 +1,20 @@
+# pylint: disable=too-few-public-methods
+import abc
+from o2ims import config
+
+
+SMO_O2_ENDPOINT = config.get_smo_o2endpoint()
+
+
+class AbstractNotifications(abc.ABC):
+    @abc.abstractmethod
+    def send(self, message):
+        raise NotImplementedError
+
+
+class SmoO2Notifications(AbstractNotifications):
+    def __init__(self, smoO2Endpoint=SMO_O2_ENDPOINT):
+        self.smoO2Endpoint = smoO2Endpoint
+
+    def send(self, message):
+        pass
diff --git a/o2common/adapter/redis_eventpublisher.py b/o2common/adapter/redis_eventpublisher.py
new file mode 100644 (file)
index 0000000..4df167e
--- /dev/null
@@ -0,0 +1,31 @@
+# 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.
+
+import json
+from dataclasses import asdict
+import redis
+
+from o2ims import config
+from o2ims.domain import events
+
+from o2common.helper import o2logging
+logger = o2logging.get_logger(__name__)
+
+
+r = redis.Redis(**config.get_redis_host_and_port())
+
+
+def publish(channel, event: events.Event):
+    logger.info("publishing: channel=%s, event=%s", channel, event)
+    r.publish(channel, json.dumps(asdict(event)))
diff --git a/o2common/config/__init__.py b/o2common/config/__init__.py
new file mode 100644 (file)
index 0000000..b514342
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
diff --git a/o2common/config/config.py b/o2common/config/config.py
new file mode 100644 (file)
index 0000000..55d4755
--- /dev/null
@@ -0,0 +1,93 @@
+# 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.
+
+import os
+import sys
+
+from o2common.helper import o2logging
+logger = o2logging.get_logger(__name__)
+
+
+def get_postgres_uri():
+    host = os.environ.get("DB_HOST", "localhost")
+    port = 54321 if host == "localhost" else 5432
+    password = os.environ.get("DB_PASSWORD", "o2ims123")
+    user, db_name = "o2ims", "o2ims"
+    return f"postgresql://{user}:{password}@{host}:{port}/{db_name}"
+
+
+def get_api_url():
+    host = os.environ.get("API_HOST", "localhost")
+    port = 5005 if host == "localhost" else 80
+    return f"http://{host}:{port}"
+
+
+def get_root_api_base():
+    return "/"
+
+
+def get_o2ims_api_base():
+    return get_root_api_base() + 'o2ims_infrastructureInventory/v1'
+
+
+def get_o2dms_api_base():
+    return get_root_api_base() + "o2dms/v1"
+
+
+def get_redis_host_and_port():
+    host = os.environ.get("REDIS_HOST", "localhost")
+    port = 63791 if host == "localhost" else 6379
+    return dict(host=host, port=port)
+
+
+def get_smo_o2endpoint():
+    smo_o2endpoint = os.environ.get(
+        "SMO_O2_ENDPOINT", "http://localhost/smo_sim")
+    return smo_o2endpoint
+
+
+def get_stx_access_info():
+    # authurl = os.environ.get("STX_AUTH_URL", "http://192.168.204.1:5000/v3")
+    # username = os.environ.get("STX_USERNAME", "admin")
+    # pswd = os.environ.get("STX_PASSWORD", "passwd1")
+    # stx_access_info = (authurl, username, pswd)
+    try:
+        client_args = dict(
+            auth_url=os.environ.get('OS_AUTH_URL',
+                                    "http://192.168.204.1:5000/v3"),
+            username=os.environ.get('OS_USERNAME', "admin"),
+            api_key=os.environ.get('OS_PASSWORD', "fakepasswd1"),
+            project_name=os.environ.get('OS_PROJECT_NAME', "admin"),
+        )
+        # dc_client_args = dict(
+        #     auth_url=os.environ['OS_AUTH_URL'],
+        #     username=os.environ['OS_USERNAME'],
+        #     api_key=os.environ['OS_PASSWORD'],
+        #     project_name=os.environ['OS_PROJECT_NAME'],
+        #     user_domain_name=os.environ['OS_USER_DOMAIN_NAME'],
+        #     project_domain_name=os.environ['OS_PROJECT_NAME'],
+        #     project_domain_id=os.environ['OS_PROJECT_DOMAIN_ID']
+        # )
+    except KeyError:
+        logger.error('Please source your RC file before execution, '
+                     'e.g.: `source ~/downloads/admin-rc.sh`')
+        sys.exit(1)
+
+    os_client_args = {}
+    for key, val in client_args.items():
+        os_client_args['os_{key}'.format(key=key)] = val
+    os_client_args['os_password'] = os_client_args.pop('os_api_key')
+    os_client_args['os_region_name'] = 'RegionOne'
+    os_client_args['api_version'] = 1
+    return os_client_args
diff --git a/o2common/domain/__init__.py b/o2common/domain/__init__.py
new file mode 100644 (file)
index 0000000..b514342
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
diff --git a/o2common/domain/base.py b/o2common/domain/base.py
new file mode 100644 (file)
index 0000000..8a673da
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
+\r
+from datetime import datetime\r
+from typing import List\r
+from .events import Event\r
+\r
+\r
+class AgRoot:\r
+    def __init__(self) -> None:\r
+        self.hash = ""\r
+        # self.id = ""\r
+        self.updatetime = datetime.now()\r
+        self.createtime = datetime.now()\r
+        self.events = []  # type: List[Event]\r
diff --git a/o2common/domain/commands.py b/o2common/domain/commands.py
new file mode 100644 (file)
index 0000000..8383f47
--- /dev/null
@@ -0,0 +1,60 @@
+# 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=too-few-public-methods
+# from datetime import date
+# from typing import Optional
+from dataclasses import dataclass
+# from datetime import datetime
+# from o2ims.domain.resource_type import ResourceTypeEnum
+from o2ims.domain.stx_object import StxGenericModel
+
+
+class Command:
+    pass
+
+
+@dataclass
+class UpdateStxObject(Command):
+    data: StxGenericModel
+
+
+@dataclass
+class UpdateOCloud(UpdateStxObject):
+    pass
+
+
+@dataclass
+class UpdateDms(UpdateStxObject):
+    parentid: str
+
+
+@dataclass
+class UpdateResourcePool(UpdateStxObject):
+    parentid: str
+
+
+@dataclass
+class UpdateResource(UpdateStxObject):
+    parentid: str
+
+
+@dataclass
+class UpdatePserverCpu(UpdateResource):
+    pass
+
+
+@dataclass
+class UpdatePserver(UpdateResource):
+    pass
diff --git a/o2common/domain/events.py b/o2common/domain/events.py
new file mode 100644 (file)
index 0000000..591662f
--- /dev/null
@@ -0,0 +1,25 @@
+# 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=too-few-public-methods
+from dataclasses import dataclass
+
+
+class Event:
+    pass
+
+
+@dataclass
+class OcloudUpdated(Event):
+    oCloudId: str
diff --git a/o2common/service/__init__.py b/o2common/service/__init__.py
new file mode 100644 (file)
index 0000000..b514342
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
diff --git a/o2common/service/unit_of_work.py b/o2common/service/unit_of_work.py
new file mode 100644 (file)
index 0000000..3bef2a3
--- /dev/null
@@ -0,0 +1,54 @@
+# 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=attribute-defined-outside-init
+from __future__ import annotations
+import abc
+
+from o2ims.domain.ocloud_repo import OcloudRepository,\
+    ResourcePoolRepository, ResourceRepository, ResourceTypeRepository,\
+    DeploymentManagerRepository
+from o2ims.domain.stx_repo import StxObjectRepository
+
+
+class AbstractUnitOfWork(abc.ABC):
+    oclouds: OcloudRepository
+    resource_types: ResourceTypeRepository
+    resource_pools: ResourcePoolRepository
+    resources: ResourceRepository
+    deployment_managers: DeploymentManagerRepository
+    stxobjects: StxObjectRepository
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, *args):
+        self.rollback()
+
+    def commit(self):
+        self._commit()
+
+    def collect_new_events(self):
+        return self._collect_new_events()
+
+    def _collect_new_events(self):
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def _commit(self):
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def rollback(self):
+        raise NotImplementedError
diff --git a/o2common/service/watcher/__init__.py b/o2common/service/watcher/__init__.py
new file mode 100644 (file)
index 0000000..b514342
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
diff --git a/o2common/service/watcher/base.py b/o2common/service/watcher/base.py
new file mode 100644 (file)
index 0000000..0daf8d4
--- /dev/null
@@ -0,0 +1,98 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
+\r
+# from logging import exception\r
+# from cgtsclient import exc\r
+from o2ims.service.client.base_client import BaseClient\r
+# from o2ims.domain.stx_object import StxGenericModel\r
+# from o2ims.service.unit_of_work import AbstractUnitOfWork\r
+from o2ims.domain import commands\r
+from o2ims.service.messagebus import MessageBus\r
+from o2common.helper import o2logging\r
+logger = o2logging.get_logger(__name__)\r
+\r
+\r
+class BaseWatcher(object):\r
+    def __init__(self, client: BaseClient,\r
+                 bus: MessageBus) -> None:\r
+        super().__init__()\r
+        self._client = client\r
+        self._bus = bus\r
+        # self._uow = bus.uow\r
+\r
+    def targetname(self) -> str:\r
+        return self._targetname()\r
+\r
+    def probe(self, parent: commands.UpdateStxObject = None):\r
+        try:\r
+            cmds = self._probe(parent.data if parent else None)\r
+            for cmd in cmds:\r
+                self._bus.handle(cmd)\r
+\r
+            # return self._probe(parent)\r
+            return cmds\r
+        except Exception as ex:\r
+            logger.warning("Failed to probe resource due to: " + str(ex))\r
+            return []\r
+\r
+    def _probe(self, parent: object = None) -> commands.UpdateStxObject:\r
+        raise NotImplementedError\r
+\r
+    def _targetname(self):\r
+        raise NotImplementedError\r
+\r
+    # def _compare_and_update(self, newmodel: StxGenericModel) -> bool:\r
+    #     with self._uow:\r
+    #         # localmodel = self._uow.stxobjects.get(ocloudmodel.id)\r
+    #         localmodel = self._uow.stxobjects.get(str(newmodel.id))\r
+    #         if not localmodel:\r
+    #             logger.info("add entry:" + newmodel.name)\r
+    #             self._uow.stxobjects.add(newmodel)\r
+    #         elif localmodel.is_outdated(newmodel):\r
+    #             logger.info("update entry:" + newmodel.name)\r
+    #             localmodel.update_by(newmodel)\r
+    #             self._uow.stxobjects.update(localmodel)\r
+    #         self._uow.commit()\r
+\r
+\r
+# node to organize watchers in tree hierachy\r
+class WatcherTree(object):\r
+    def __init__(self, watcher: BaseWatcher) -> None:\r
+        super().__init__()\r
+        self.watcher = watcher\r
+        self.children = {}\r
+\r
+    def addchild(self, watcher: BaseWatcher) -> object:\r
+        child = WatcherTree(watcher)\r
+        self.children[watcher.targetname()] = child\r
+        return child\r
+\r
+    def removechild(self, targetname: str) -> object:\r
+        return self.children.pop(targetname)\r
+\r
+    # probe all resources by parent, depth = 0 for indefinite recursive\r
+    def probe(self, parentresource=None, depth: int = 0):\r
+        logger.debug("probe resources with watcher: "\r
+                     + self.watcher.targetname())\r
+        childdepth = depth - 1 if depth > 0 else 0\r
+        resources = self.watcher.probe(parentresource)\r
+        logger.debug("probe returns " + str(len(resources)) + " resources")\r
+\r
+        if depth == 1:\r
+            # stop recursive\r
+            return\r
+\r
+        for res in resources:\r
+            for targetname in self.children.keys():\r
+                self.children[targetname].probe(res, childdepth)\r
diff --git a/o2dms/adapter/__init__.py b/o2dms/adapter/__init__.py
new file mode 100644 (file)
index 0000000..b514342
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
diff --git a/o2dms/adapter/dms_repository.py b/o2dms/adapter/dms_repository.py
new file mode 100644 (file)
index 0000000..c69acff
--- /dev/null
@@ -0,0 +1,37 @@
+# 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 typing import List
+from o2dms.domain import dms, dms_repo
+
+
+class NfDeploymentDescSqlAlchemyRepository(dms_repo
+                                           .NfDeploymentDescRepository):
+
+    def __init__(self, session):
+        super().__init__()
+        self.session = session
+
+    def _add(self, nfdeployment_desc: dms.NfDeploymentDesc):
+        self.session.add(nfdeployment_desc)
+
+    def _get(self, nfdeployment_desc_id) -> dms.NfDeploymentDesc:
+        return self.session.query(dms.NfDeploymentDesc).filter_by(
+            nfDeploymentDescId=nfdeployment_desc_id).first()
+
+    def _list(self) -> List[dms.NfDeploymentDesc]:
+        return self.session.query()
+
+    def _update(self, nfdeployment_desc: dms.NfDeploymentDesc):
+        self.session.add(nfdeployment_desc)
diff --git a/o2dms/adapter/orm.py b/o2dms/adapter/orm.py
new file mode 100644 (file)
index 0000000..7527515
--- /dev/null
@@ -0,0 +1,61 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
+\r
+from sqlalchemy import (\r
+    Table,\r
+    MetaData,\r
+    Column,\r
+    Integer,\r
+    String,\r
+    # Date,\r
+    DateTime,\r
+    # ForeignKey,\r
+    # engine,\r
+    # event,\r
+)\r
+\r
+from sqlalchemy.orm import mapper\r
+from o2dms.domain import dms as dmsModel\r
+\r
+from o2common.helper import o2logging\r
+logger = o2logging.get_logger(__name__)\r
+\r
+metadata = MetaData()\r
+\r
+nfDeploymentDesc = Table(\r
+    "nfDeploymentDesc",\r
+    metadata,\r
+    Column("updatetime", DateTime),\r
+    Column("createtime", DateTime),\r
+    Column("hash", String(255)),\r
+    Column("version_number", Integer),\r
+\r
+    Column("id", String(255), primary_key=True),\r
+    Column("deploymentManagerId", String(255)),\r
+    Column("name", String(255)),\r
+    Column("description", String(255)),\r
+    Column("supportedLocations", String(255)),\r
+    Column("capabilities", String(255)),\r
+    Column("capacity", String(255)),\r
+    # Column("extensions", String(1024))\r
+)\r
+\r
+\r
+def start_o2dms_mappers(engine=None):\r
+    logger.info("Starting O2 DMS mappers")\r
+\r
+    mapper(dmsModel.NfDeploymentDesc, nfDeploymentDesc)\r
+\r
+    if engine is not None:\r
+        metadata.create_all(engine)\r
diff --git a/o2dms/domain/dms.py b/o2dms/domain/dms.py
new file mode 100644 (file)
index 0000000..d80b4a6
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
+\r
+from __future__ import annotations\r
+\r
+from o2ims.domain.base import AgRoot\r
+\r
+\r
+class NfDeploymentDesc(AgRoot):\r
+    def __init__(self, id: str, name: str, dmsId: str, description: str = '',\r
+                 inputParams: str = '', outputParams: str = '',) -> None:\r
+        super().__init__()\r
+        self.id = id\r
+        self.version_number = 0\r
+        self.dmsId = dmsId\r
+        self.name = name\r
+        self.description = description\r
+        self.inputParams = inputParams\r
+        self.outputParams = outputParams\r
+        self.extensions = []\r
diff --git a/o2dms/domain/dms_repo.py b/o2dms/domain/dms_repo.py
new file mode 100644 (file)
index 0000000..f199a3c
--- /dev/null
@@ -0,0 +1,50 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
+\r
+import abc\r
+from typing import List, Set\r
+from o2dms.domain import dms\r
+\r
+\r
+class NfDeploymentDescRepository(abc.ABC):\r
+    def __init__(self):\r
+        self.seen = set()  # type: Set[dms.NfDeploymentDesc]\r
+\r
+    def add(self, nfdeployment_descriptor: dms.NfDeploymentDesc):\r
+        self._add(nfdeployment_descriptor)\r
+        self.seen.add(nfdeployment_descriptor)\r
+\r
+    def get(self, nfdeployment_descriptor_id) -> dms.NfDeploymentDesc:\r
+        nfdeployment_descriptor = self._get(nfdeployment_descriptor_id)\r
+        if nfdeployment_descriptor:\r
+            self.seen.add(nfdeployment_descriptor)\r
+        return nfdeployment_descriptor\r
+\r
+    def list(self) -> List[dms.NfDeploymentDesc]:\r
+        return self._list()\r
+\r
+    def update(self, nfdeployment_descriptor: dms.NfDeploymentDesc):\r
+        self._update(nfdeployment_descriptor)\r
+\r
+    @abc.abstractmethod\r
+    def _add(self, nfdeployment_descriptor: dms.NfDeploymentDesc):\r
+        raise NotImplementedError\r
+\r
+    @abc.abstractmethod\r
+    def _get(self, nfdeployment_descriptor_id) -> dms.NfDeploymentDesc:\r
+        raise NotImplementedError\r
+\r
+    @abc.abstractmethod\r
+    def _update(self, nfdeployment_descriptor: dms.NfDeploymentDesc):\r
+        raise NotImplementedError\r
diff --git a/o2dms/service/__init__.py b/o2dms/service/__init__.py
new file mode 100644 (file)
index 0000000..b514342
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
diff --git a/o2dms/views/__init__.py b/o2dms/views/__init__.py
new file mode 100644 (file)
index 0000000..b514342
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
diff --git a/o2dms/views/dms_dto.py b/o2dms/views/dms_dto.py
new file mode 100644 (file)
index 0000000..d353137
--- /dev/null
@@ -0,0 +1,54 @@
+# 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 flask_restx import Namespace, fields
+
+
+class DmsDTO:
+
+    api = Namespace("O2DMS",
+                    description='DMS related operations.')
+
+    dms_get = api.model(
+        "Get DMS information",
+        {
+            'deploymentManagerId': fields.String(
+                required=True,
+                description='Deployment manager ID'),
+            'name': fields.String,
+            'description': fields.String,
+            'supportedLocations': fields.String,
+            'capabilities': fields.String,
+            'capacity': fields.String,
+        }
+    )
+
+
+class DmsLcmNfDeploymentDescriptorDTO:
+
+    api = Namespace("O2DMS_LCM_NfDeploymentDescriptor",
+                    description='DMS LCM NfDeploymentDescritpor operations.')
+
+    dmslcm_NfDeploymentDescriptor_get = api.model(
+        "Get NfDeploymentDescriptor information",
+        {
+            'id': fields.String(
+                required=True,
+                description='NfDeploymentDescriptor ID'),
+            'name': fields.String,
+            'description': fields.String,
+            'inputParams': fields.String,
+            'outputParams': fields.String
+        }
+    )
diff --git a/o2dms/views/dms_lcm_view.py b/o2dms/views/dms_lcm_view.py
new file mode 100644 (file)
index 0000000..32f77cc
--- /dev/null
@@ -0,0 +1,71 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
+\r
+from sqlalchemy import select\r
+\r
+from o2common.service import unit_of_work\r
+from o2ims.adapter.orm import deploymentmanager\r
+from o2dms.adapter.orm import nfDeploymentDesc\r
+\r
+\r
+def deployment_managers(uow: unit_of_work.AbstractUnitOfWork):\r
+    with uow:\r
+        res = uow.session.execute(select(deploymentmanager))\r
+    return [dict(r) for r in res]\r
+\r
+\r
+def deployment_manager_one(deploymentManagerId: str,\r
+                           uow: unit_of_work.AbstractUnitOfWork):\r
+    with uow:\r
+        res = uow.session.execute(select(deploymentmanager).where(\r
+            deploymentmanager.c.deploymentManagerId == deploymentManagerId))\r
+        first = res.first()\r
+    return None if first is None else dict(first)\r
+\r
+\r
+def lcm_nfdeploymentdesc_list(deploymentManagerID: str,\r
+                              uow: unit_of_work.AbstractUnitOfWork):\r
+    with uow:\r
+        res = uow.session.execute(select(nfDeploymentDesc).where(\r
+            nfDeploymentDesc.c.deploymentManagerId == deploymentManagerID))\r
+    return [dict(r) for r in res]\r
+\r
+\r
+def lcm_nfdeploymentdesc_one(nfdeploymentdescriptorid: str,\r
+                             deploymentManagerID: str,\r
+                             uow: unit_of_work.AbstractUnitOfWork):\r
+    with uow:\r
+        res = uow.session.execute(select(deploymentmanager).where(\r
+            nfDeploymentDesc.c.deploymentManagerId == deploymentManagerID,\r
+            nfDeploymentDesc.c.id == nfdeploymentdescriptorid))\r
+        first = res.first()\r
+    return None if first is None else dict(first)\r
+\r
+\r
+# def lcm_nfdeploymentdesc_create(nfdeploymentdescriptorid: str,\r
+#                            uow: unit_of_work.AbstractUnitOfWork):\r
+#     with uow:\r
+#         res = uow.session.execute(select(deploymentmanager).where(\r
+#             deploymentmanager.c.id == nfdeploymentdescriptorid))\r
+#         first = res.first()\r
+#     return None if first is None else dict(first)\r
+\r
+\r
+# def lcm_nfdeploymentdesc_delete(nfdeploymentdescriptorid: str,\r
+#                            uow: unit_of_work.AbstractUnitOfWork):\r
+#     with uow:\r
+#         res = uow.session.execute(select(deploymentmanager).where(\r
+#             deploymentmanager.c.id == nfdeploymentdescriptorid))\r
+#         first = res.first()\r
+#     return None if first is None else dict(first)\r
diff --git a/o2dms/views/dms_route.py b/o2dms/views/dms_route.py
new file mode 100644 (file)
index 0000000..895bfcb
--- /dev/null
@@ -0,0 +1,96 @@
+# 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 flask import jsonify
+from flask_restx import Resource
+
+from o2common.config import config
+from o2dms.views.dms_dto import DmsDTO, DmsLcmNfDeploymentDescriptorDTO
+from o2dms.views import dms_lcm_view
+
+apibase = config.get_o2dms_api_base()
+
+
+# ----------  DeploymentManagers ---------- #
+api_dms = DmsDTO.api
+
+
+@api_dms.route("/<deploymentManagerID>")
+@api_dms.param('deploymentManagerID', 'ID of the deployment manager')
+@api_dms.response(404, 'Deployment manager not found')
+class DmsGetRouter(Resource):
+
+    model = DmsDTO.dms_get
+
+    @api_dms.doc('Get deployment manager')
+    @api_dms.marshal_with(model)
+    def get(self, deploymentManagerID):
+        result = dms_lcm_view.deployment_manager_one(
+            deploymentManagerID, uow)
+        if result is not None:
+            return result
+        api_dms.abort(404, "Deployment manager {} doesn't exist".format(
+            deploymentManagerID))
+
+
+# LCM services #
+api_lcm_nfdeploymentDesc = DmsLcmNfDeploymentDescriptorDTO.api
+
+
+@api_lcm_nfdeploymentDesc\
+    .route("/<deploymentManagerID>/O2dms_DeploymentLifecycle")
+@api_lcm_nfdeploymentDesc\
+    .param('deploymentManagerID', 'ID of the deployment manager')
+@api_lcm_nfdeploymentDesc.response(404, 'DMS LCM not found')
+class DmsLcmNfDeploymentDescListRouter(Resource):
+
+    model = DmsLcmNfDeploymentDescriptorDTO.dmslcm_NfDeploymentDescriptor_get
+
+    @api_lcm_nfdeploymentDesc.doc('Get a list of NfDeploymentDescriptor')
+    @api_lcm_nfdeploymentDesc.marshal_list_with(model)
+    def get(self, deploymentManagerID):
+        return dms_lcm_view.lcm_nfdeploymentdesc_list(deploymentManagerID, uow)
+
+
+@api_lcm_nfdeploymentDesc\
+    .route("/<deploymentManagerID>/O2dms_DeploymentLifecycle/"
+           "<nfDeploymentDescriptorId>")
+@api_lcm_nfdeploymentDesc\
+    .param('deploymentManagerID', 'ID of the deployment manager')
+@api_lcm_nfdeploymentDesc.param('nfDeploymentDescriptorId',
+                                'ID of the NfDeploymentDescriptor')
+@api_lcm_nfdeploymentDesc.response(404, 'DMS LCM not found')
+class DmsLcmNfDeploymentDescGetRouter(Resource):
+
+    model = DmsLcmNfDeploymentDescriptorDTO.dmslcm_NfDeploymentDescriptor_get
+
+    @api_lcm_nfdeploymentDesc.doc('Get a NfDeploymentDescriptor')
+    @api_lcm_nfdeploymentDesc.marshal_with(model)
+    def get(self, nfDeploymentDescriptorId, deploymentManagerID):
+        result = dms_lcm_view\
+            .lcm_nfdeploymentdesc_one(nfDeploymentDescriptorId,
+                                      deploymentManagerID, uow)
+        if result is not None:
+            return result
+        api_dms.abort(404, "NfDeploymentDescriptor {} doesn't exist".format(
+            nfDeploymentDescriptorId))
+
+
+def configure_namespace(app, bus):
+    app.add_namespace(api_dms, path=apibase)
+    app.add_namespace(api_lcm_nfdeploymentDesc, path=apibase)
+
+    # Set global uow
+    global uow
+    uow = bus.uow
diff --git a/o2ims/adapter/__init__.py b/o2ims/adapter/__init__.py
new file mode 100644 (file)
index 0000000..b514342
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
index 61c3157..7aafde5 100644 (file)
@@ -111,6 +111,7 @@ deploymentmanager = Table(
     Column("updatetime", DateTime),\r
     Column("createtime", DateTime),\r
     Column("hash", String(255)),\r
+    Column("version_number", Integer),\r
 \r
     Column("deploymentManagerId", String(255), primary_key=True),\r
     Column("oCloudId", ForeignKey("ocloud.oCloudId")),\r
index 7283383..55d4755 100644 (file)
@@ -33,12 +33,16 @@ def get_api_url():
     return f"http://{host}:{port}"
 
 
+def get_root_api_base():
+    return "/"
+
+
 def get_o2ims_api_base():
-    return '/o2ims_infrastructureInventory/v1'
+    return get_root_api_base() + 'o2ims_infrastructureInventory/v1'
 
 
-def get_o2dms_api_base(dmsid: str):
-    return "/" + dmsid + '/o2dms/v1'
+def get_o2dms_api_base():
+    return get_root_api_base() + "o2dms/v1"
 
 
 def get_redis_host_and_port():
index fadb34a..431b2de 100644 (file)
@@ -18,6 +18,7 @@ from flask_restx import Api
 from o2ims import bootstrap\r
 # from o2ims import config\r
 from o2ims.views.ocloud_route import configure_namespace\r
+from o2dms.views import dms_route\r
 \r
 \r
 # apibase = config.get_o2ims_api_base()\r
@@ -29,3 +30,5 @@ api = Api(app, version='1.0.0',
           )\r
 bus = bootstrap.bootstrap()\r
 configure_namespace(api, bus)\r
+\r
+dms_route.configure_namespace(api, bus)\r
index b7d8e83..207f6e2 100644 (file)
@@ -76,7 +76,8 @@ def is_outdated(ocloud: DeploymentManager, stxobj: StxGenericModel):
 
 
 def create_by(stxobj: StxGenericModel, parentid: str) -> DeploymentManager:
-    dmsendpoint = config.get_api_url() + config.get_o2dms_api_base(stxobj.id)
+    dmsendpoint = config.get_api_url() +\
+                  config.get_o2dms_api_base() + "/" + stxobj.id
     description = "A DMS"
     ocloudid = parentid
     supportedLocations = ''
diff --git a/o2ims/views/__init__.py b/o2ims/views/__init__.py
new file mode 100644 (file)
index 0000000..b514342
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
diff --git a/tests/o2app-api-entry.sh b/tests/o2app-api-entry.sh
new file mode 100644 (file)
index 0000000..ecdd768
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+# pip install -e /src
+# python /o2ims/entrypoints/resource_watcher.py
+
+mkdir -p /etc/o2
+cp -r /configs/* /etc/o2/
+mkdir -p /src/o2common
+cp -r /o2common/* /src/o2common
+mkdir -p /src/o2ims
+cp -r /o2ims/* /src/o2ims
+mkdir -p /src/o2dms
+cp -r /o2dms/* /src/o2dms
+mkdir -p /src/o2app
+cp -r /o2app/* /src/o2app
+pip install -e /src
+
+export FLASK_APP=/o2app/entrypoints/flask_application.py
+flask run --host=0.0.0.0 --port=80
similarity index 54%
rename from tests/o2ims-watcher-entry.sh
rename to tests/o2app-redis-entry.sh
index 1ab193e..e47ce96 100644 (file)
@@ -3,9 +3,15 @@
 # pip install -e /src
 # python /o2ims/entrypoints/resource_watcher.py
 
+mkdir -p /etc/o2
 cp -r /configs/* /etc/o2/
+mkdir -p /src/o2common
 cp -r /o2common/* /src/o2common
+mkdir -p /src/o2ims
 cp -r /o2ims/* /src/o2ims
+mkdir -p /src/o2dms
 cp -r /o2dms/* /src/o2dms
+mkdir -p /src/o2app
+cp -r /o2app/* /src/o2app
 pip install -e /src
-python /o2ims/entrypoints/resource_watcher.py
+python /o2app/entrypoints/redis_eventconsumer.py
similarity index 55%
rename from tests/o2ims-redis-entry.sh
rename to tests/o2app-watcher-entry.sh
index be148a2..f112f93 100644 (file)
@@ -3,9 +3,15 @@
 # pip install -e /src
 # python /o2ims/entrypoints/resource_watcher.py
 
+mkdir -p /etc/o2
 cp -r /configs/* /etc/o2/
+mkdir -p /src/o2common
 cp -r /o2common/* /src/o2common
+mkdir -p /src/o2ims
 cp -r /o2ims/* /src/o2ims
+mkdir -p /src/o2dms
 cp -r /o2dms/* /src/o2dms
+mkdir -p /src/o2app
+cp -r /o2app/* /src/o2app
 pip install -e /src
-python /o2ims/entrypoints/redis_eventconsumer.py
+python /o2app/entrypoints/resource_watcher.py