Merge "Fix INF-344 resourceType fields on alarmDictionary"
authorBin Yang <bin.yang@windriver.com>
Fri, 18 Nov 2022 14:42:05 +0000 (14:42 +0000)
committerGerrit Code Review <gerrit@o-ran-sc.org>
Fri, 18 Nov 2022 14:42:05 +0000 (14:42 +0000)
27 files changed:
Dockerfile
charts/resources/scripts/init/o2api_start.sh
configs/log.yaml
o2common/config/config.py
o2common/domain/filter.py
o2common/helper/__init__.py
o2common/helper/o2logging.py
o2common/views/flask_restx_fields.py [new file with mode: 0644]
o2common/views/pagination_view.py
o2common/views/route.py
o2common/views/view.py
o2ims/adapter/clients/ocloud_client.py
o2ims/adapter/orm.py
o2ims/domain/ocloud.py
o2ims/service/auditor/pserver_acc_handler.py
o2ims/service/auditor/pserver_cpu_handler.py
o2ims/service/auditor/pserver_eth_handler.py
o2ims/service/auditor/pserver_handler.py
o2ims/service/auditor/pserver_if_handler.py
o2ims/service/auditor/pserver_mem_handler.py
o2ims/views/alarm_dto.py
o2ims/views/ocloud_dto.py
o2ims/views/ocloud_route.py
o2ims/views/ocloud_view.py
requirements-stx.txt
requirements.txt
tests/unit/test_ocloud.py

index e837ed4..ff9a4e7 100644 (file)
@@ -1,58 +1,86 @@
-FROM python:3.10-slim-buster
-
-RUN apt-get update && apt-get install -y git gcc procps vim curl ssh
-
-# in case git repo is not accessable
-# RUN mkdir -p /cgtsclient
-# COPY temp/config /cgtsclient/
-RUN git clone --depth 1 --branch r/stx.7.0 https://opendev.org/starlingx/config.git /cgtsclient
-RUN pip install -e /cgtsclient/sysinv/cgts-client/cgts-client/
-
-# RUN mkdir -p /distcloud-client
-# COPY temp/distcloud-client /distcloud-client/
-RUN git clone --depth 1 --branch r/stx.7.0 https://opendev.org/starlingx/distcloud-client.git /distcloud-client/
-RUN pip install -e /distcloud-client/distributedcloud-client
-# in case git repo is not accessable
-
-# RUN git clone --depth 1 --branch master https://github.com/cloudify-incubator/cloudify-helm-plugin.git /helmsdk
-RUN git clone --depth 1 --branch r/stx.7.0 https://opendev.org/starlingx/fault.git /faultclient
-RUN pip install -e /faultclient/python-fmclient/fmclient/
-
+FROM nexus3.onap.org:10001/onap/integration-python:10.1.0
+# https://nexus3.onap.org/#browse/search=keyword%3Dintegration-python:d406d405e4cfbf1186265b01088caf9a
+# https://git.onap.org/integration/docker/onap-python/tree/Dockerfile
+
+USER root
+
+ARG user=orano2
+ARG group=orano2
+# Create a group and user
+RUN addgroup -S $group && adduser -S -D -h /home/$user $user $group && \
+    chown -R $user:$group /home/$user &&  \
+    mkdir /var/log/$user && \
+    mkdir -p /src && \
+    mkdir -p /configs/ && \
+    mkdir -p /src/o2app/ && \
+    mkdir -p /src/helm_sdk/ && \
+    mkdir -p /etc/o2/ && \
+    chown -R $user:$group /var/log/$user && \
+    chown -R $user:$group /src && \
+    chown -R $user:$group /configs && \
+    chown -R $user:$group /etc/o2/
 
 COPY requirements.txt /tmp/
 COPY requirements-stx.txt /tmp/
 COPY constraints.txt /tmp/
 
-RUN  pip install -r /tmp/requirements.txt -c /tmp/constraints.txt
 
-# RUN  pip install -r /tmp/requirements-stx.txt
-
-COPY requirements-test.txt /tmp/
-RUN pip install -r /tmp/requirements-test.txt
-
-
-RUN mkdir -p /src
 COPY o2ims/ /src/o2ims/
 COPY o2dms/ /src/o2dms/
 COPY o2common/ /src/o2common/
-
-RUN mkdir -p /src/helm_sdk/
-COPY helm_sdk/ /src/helm_sdk/
-
-RUN mkdir -p /configs/
-COPY configs/ /configs/
-
-RUN mkdir -p /src/o2app/
 COPY o2app/ /src/o2app/
 COPY setup.py /src/
 
-RUN pip install -e /src
+COPY helm_sdk/ /src/helm_sdk/
 
 COPY configs/ /etc/o2/
+COPY configs/ /configs/
 
-COPY tests/ /tests/
-
-RUN curl -O https://get.helm.sh/helm-v3.3.1-linux-amd64.tar.gz;
-RUN tar -zxvf helm-v3.3.1-linux-amd64.tar.gz; cp linux-amd64/helm /usr/local/bin
+RUN set -ex \
+    && apk add --no-cache bash \
+       && apk add --no-cache --virtual .fetch2-deps \
+        git curl \
+    && apk add --no-cache --virtual .build2-deps  \
+               bluez-dev \
+               bzip2-dev \
+               dpkg-dev dpkg \
+               expat-dev \
+               gcc \
+               libc-dev \
+               libffi-dev \
+               libnsl-dev \
+               libtirpc-dev \
+               linux-headers \
+               make \
+               ncurses-dev \
+               openssl-dev \
+               pax-utils \
+               sqlite-dev \
+               tcl-dev \
+               tk \
+               tk-dev \
+               util-linux-dev \
+               xz-dev \
+               zlib-dev \
+    && pip install -r /tmp/requirements.txt -r /tmp/requirements-stx.txt -c /tmp/constraints.txt \
+    && curl -O https://get.helm.sh/helm-v3.3.1-linux-amd64.tar.gz; \
+        tar -zxvf helm-v3.3.1-linux-amd64.tar.gz; \
+        cp linux-amd64/helm /usr/local/bin; \
+        rm -f helm-v3.3.1-linux-amd64.tar.gz \
+    && pip install -e /src \
+    && apk del --no-network .fetch2-deps \
+    && apk del --no-network .build2-deps
+
+# && pip install -r /tmp/requirements.txt -r /tmp/requirements-stx.txt -c /tmp/constraints.txt
+# RUN apt-get update && apt-get install -y git gcc procps vim curl ssh
+# && git clone --depth 1 --branch r/stx.7.0 https://opendev.org/starlingx/config.git /cgtsclient \
+# && git clone --depth 1 --branch r/stx.7.0 https://opendev.org/starlingx/distcloud-client.git /distcloud-client/ \
+# && git clone --depth 1 --branch r/stx.7.0 https://opendev.org/starlingx/fault.git /faultclient \
+# && pip install -e /cgtsclient/sysinv/cgts-client/cgts-client \
+# && pip install -e /distcloud-client/distributedcloud-client \
+# && pip install -e /faultclient/python-fmclient/fmclient \
+# && rm -rf /cgtsclient /distcloud-client /faultclient
 
 WORKDIR /src
+
+# USER $user
index 9b376f4..6c7ebbf 100644 (file)
@@ -22,7 +22,7 @@
 # pip install retry
 
 # pip install -e /root/o2
-pip install -e /src
+pip install -e /src
 
 cat <<EOF>>/etc/hosts
 127.0.0.1  api
index 39b923d..24a9ba4 100644 (file)
@@ -19,28 +19,28 @@ loggers:
     root:
       handlers: [console_handler, file_handler]
       level: "WARNING"
-      propagate: False
-    o2common:
-      handlers: [console_handler, file_handler]
-      level: "WARNING"
-      propagate: False
-    o2ims:
-      handlers: [console_handler, file_handler]
-      level: "DEBUG"
-      propagate: False
-    o2dms:
-      handlers: [console_handler, file_handler]
-      level: "DEBUG"
-      propagate: False
+      propagate: False
+    o2common:
+      handlers: [console_handler, file_handler]
+      level: "WARNING"
+    #   propagate: True
+    o2ims:
+      handlers: [console_handler, file_handler]
+    #   level: "WARNING"
+    #   propagate: True
+    o2dms:
+      handlers: [console_handler, file_handler]
+    #   level: "WARNING"
+    #   propagate: True
 handlers:
     console_handler:
-      level: "DEBUG"
+      level: "NOTSET"
       class: "logging.StreamHandler"
       formatter: "standard"
     file_handler:
-      level: "DEBUG"
+      level: "NOTSET"
       class: "logging.handlers.RotatingFileHandler"
-      filename: "/var/log/o2.log"
+      filename: "/var/log/orano2/o2.log"
       formatter: "standard"
       maxBytes: 52428800
       backupCount: 10
index 3d1f857..54d6d0f 100644 (file)
@@ -36,15 +36,18 @@ def get_smo_ca_config_path():
 
 
 def get_postgres_uri():
-    host = os.environ.get("DB_HOST", "localhost")
-    port = 54321 if host == "localhost" else 5432
+    # host = os.environ.get("DB_HOST", "localhost")
+    # port = 54321 if host == "localhost" else 5432
+    host = "localhost"
+    port = 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_interal = os.environ.get("API_HOST", "localhost")
+    # host_interal = os.environ.get("API_HOST", "localhost")
+    host_interal = "localhost"
     host_external = os.environ.get("API_HOST_EXTERNAL_FLOATING")
     if config.conf.OCLOUD.API_HOST_EXTERNAL_FLOATING is not None and \
             config.conf.OCLOUD.API_HOST_EXTERNAL_FLOATING != '':
@@ -76,8 +79,10 @@ def get_o2dms_api_base():
 
 
 def get_redis_host_and_port():
-    host = os.environ.get("REDIS_HOST", "localhost")
-    port = 63791 if host == "localhost" else 6379
+    # host = os.environ.get("REDIS_HOST", "localhost")
+    # port = 63791 if host == "localhost" else 6379
+    host = "localhost"
+    port = 6379
     return dict(host=host, port=port)
 
 
index 80fe322..de89cea 100644 (file)
@@ -22,45 +22,46 @@ logger = o2logging.get_logger(__name__)
 def gen_orm_filter(obj: ColumnElement, filter_str: str):
     if not filter_str:
         return []
-    filter_without_space = filter_str.replace(" ", "")
+    # filter_without_space = filter_str.replace(" ", "")
+    filter_without_space = filter_str.strip(' ()')
     items = filter_without_space.split(';')
 
     filter_list = list()
     for i in items:
-        if '(' in i:
-            i = i.replace("(", "")
-        if ')' in i:
-            i = i.replace(")", "")
+        if '(' in i:
+            i = i.replace("(", "")
+        if ')' in i:
+            i = i.replace(")", "")
         filter_expr = i.split(',')
         if len(filter_expr) < 3:
             continue
-        filter_op = filter_expr[0]
-        filter_key = filter_expr[1]
+        filter_op = filter_expr[0].strip()
+        filter_key = filter_expr[1].strip()
         filter_vals = filter_expr[2:]
         filter_list.extend(toFilterArgs(
             filter_op, obj, filter_key, filter_vals))
-    logger.info('Filter list length: %d' % len(filter_list))
+    logger.debug('Filter list length: %d' % len(filter_list))
     return filter_list
 
 
 def toFilterArgs(operation: str, obj: ColumnElement, key: str, values: list):
-    if not hasattr(obj, key):
-        logger.warning('Filter attrName %s not in Object %s.' %
-                       (key, str(obj)))
-        raise KeyError(
-            'Filter attrName {} not in the Object'.format(key))
+    if not hasattr(obj, key):
+    #     logger.warning('Filter attrName %s not in Object %s' %
+                       (key, str(obj)))
+        raise KeyError(
+            'Filter attrName {} not in the Object'.format(key))
 
-    if operation in ['eq', 'neq', 'gt', 'lt', 'gte', 'lte']:
-        if len(values) != 1:
-            raise KeyError(
-                'Filter operation one {} is only support one value.'.
-                format(operation))
-    elif operation in ['in', 'nin', 'cont', 'ncont']:
-        if len(values) == 0:
-            raise KeyError('Filter operation {} value is needed.'.
-                           format(operation))
-    else:
-        raise KeyError('Filter operation {} not support.'.format(operation))
+    if operation in ['eq', 'neq', 'gt', 'lt', 'gte', 'lte']:
+        if len(values) != 1:
+            raise KeyError(
+    #             'Filter operation one {} is only support one value'.
+                format(operation))
+    elif operation in ['in', 'nin', 'cont', 'ncont']:
+        if len(values) == 0:
+    #         raise KeyError('Filter operation {} value is needed'.
+                           format(operation))
+    else:
+    #     raise KeyError('Filter operation {} not support'.format(operation))
 
     ll = list()
     if operation == 'eq':
index 813897e..c7f15c5 100644 (file)
 #  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 o2common.helper.o2logging import configure_logger
+
+
+# make sure init logger at the first chance
+configure_logger()
index 31584f5..e1196d2 100644 (file)
@@ -20,17 +20,25 @@ import yaml
 
 
 def get_logger(name=None):
-    CONFIG_FILE = os.environ.get(
-        "LOGGING_CONFIG_FILE", "/etc/o2/log.yaml")
-    if os.path.exists(CONFIG_FILE):
-        with open(file=CONFIG_FILE, mode='r', encoding="utf-8") as file:
-            config_yaml = yaml.load(stream=file, Loader=yaml.FullLoader)
-        logging.config.dictConfig(config=config_yaml)
+    CONFIG_FILE = os.environ.get(
+        "LOGGING_CONFIG_FILE", "/etc/o2/log.yaml")
+    if os.path.exists(CONFIG_FILE):
+        with open(file=CONFIG_FILE, mode='r', encoding="utf-8") as file:
+            config_yaml = yaml.load(stream=file, Loader=yaml.FullLoader)
+        logging.config.dictConfig(config=config_yaml)
 
     logger = logging.getLogger(name)
-
-    # override logging level
+    # override root logger's logging level
     LOGGING_CONFIG_LEVEL = os.environ.get("LOGGING_CONFIG_LEVEL", None)
     if LOGGING_CONFIG_LEVEL:
         logger.setLevel(LOGGING_CONFIG_LEVEL)
     return logger
+
+
+def configure_logger():
+    CONFIG_FILE = os.environ.get(
+        "LOGGING_CONFIG_FILE", "/etc/o2/log.yaml")
+    if os.path.exists(CONFIG_FILE):
+        with open(file=CONFIG_FILE, mode='r', encoding="utf-8") as file:
+            config_yaml = yaml.load(stream=file, Loader=yaml.FullLoader)
+            logging.config.dictConfig(config=config_yaml)
diff --git a/o2common/views/flask_restx_fields.py b/o2common/views/flask_restx_fields.py
new file mode 100644 (file)
index 0000000..0337239
--- /dev/null
@@ -0,0 +1,35 @@
+# Copyright (C) 2022 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.
+
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from flask_restx import fields
+import json
+
+from o2common.helper import o2logging
+logger = o2logging.get_logger(__name__)
+
+
+class Json2Dict(fields.Raw):
+
+    def format(self, value):
+        value2 = None
+        try:
+            value2 = json.loads(value) if value else None
+        except Exception as ex:
+            logger.warning(
+                f"Failed to loads json string: {value}, exception: {str(ex)}")
+            value2 = value
+        return value2
index 9f282f2..2ea68b4 100644 (file)
@@ -38,7 +38,7 @@ class Pagination:
 
     def get_result(self, ret: Tuple[int, List[Serializer]]):
         count = ret[0]
-        logger.info('List count: {}'.format(count))
+        logger.debug('List count: {}'.format(count))
         ret_list = ret[1]
         page_total = int(math.ceil(count/self.limit)
                          ) if count > self.limit else 1
index 9366a32..c6fc56e 100644 (file)
@@ -130,7 +130,7 @@ class o2_marshal_with(marshal_with):
         mask_val = ''
         if 'all_fields' in kwargs:
             all_fields_without_space = kwargs['all_fields'].replace(" ", "")
-            logger.info('all_fields selector value is {}'.format(
+            logger.debug('all_fields selector value is {}'.format(
                 all_fields_without_space))
             # all_fields = all_fields_without_space.lower()
             # if 'true' == all_fields:
index 2b05027..d390634 100644 (file)
@@ -12,7 +12,7 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-import re
+import re
 from sqlalchemy.sql.elements import ColumnElement
 
 from o2common.views.route_exception import BadRequestException
@@ -44,33 +44,49 @@ def gen_filter(obj: ColumnElement, filter_str: str):
 def check_filter(obj: ColumnElement, filter_str: str):
     if not filter_str:
         return
-    pattern = r'^(\((eq|neq|gt|lt|gte|lte){1},\w+,[\w -\.]+\)\;?|' +\
-        r'\((in|nin|cont|ncont){1},\w*(,[\w -\.]*)*\)\;?)+'
-    result = re.match(pattern, filter_str)
-    logger.warning('filter: {} match result is {}'.format(filter_str, result))
-    if not result:
-        raise BadRequestException(
-            'filter value formater not correct.')
+    pattern = r'^(\((eq|neq|gt|lt|gte|lte){1},\w+,[\w -\.]+\)\;?|' +\
+        r'\((in|nin|cont|ncont){1},\w*(,[\w -\.]*)*\)\;?)+'
+    result = re.match(pattern, filter_str)
+    # logger.debug('filter: {} match result is {}'.format(filter_str, result))
+    if not result:
+        raise BadRequestException(
+    #         'filter value format is invalid')
     check_filter_attribute(obj, filter_str)
 
 
 def check_filter_attribute(obj: ColumnElement, filter_str: str):
-    filter_without_space = filter_str.replace(" ", "")
+    # filter_without_space = filter_str.replace(" ", "")
+    filter_without_space = filter_str.strip(' ()')
+    logger.debug(
+        f"filter_str: {filter_str}, stripped: {filter_without_space}")
     items = filter_without_space.split(';')
 
     for i in items:
-        if '(' in i:
-            i = i.replace("(", "")
-        if ')' in i:
-            i = i.replace(")", "")
+        if '(' in i:
+            i = i.replace("(", "")
+        if ')' in i:
+            i = i.replace(")", "")
         filter_expr = i.split(',')
         if len(filter_expr) < 3:
             raise BadRequestException(
-                'Filter {} formater not correct.'.format(i))
+                'ignore invalid filter {}'.format(i))
             continue
-        # filter_op = filter_expr[0]
-        filter_key = filter_expr[1]
-        # filter_vals = filter_expr[2:]
+        filter_op = filter_expr[0].strip()
+        filter_key = filter_expr[1].strip()
+        filter_vals = filter_expr[2:]
+        if filter_op in ["eq", "neq", "gt", "lt", "gte", "lte"]:
+            if len(filter_vals) != 1:
+                raise BadRequestException(
+                    "Found {} values: {} while only single value"
+                    " is allowed for operation {}".format(
+                        len(filter_vals), filter_vals, filter_op)
+                )
+        elif filter_op not in ["in", "nin", "cont", "ncont"]:
+            raise BadRequestException(
+                'Filter operation {} is invalid'.format(filter_op)
+            )
+        else:
+            pass
         if not hasattr(obj, filter_key):
             raise BadRequestException(
-                'Filter attrName {} not in the Object'.format(filter_key))
+                'Filter attrName {} is invalid'.format(filter_key))
index 9fea66c..015da1f 100644 (file)
@@ -270,6 +270,7 @@ class StxClientImp(object):
             ResourceTypeEnum.OCLOUD, systems[0]) if systems else None
 
     def getSubcloudList(self):
+        self.dcclient = self.getDcmanagerClient()
         subs = self.dcclient.subcloud_manager.list_subclouds()
         known_subs = [sub for sub in subs if sub.sync_status != 'unknown']
         return known_subs
index eaefe16..762004f 100644 (file)
@@ -117,9 +117,9 @@ resource = Table(
     Column("name", String(255)),
     Column("globalAssetId", String(255)),
     Column("parentId", String(255)),
-    Column("description", String(255)),
-    Column("elements", Text())
-    # Column("extensions", String(1024))
+    Column("description", String()),
+    Column("elements", Text()),
+    Column("extensions", String())
 )
 
 deploymentmanager = Table(
index 4ec5840..a7ca18e 100644 (file)
@@ -115,7 +115,7 @@ class Resource(AgRoot, Serializer):
     def __init__(self, resourceId: str, resourceTypeId: str,
                  resourcePoolId: str, name: str, parentId: str = '',
                  gAssetId: str = '', elements: str = '',
-                 description: str = '') -> None:
+                 description: str = '', extensions: str = '') -> None:
         super().__init__()
         self.resourceId = resourceId
         self.description = description
@@ -123,7 +123,7 @@ class Resource(AgRoot, Serializer):
         self.globalAssetId = gAssetId
         self.resourcePoolId = resourcePoolId
         self.elements = elements
-        self.extensions = []
+        self.extensions = extensions
 
         self.name = name
         self.parentId = parentId
index 47ff4c6..6c3ed51 100644 (file)
@@ -15,7 +15,7 @@
 # pylint: disable=unused-argument
 from __future__ import annotations
 import uuid
-import json
+import json
 
 from o2ims.domain import commands, events
 from o2ims.domain.stx_object import StxGenericModel
@@ -105,11 +105,21 @@ def create_by(stxobj: StxGenericModel, parent: Resource, resourcetype_id: str)\
     resourcepool_id = parent.resourcePoolId
     parent_id = parent.resourceId
     gAssetId = ''  # TODO: global ID
-    description = "%s : An Accelerator resource of the physical server"\
-        % stxobj.name
+    # description = "%s : An Accelerator resource of the physical server"\
+    #     % stxobj.name
+    content = json.loads(stxobj.content)
+    selected_keys = [
+        "name", "pdevice", "pciaddr", "pvendor_id", "pvendor",
+        "pclass_id", "pclass", "psvendor", "psdevice",
+        "sriov_totalvfs", "sriov_numvfs", "numa_node"
+        ]
+    filtered = dict(
+        filter(lambda item: item[0] in selected_keys, content.items()))
+    extensions = json.dumps(filtered)
+    description = ";".join([f"{k}:{v}" for k, v in filtered.items()])
     resource = Resource(stxobj.id, resourcetype_id, resourcepool_id,
                         stxobj.name, parent_id, gAssetId, stxobj.content,
-                        description)
+                        description, extensions)
     resource.createtime = stxobj.createtime
     resource.updatetime = stxobj.updatetime
     resource.hash = stxobj.hash
index 8c7c2b3..111259c 100644 (file)
@@ -15,7 +15,7 @@
 # pylint: disable=unused-argument
 from __future__ import annotations
 import uuid
-import json
+import json
 
 from o2ims.domain import commands, events
 from o2ims.domain.stx_object import StxGenericModel
@@ -105,10 +105,19 @@ def create_by(stxobj: StxGenericModel, parent: Resource, resourcetype_id: str)\
     resourcepool_id = parent.resourcePoolId
     parent_id = parent.resourceId
     gAssetId = ''  # TODO: global ID
-    description = "%s : A CPU resource of the physical server" % stxobj.name
+    # description = "%s : A CPU resource of the physical server" % stxobj.name
+    content = json.loads(stxobj.content)
+    selected_keys = [
+        "cpu", "core", "thread", "allocated_function", "numa_node",
+        "cpu_model", "cpu_family"
+        ]
+    filtered = dict(
+        filter(lambda item: item[0] in selected_keys, content.items()))
+    extensions = json.dumps(filtered)
+    description = ";".join([f"{k}:{v}" for k, v in filtered.items()])
     resource = Resource(stxobj.id, resourcetype_id, resourcepool_id,
                         stxobj.name, parent_id, gAssetId, stxobj.content,
-                        description)
+                        description, extensions)
     resource.createtime = stxobj.createtime
     resource.updatetime = stxobj.updatetime
     resource.hash = stxobj.hash
index eeb2c79..517bb32 100644 (file)
@@ -15,7 +15,7 @@
 # pylint: disable=unused-argument
 from __future__ import annotations
 import uuid
-import json
+import json
 
 from o2ims.domain import commands, events
 from o2ims.domain.stx_object import StxGenericModel
@@ -105,11 +105,23 @@ def create_by(stxobj: StxGenericModel, parent: Resource, resourcetype_id: str)\
     resourcepool_id = parent.resourcePoolId
     parent_id = parent.resourceId
     gAssetId = ''  # TODO: global ID
-    description = "%s : An ethernet resource of the physical server"\
-        % stxobj.name
+    # description = "%s : An ethernet resource of the physical server"\
+    #     % stxobj.name
+    content = json.loads(stxobj.content)
+    selected_keys = [
+        "name", "namedisplay", "dev_id", "pdevice", "capabilities",
+        "type", "driver", "mac", "numa_node",
+        "pciaddr", "pclass", "psvendor", "psdevice",
+        "sriov_totalvfs", "sriov_numvfs", "dpdksupport",
+        "sriov_vf_driver", "sriov_vf_pdevice_id", "interface_uuid"
+        ]
+    filtered = dict(
+        filter(lambda item: item[0] in selected_keys, content.items()))
+    extensions = json.dumps(filtered)
+    description = ";".join([f"{k}:{v}" for k, v in filtered.items()])
     resource = Resource(stxobj.id, resourcetype_id, resourcepool_id,
                         stxobj.name, parent_id, gAssetId, stxobj.content,
-                        description)
+                        description, extensions)
     resource.createtime = stxobj.createtime
     resource.updatetime = stxobj.updatetime
     resource.hash = stxobj.hash
index 16ef26f..7fa2b12 100644 (file)
@@ -15,7 +15,7 @@
 # pylint: disable=unused-argument
 from __future__ import annotations
 import uuid
-import json
+import json
 from typing import Callable
 
 from o2ims.domain import commands, events
@@ -108,10 +108,22 @@ def create_by(stxobj: StxGenericModel, parentid: str, resourcetype_id: str) \
     resourcepool_id = parentid
     parent_id = None  # the root of the resource has no parent id
     gAssetId = ''  # TODO: global ID
-    description = "%s : A physical server resource" % stxobj.name
+    # description = "%s : A physical server resource" % stxobj.name
+    content = json.loads(stxobj.content)
+    selected_keys = [
+        "hostname", "personality", "id", "mgmt_ip", "mgmt_mac",
+        "software_load", "capabilities",
+        "operational", "availability", "administrative",
+        "boot_device", "rootfs_device", "install_state", "subfunctions",
+        "clock_synchronization", "max_cpu_mhz_allowed"
+        ]
+    filtered = dict(
+        filter(lambda item: item[0] in selected_keys, content.items()))
+    extensions = json.dumps(filtered)
+    description = ";".join([f"{k}:{v}" for k, v in filtered.items()])
     resource = Resource(stxobj.id, resourcetype_id, resourcepool_id,
                         stxobj.name, parent_id, gAssetId, stxobj.content,
-                        description)
+                        description, extensions)
     resource.createtime = stxobj.createtime
     resource.updatetime = stxobj.updatetime
     resource.hash = stxobj.hash
index e96904f..ef5a385 100644 (file)
@@ -15,7 +15,7 @@
 # pylint: disable=unused-argument
 from __future__ import annotations
 import uuid
-import json
+import json
 
 from o2ims.domain import commands, events
 from o2ims.domain.stx_object import StxGenericModel
@@ -105,11 +105,21 @@ def create_by(stxobj: StxGenericModel, parent: Resource, resourcetype_id: str)\
     resourcepool_id = parent.resourcePoolId
     parent_id = parent.resourceId
     gAssetId = ''  # TODO: global ID
-    description = "%s : An interface resource of the physical server"\
-        % stxobj.name
+    # description = "%s : An interface resource of the physical server"\
+    #     % stxobj.name
+    content = json.loads(stxobj.content)
+    selected_keys = [
+        "ifname", "iftype", "imac", "vlan_id", "imtu",
+        "ifclass", "uses", "max_tx_rate",
+        "sriov_vf_driver", "sriov_numvfs", "ptp_role"
+        ]
+    filtered = dict(
+        filter(lambda item: item[0] in selected_keys, content.items()))
+    extensions = json.dumps(filtered)
+    description = ";".join([f"{k}:{v}" for k, v in filtered.items()])
     resource = Resource(stxobj.id, resourcetype_id, resourcepool_id,
                         stxobj.name, parent_id, gAssetId, stxobj.content,
-                        description)
+                        description, extensions)
     resource.createtime = stxobj.createtime
     resource.updatetime = stxobj.updatetime
     resource.hash = stxobj.hash
index 1f38c09..806d8d7 100644 (file)
@@ -15,7 +15,7 @@
 # pylint: disable=unused-argument
 from __future__ import annotations
 import uuid
-import json
+import json
 
 from o2ims.domain import commands, events
 from o2ims.domain.stx_object import StxGenericModel
@@ -105,11 +105,24 @@ def create_by(stxobj: StxGenericModel, parent: Resource, resourcetype_id: str)\
     resourcepool_id = parent.resourcePoolId
     parent_id = parent.resourceId
     gAssetId = ''  # TODO: global ID
-    description = "%s : A memory resource of the physical server"\
-        % stxobj.name
+    # description = "%s : A memory resource of the physical server"\
+    #     % stxobj.name
+    content = json.loads(stxobj.content)
+    selected_keys = [
+        "memtotal_mib", "memavail_mib", "vm_hugepages_use_1G",
+        "vm_hugepages_possible_1G", "hugepages_configured",
+        "vm_hugepages_avail_1G", "vm_hugepages_nr_1G",
+        "vm_hugepages_nr_4K", "vm_hugepages_nr_2M",
+        "vm_hugepages_possible_2M", "vm_hugepages_avail_2M",
+        "platform_reserved_mib", "numa_node"
+        ]
+    filtered = dict(
+        filter(lambda item: item[0] in selected_keys, content.items()))
+    extensions = json.dumps(filtered)
+    description = ";".join([f"{k}:{v}" for k, v in filtered.items()])
     resource = Resource(stxobj.id, resourcetype_id, resourcepool_id,
                         stxobj.name, parent_id, gAssetId, stxobj.content,
-                        description)
+                        description, extensions)
     resource.createtime = stxobj.createtime
     resource.updatetime = stxobj.updatetime
     resource.hash = stxobj.hash
index 823268f..6697f20 100644 (file)
@@ -26,10 +26,21 @@ class AlarmDTO:
                 required=True,
                 description='Alarm Event Record ID'),
             'resourceTypeId': fields.String,
+            'resourceTypeID': fields.String(attribute='resourceTypeId'),
             'resourceId': fields.String,
+            'resourceID': fields.String(attribute='resourceId'),
+            'alarmEventRecordID':
+            fields.String(attribute='alarmEventRecordId'),
             'alarmDefinitionId': fields.String,
+            'alarmDefinitionID': fields.String(attribute='alarmDefinitionId'),
+            'probableCauseId': fields.String,
+            'probableCauseID': fields.String(attribute='probableCauseId'),
             'alarmRaisedTime': fields.String,
             'perceivedSeverity': fields.String,
+            'alarmChangedTime': fields.String,
+            'alarmAcknowledgeTime': fields.String,
+            'alarmAcknowledged': fields.Boolean,
+            'extensions': fields.Raw(attribute='extensions'),
         }
     )
 
index 0a18664..0003f5b 100644 (file)
@@ -15,6 +15,7 @@
 from flask_restx import fields
 
 from o2ims.views.api_ns import api_ims_inventory as api_ims_inventory_v1
+from o2common.views.flask_restx_fields import Json2Dict
 
 
 class OcloudDTO:
@@ -125,7 +126,9 @@ class ResourceDTO:
             'parentId': fields.String,
             'description': fields.String,
             # 'elements': fields.String,
-            'extensions': fields.String
+            # 'extensions': fields.String
+            'extensions': Json2Dict(attribute='extensions')
+            # 'extensions': fields.Raw(attribute='extensions')
         },
         mask='{resourceId,resourcePoolId,resourceTypeId,description,parentId}'
     )
@@ -141,7 +144,9 @@ class ResourceDTO:
             'parentId': fields.String,
             'description': fields.String,
             # 'elements': fields.String,
-            'extensions': fields.String
+            # 'extensions': fields.String
+            'extensions': Json2Dict(attribute='extensions')
+            # 'extensions': fields.Raw(attribute='extensions')
         }
         if iteration_number:
             resource_json_mapping['elements'] = fields.List(
index f6f3b7a..75d0df6 100644 (file)
@@ -262,6 +262,7 @@ class ResourcePoolGetRouter(Resource):
 # ----------  Resources ---------- #
 @api_ims_inventory_v1.route("/v1/resourcePools/<resourcePoolID>/resources")
 @api_ims_inventory_v1.param('resourcePoolID', 'ID of the resource pool')
+@api_ims_inventory_v1.response(404, 'Resource pool not found')
 # @api_ims_inventory_v1.param('sort', 'sort by column name',
 #                             _in='query')
 # @api_ims_inventory_v1.param('per_page', 'The number of results per page ' +
@@ -312,8 +313,10 @@ class ResourcesListRouter(Resource):
         if args.nextpage_opaque_marker is not None:
             kwargs['page'] = args.nextpage_opaque_marker
         kwargs['filter'] = args.filter if args.filter is not None else ''
-
         ret = ocloud_view.resources(resourcePoolID, bus.uow, **kwargs)
+        if ret is None:
+            raise NotFoundException("Resources under {} doesn't exist".format(
+                resourcePoolID))
         return link_header(request.full_path, ret)
 
 
@@ -351,11 +354,11 @@ class ResourceGetRouter(Resource):
     @api_ims_inventory_v1.doc('Get resource')
     @api_ims_inventory_v1.marshal_with(model)
     def get(self, resourcePoolID, resourceID):
-        result = ocloud_view.resource_one(resourceID, bus.uow)
-        if result is not None:
-            return result
-        raise NotFoundException("Resource {} doesn't exist".format(
-            resourceID))
+        result = ocloud_view.resource_one(resourceID, bus.uow, resourcePoolID)
+        if result is None:
+            raise NotFoundException("Resource {} doesn't exist".format(
+                resourceID))
+        return result
 
 
 # ----------  DeploymentManagers ---------- #
index 3c93478..b529c13 100644 (file)
@@ -82,6 +82,11 @@ def resource_pool_one(resourcePoolId: str,
 
 def resources(resourcePoolId: str, uow: unit_of_work.AbstractUnitOfWork,
               **kwargs):
+    with uow:
+        first = uow.resource_pools.get(resourcePoolId)
+    if first is None:
+        raise NotFoundException("ResourcePool {} doesn't exist".format(
+            resourcePoolId))
     pagination = Pagination(**kwargs)
     # filter key should be the same with database name
     query_kwargs = pagination.get_pagination()
@@ -113,10 +118,19 @@ def resources(resourcePoolId: str, uow: unit_of_work.AbstractUnitOfWork,
     return pagination.get_result(ret)
 
 
-def resource_one(resourceId: str, uow: unit_of_work.AbstractUnitOfWork):
+def resource_one(resourceId: str,
+                 uow: unit_of_work.AbstractUnitOfWork, resourcePoolId: str):
     with uow:
-        first = uow.resources.get(resourceId)
-        return first.serialize() if first is not None else None
+        resoucePool = uow.resource_pools.get(resourcePoolId)
+    if resoucePool is None:
+        raise NotFoundException("ResourcePool {} doesn't exist".format(
+            resourcePoolId))
+
+    first = uow.resources.get(resourceId)
+    if first is None:
+        raise NotFoundException("Resource {} doesn't exist".format(
+            resourceId))
+    return first.serialize()
 
 
 def deployment_managers(uow: unit_of_work.AbstractUnitOfWork, **kwargs):
index 31b4dab..77555c6 100644 (file)
@@ -1,4 +1,7 @@
--e git+https://opendev.org/starlingx/distcloud-client.git@master#egg=distributedcloud-client&subdirectory=distributedcloud-client
--e git+https://opendev.org/starlingx/config.git@master#egg=cgtsclient&subdirectory=sysinv/cgts-client/cgts-client
-# -e git+https://github.com/cloudify-incubator/cloudify-helm-plugin.git@master#egg=helmsdk&subdirectory=helm_sdk
--e git+https://opendev.org/starlingx/fault.git@master#egg=fmclient&subdirectory=python-fmclient/fmclient
+# -e git+https://opendev.org/starlingx/distcloud-client.git@master#egg=distributedcloud-client&subdirectory=distributedcloud-client
+# -e git+https://opendev.org/starlingx/config.git@master#egg=cgtsclient&subdirectory=sysinv/cgts-client/cgts-client
+# -e git+https://opendev.org/starlingx/fault.git@master#egg=fmclient&subdirectory=python-fmclient/fmclient
+
+-e git+https://opendev.org/starlingx/distcloud-client.git@r/stx.7.0#egg=distributedcloud-client&subdirectory=distributedcloud-client
+-e git+https://opendev.org/starlingx/config.git@r/stx.7.0#egg=cgtsclient&subdirectory=sysinv/cgts-client/cgts-client
+-e git+https://opendev.org/starlingx/fault.git@r/stx.7.0#egg=fmclient&subdirectory=python-fmclient/fmclient
index 3d03fdd..33350d5 100644 (file)
@@ -17,4 +17,6 @@ ruamel.yaml==0.17.17
 
 # https://github.com/python-restx/flask-restx/issues/460
 # Workaround for this issue
-werkzeug<=2.1.2
\ No newline at end of file
+werkzeug<=2.1.2
+
+pyOpenSSL
index 5b51221..5a5ed2c 100644 (file)
@@ -243,7 +243,8 @@ def test_view_resource_one(mock_uow):
         return_value.serialize.return_value = None
 
     # Query return None
-    resource_res = ocloud_view.resource_one(resource_id1, uow)
+    resource_res = ocloud_view.resource_one(
+        resource_id1, uow, resource_pool_id1)
     assert resource_res is None
 
     session.return_value.query.return_value.filter_by.return_value.first.\
@@ -251,9 +252,10 @@ def test_view_resource_one(mock_uow):
             "resourceId": resource_id1,
             "resourcePoolId": resource_pool_id1
         }
-
-    resource_res = ocloud_view.resource_one(resource_id1, uow)
-    assert str(resource_res.get("resourceId")) == resource_id1
+    resource_res = ocloud_view.resource_one(
+        resource_id1, uow, resource_pool_id1)
+    assert str(resource_res.get("resourceId") == resource_id1)
+    assert str(resource_res.get("resourcePoolId") == resource_pool_id1)
 
 
 def test_view_deployment_managers(mock_uow):