INF-303 Add Infrastructure Monitoring Fault Service; INF-305 update inventory api... 20/9320/5
authorZhang Rong(Jon) <rong.zhang@windriver.com>
Wed, 19 Oct 2022 04:12:59 +0000 (12:12 +0800)
committerZhang Rong(Jon) <rong.zhang@windriver.com>
Wed, 19 Oct 2022 06:22:44 +0000 (14:22 +0800)
1. Add Infrastructure Monitoring Fault Service
2. Update the infrastructure inventory API service path

Issue-ID: INF-303
Issue-ID: INF-305
Signed-off-by: Zhang Rong(Jon) <rong.zhang@windriver.com>
Change-Id: I38ac307fb5e1102c027b7f0b1061f97cfe47277e

40 files changed:
Dockerfile
Dockerfile.localtest
README.md
configs/alarm.yaml [new file with mode: 0644]
configs/config.yaml [new file with mode: 0644]
configs/events.yaml [new file with mode: 0755]
o2app/adapter/unit_of_work.py
o2app/bootstrap.py
o2app/entrypoints/flask_application.py
o2app/entrypoints/redis_eventconsumer.py
o2app/entrypoints/resource_watcher.py
o2app/service/handlers.py
o2common/config/config.py
o2common/service/watcher/base.py
o2common/service/watcher/worker.py
o2ims/adapter/alarm_loader.py [new file with mode: 0644]
o2ims/adapter/alarm_repository.py [new file with mode: 0644]
o2ims/adapter/clients/alarm_dict_client.py [new file with mode: 0644]
o2ims/adapter/clients/fault_client.py [new file with mode: 0644]
o2ims/adapter/orm.py
o2ims/domain/alarm_obj.py [new file with mode: 0644]
o2ims/domain/alarm_repo.py [new file with mode: 0644]
o2ims/domain/commands.py
o2ims/domain/events.py
o2ims/service/auditor/alarm_handler.py [new file with mode: 0644]
o2ims/service/command/notify_alarm_handler.py [new file with mode: 0644]
o2ims/service/event/alarm_event.py [new file with mode: 0644]
o2ims/service/watcher/alarm_watcher.py [new file with mode: 0644]
o2ims/views/__init__.py
o2ims/views/alarm_dto.py [new file with mode: 0644]
o2ims/views/alarm_route.py [new file with mode: 0644]
o2ims/views/alarm_view.py [new file with mode: 0644]
o2ims/views/api_ns.py
requirements-stx.txt
requirements-test.txt
tests/conftest.py
tests/integration-ocloud/test_clientdriver_stx_fault.py [new file with mode: 0644]
tests/unit/test_alarm.py [new file with mode: 0644]
tests/unit/test_ocloud.py
tests/unit/test_provision.py

index 8c33fbe..c3aba8d 100644 (file)
@@ -15,6 +15,8 @@ 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 master https://opendev.org/starlingx/fault.git /faultclient
+RUN pip install -e /faultclient/python-fmclient/fmclient/
 
 
 COPY requirements.txt /tmp/
index a46b178..02ee361 100644 (file)
@@ -7,9 +7,11 @@ RUN apt-get update && apt-get install -y git gcc \
 RUN mkdir -p /cgtsclient && mkdir -p /distcloud-client
 COPY temp/config /cgtsclient/
 COPY temp/distcloud-client /distcloud-client/
+COPY temp/fault /faultclient/
 
 RUN pip install -e cgtsclient/sysinv/cgts-client/cgts-client/ \
-    && pip install -e /distcloud-client/distributedcloud-client
+    && pip install -e /distcloud-client/distributedcloud-client \
+    && pip install -e /faultclient/python-fmclient/fmclient/
 # in case git repo is not accessable
 
 COPY requirements.txt constraints.txt requirements-test.txt /tmp/
index e2e74e0..ab9166e 100644 (file)
--- a/README.md
+++ b/README.md
@@ -6,8 +6,9 @@ cloned into temp before docker building
 ```sh
 mkdir -p temp
 cd temp
-git clone --depth 1 --branch master https://opendev.org/starlingx/config.git
-git clone --depth 1 --branch master https://opendev.org/starlingx/distcloud-client.git
+git clone --branch master https://opendev.org/starlingx/config.git
+git clone --depth 1 --branch r/stx.7.0 https://opendev.org/starlingx/distcloud-client.git
+git clone --depth 1 --branch master https://opendev.org/starlingx/fault.git
 cd config
 git checkout bca406d1
 patch -p1 < ../../cgtsclient-insecure.patch
diff --git a/configs/alarm.yaml b/configs/alarm.yaml
new file mode 100644 (file)
index 0000000..faa76a8
--- /dev/null
@@ -0,0 +1,40 @@
+# 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.
+
+dictionary:
+    pserver:
+        version: 0.1
+        alarmDefinition: [
+          "100.104", "100.105"
+        ]
+    pserver_cpu:
+        version: 0.1
+        alarmDefinition: [
+          "100.101"
+        ]
+    pserver_mem:
+        version: 0.1
+        alarmDefinition: [
+          "100.103"
+        ]
+    pserver_ethernet:
+        version: 0.1
+        alarmDefinition: [
+          "100.102"
+        ]
+    pserver_if:
+        version: 0.1
+        alarmDefinition: [
+          
+        ]
diff --git a/configs/config.yaml b/configs/config.yaml
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/configs/events.yaml b/configs/events.yaml
new file mode 100755 (executable)
index 0000000..d15a423
--- /dev/null
@@ -0,0 +1,3938 @@
+---
+
+#
+# Copyright (c) 2013-2021 Wind River Systems, Inc.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+############################################################################
+#
+# ALARM & CUSTOMER LOG DOCUMENTATION
+#
+############################################################################
+
+############################################################################
+#
+# Record Format ... for documentation
+#
+# 100.001:
+#   Type: < Alarm |  Log >
+#   Description: < yaml string >
+#                OR
+#                [ < yaml string >,      // list of yaml strings
+#                  < yaml string >  ]
+#                OR
+#                critical: < yaml string >     // i.e. dictionary of yaml strings indexed by severity
+#                major:    < yaml string >
+#                minor:    < yaml string >
+#                warning:  < yaml string >
+#   Entity_Instance_ID: < yaml string ... e.g. host=<hostname>.interface=<ifname> >
+#                       OR
+#                       [ < yaml string >,      // list of yaml strings
+#                         < yaml string >  ]
+#   Severity: < critical |  major |  minor |  warning >
+#                       OR
+#                       [ critical, major ]      // list of severity values
+#   Proposed_Repair_Action: < yaml string >      // NOTE ALARM ONLY FIELD
+#                           OR
+#                           critical: < yaml string >     // i.e. dictionary of yaml strings indexed by severity
+#                           major:    < yaml string >
+#                           minor:    < yaml string >
+#                           warning:  < yaml string >
+#   Maintenance_Action: < yaml string >          // NOTE ALARM ONLY FIELD
+#                       OR
+#                       critical: < yaml string >     // i.e. dictionary of yaml strings indexed by severity
+#                       major:    < yaml string >
+#                       minor:    < yaml string >
+#                       warning:  < yaml string >
+#   Inhibit_Alarms: < True | False >            // NOTE ALARM ONLY FIELD
+#   Alarm_Type: < operational-violation | ... >
+#   Probable_Cause: < timing-problem | ... >
+#                   OR
+#                   [ < timing-problem | ... >,      // list of probable-causes
+#                     < timing-problem | ... >  ]
+#   Service_Affecting: < True | False >
+#   Suppression: < True | False >               // NOTE ALARM ONLY FIELD
+#   Management_Affecting_Severity: < none | critical | major | minor | warning >
+#       // lowest alarm level of this type that will block forced upgrades & orchestration actions
+#   Degrade_Affecting_Severity: < none | critical | major | minor >
+#       // lowest alarm level of this type sets a host to 'degraded'
+#
+#
+#   Other Notes:
+#      - use general record format above
+#      - the only dictionaries allowed are ones indexed by severity
+#      - if there are multiple lists in a record,
+#        then they should all have the same # of items and corresponding list items represent instance of alarm
+#      - if you can't describe the alarm/log based on the above rules,
+#        then you can use a multi-line string format
+#      - DELETING alarms from events.yaml: alarms should only be deleted when going to a new Titanium Cloud release
+#      - if all possible alarm severities are mgmt affecting, the convention is to
+#        use 'warning' as the Management_Affecting_Severity, even if warning is not a possible severity for that alarm
+#
+#   Testing:
+#      - Testing of events.yaml can be done by running regular make command
+#        and specifying fm-doc:
+#                nice -n 20 ionice -c Idle make -C build fm-doc.rebuild
+#      - When building, events.yaml will be parsed for correct format, and also
+#        to ensure that Alarm IDs defined in constants.py and fmAlarm.h are
+#        listed in events.yaml
+#
+############################################################################
+
+
+#---------------------------------------------------------------------------
+#   Monitored Resource Alarms
+#---------------------------------------------------------------------------
+
+
+100.101:
+    Type: Alarm
+    Description: |-
+        Platform CPU threshold exceeded; threshold x%, actual y% .
+             CRITICAL @ 95%
+             MAJOR    @ 90%
+    Entity_Instance_ID: host=<hostname>
+    Severity: [critical, major]
+    Proposed_Repair_Action: "Monitor and if condition persists, contact next level of support."
+    Maintenance_Action:
+        critical: degrade
+        major: degrade
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: threshold-crossed
+    Service_Affecting: False
+    Suppression: True
+    Management_Affecting_Severity: major
+    Degrade_Affecting_Severity: critical
+
+100.102:
+    Type: Alarm
+    Description: |-
+        VSwitch CPU threshold exceeded; threshold x%, actual y% .
+             CRITICAL @ 95%
+             MAJOR    @ 90%
+             MINOR    @ 80%
+    Entity_Instance_ID: host=<hostname>
+    Severity: [critical, major, minor]
+    Proposed_Repair_Action: "Monitor and if condition persists, contact next level of support."
+    Maintenance_Action:
+        critical: degrade
+        major: degrade
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: threshold-crossed
+    Service_Affecting: False
+    Suppression: True
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+100.103:
+    Type: Alarm
+    Description: |-
+        Memory threshold exceeded; threshold x%, actual y% .
+             CRITICAL @ 90%
+             MAJOR    @ 80%
+    Entity_Instance_ID: |-
+        host=<hostname>
+        OR
+        host=<hostname>.memory=total
+        OR
+        host=<hostname>.memory=platform
+        OR
+        host=<hostname>.numa=node<number>
+    Severity: [critical, major]
+    Proposed_Repair_Action: "Monitor and if condition persists, contact next level of support; may require additional memory on Host."
+    Maintenance_Action:
+        critical: degrade
+        major: degrade
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: threshold-crossed
+    Service_Affecting: False
+    Suppression: True
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: critical
+
+100.104:    # NOTE This should really be split into two different Alarms.
+    Type: Alarm
+    Description: |-
+        host=<hostname>.filesystem=<mount-dir>
+            File System threshold exceeded; threshold x%, actual y% .
+                CRITICAL @ 90%
+                MAJOR    @ 80%
+        OR
+        host=<hostname>.volumegroup=<volumegroup-name>
+            Monitor and if condition persists, consider adding additional physical volumes to the volume group.
+    Entity_Instance_ID: |-
+        host=<hostname>.filesystem=<mount-dir>
+        OR
+        host=<hostname>.volumegroup=<volumegroup-name>
+    Severity: [critical, major]
+    Proposed_Repair_Action: "Reduce usage or resize filesystem."
+    Maintenance_Action:
+        critical: degrade
+        major: degrade
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: threshold-crossed
+    Service_Affecting: False
+    Suppression: True
+    Management_Affecting_Severity: critical
+    Degrade_Affecting_Severity: critical
+
+100.105:
+    Type: Alarm
+    Description: |-
+        Filesystem Alarm Condition:
+        <fs_name> filesystem is not added on both controllers and/or does not have the same size: <hostname>.
+    Entity_Instance_ID: fs_name=<image-conversion>
+    Severity: critical
+    Proposed_Repair_Action: "Add image-conversion filesystem on both controllers.
+                             Consult the System Administration Manual for more details.
+                             If problem persists, contact next level of support."
+    Maintenance_Action: degrade
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: configuration-or-customization-error
+    Service_Affecting: True
+    Suppression: False
+    Management_Affecting_Severity: major
+    Degrade_Affecting_Severity: none
+
+#--------
+# 100.105: Retired (with R2 release): previously monitored /etc/nova/instances
+#          NFS mount from controller to computes
+#--------
+
+100.106:
+    Type: Alarm
+    Description: "'OAM' Port failed."
+    Entity_Instance_ID: host=<hostname>.port=<port-name>
+    Severity: major
+    Proposed_Repair_Action: Check cabling and far-end port configuration and status on adjacent equipment.
+    Maintenance_Action: degrade
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: unknown
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: major
+
+100.107:
+    Type: Alarm
+    Description: |-
+        'OAM' Interface degraded.
+        OR
+        'OAM' Interface failed.
+    Entity_Instance_ID: host=<hostname>.interface=<if-name>
+    Severity: [critical, major]
+    Proposed_Repair_Action: Check cabling and far-end port configuration and status on adjacent equipment.
+    Maintenance_Action:
+        critical: degrade
+        major: degrade
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: unknown
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: major
+
+100.108:
+    Type: Alarm
+    Description: "'MGMT' Port failed."
+    Entity_Instance_ID: host=<hostname>.port=<port-name>
+    Severity: major
+    Proposed_Repair_Action: Check cabling and far-end port configuration and status on adjacent equipment.
+    Maintenance_Action: degrade
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: unknown
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: major
+
+100.109:
+    Type: Alarm
+    Description: |-
+        'MGMT' Interface degraded.
+        OR
+        'MGMT' Interface failed.
+    Entity_Instance_ID: host=<hostname>.interface=<if-name>
+    Severity: [critical, major]
+    Proposed_Repair_Action: Check cabling and far-end port configuration and status on adjacent equipment.
+    Maintenance_Action:
+        critical: degrade
+        major: degrade
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: unknown
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: major
+
+100.110:
+    Type: Alarm
+    Description: "'CLUSTER-HOST' Port failed."
+    Entity_Instance_ID: host=<hostname>.port=<port-name>
+    Severity: major
+    Proposed_Repair_Action: Check cabling and far-end port configuration and status on adjacent equipment.
+    Maintenance_Action: degrade
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: unknown
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: major
+
+100.111:
+    Type: Alarm
+    Description: |-
+        'CLUSTER-HOST' Interface degraded.
+        OR
+        'CLUSTER-HOST' Interface failed.
+    Entity_Instance_ID: host=<hostname>.interface=<if-name>
+    Severity: [critical, major]
+    Proposed_Repair_Action: Check cabling and far-end port configuration and status on adjacent equipment.
+    Maintenance_Action:
+        critical: degrade
+        major: degrade
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: unknown
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: major
+
+100.112:
+    Type: Alarm
+    Description: "'DATA-VRS' Port down."
+    Entity_Instance_ID: host=<hostname>.port=<port-name>
+    Severity: major
+    Proposed_Repair_Action: Check cabling and far-end port configuration and status on adjacent equipment.
+    Maintenance_Action: degrade
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: unknown
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: major
+
+100.113:
+    Type: Alarm
+    Description: |-
+        'DATA-VRS' Interface degraded.
+        OR
+        'DATA-VRS' Interface down.
+    Entity_Instance_ID: host=<hostname>.interface=<if-name>
+    Severity: [critical, major]
+    Proposed_Repair_Action: Check cabling and far-end port configuration and status on adjacent equipment.
+    Maintenance_Action:
+        major: degrade
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: unknown
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: major
+
+100.114:
+    Type: Alarm
+    Description:
+        major: "NTP configuration does not contain any valid or reachable NTP servers."
+        minor: "NTP address <IP address>  is not a valid or a reachable NTP server."
+    Entity_Instance_ID:
+        major: host=<hostname>.ntp
+        minor: host=<hostname>.ntp=<IP address>
+    Severity: [major, minor]
+    Proposed_Repair_Action: "Monitor and if condition persists, contact next level of support."
+    Maintenance_Action: none
+    Inhibit_Alarms:
+    Alarm_Type: communication
+    Probable_Cause: unknown
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+100.115:
+    Type: Alarm
+    Description: "VSwitch Memory Usage, processor <processor> threshold exceeded; threshold x%, actual y% ."
+    Entity_Instance_ID: host=<hostname>.processor=<processor>
+    Severity: [critical, major, minor]
+    Proposed_Repair_Action: "Monitor and if condition persists, contact next level of support."
+    Maintenance_Action:
+        critical: degrade
+        major: degrade
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: threshold-crossed
+    Service_Affecting: False
+    Suppression: True
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: critical
+
+100.116:
+    Type: Alarm
+    Description: "Cinder LVM Thinpool Usage threshold exceeded; threshold x%, actual y% ."
+    Entity_Instance_ID: host=<hostname>
+    Severity: [critical, major, minor]
+    Proposed_Repair_Action: "Monitor and if condition persists, contact next level of support."
+    Maintenance_Action:
+        critical: degrade
+        major: degrade
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: threshold-crossed
+    Service_Affecting: False
+    Suppression: True
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: critical
+
+100.117:
+    Type: Alarm
+    Description: "Nova LVM Thinpool Usage threshold exceeded; threshold x%, actual y% ."
+    Entity_Instance_ID: host=<hostname>
+    Severity: [critical, major, minor]
+    Proposed_Repair_Action: "Monitor and if condition persists, contact next level of support."
+    Maintenance_Action:
+        critical: degrade
+        major: degrade
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: threshold-crossed
+    Service_Affecting: False
+    Suppression: True
+    Management_Affecting_Severity: major
+    Degrade_Affecting_Severity: critical
+
+100.118:
+    Type: Alarm
+    Description: Controller cannot establish connection with remote logging server.
+    Entity_Instance_ID: host=<hostname>
+    Severity: minor
+    Proposed_Repair_Action: "Ensure Remote Log Server IP is reachable from Controller through OAM interface; otherwise contact next level of support."
+    Maintenance_Action: none
+    Inhibit_Alarms: False
+    Alarm_Type: communication
+    Probable_Cause: communication-subsystem-failure
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+100.119:
+    Type: Alarm
+    Description: |-
+        <hostname> does not support the provisioned PTP mode
+        OR
+        <hostname> PTP clocking is out-of-tolerance
+        OR
+        <hostname> is not locked to remote PTP Grand Master
+        OR
+        <hostname> GNSS signal loss state:<state>
+        OR
+        <hostname> 1PPS signal loss state:<state>
+    Entity_Instance_ID: |-
+        host=<hostname>.ptp
+        OR
+        host=<hostname>.ptp=no-lock
+        OR
+        host=<hostname>.ptp=<interface>.unsupported=hardware-timestamping
+        OR
+        host=<hostname>.ptp=<interface>.unsupported=software-timestamping
+        OR
+        host=<hostname>.ptp=<interface>.unsupported=legacy-timestamping
+        OR
+        host=<hostname>.ptp=out-of-tolerance
+        OR
+        host=<hostname>.instance=<instance>.ptp=out-of-tolerance
+        OR
+        host=<hostname>.interface=<interface>.ptp=signal-loss
+    Severity: [major, minor]
+    Proposed_Repair_Action: "Monitor and if condition persists, contact next level of support."
+    Maintenance_Action: none
+    Inhibit_Alarms:
+    Alarm_Type: communication
+    Probable_Cause: unknown
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+100.150:
+    Type: Alarm
+    Description:
+        critical: "service open file descriptor has reached its limit"
+        major: "service open file descriptor is approaching to its limit"
+    Entity_Instance_ID: |-
+        host=<hostname>.resource_type=file-descriptor.service_name=<service-name>
+    Severity: [critical, major]
+    Proposed_Repair_Action: "swact to the other controller if it is available"
+    Maintenance_Action: none
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: threshold-crossed
+    Service_Affecting: True
+    Suppression: False
+    Management_Affecting_Severity: critical
+    Degrade_Affecting_Severity: critical
+
+#---------------------------------------------------------------------------
+#   MAINTENANCE
+#---------------------------------------------------------------------------
+
+
+200.001:
+    Type: Alarm
+    Description: <hostname> was administratively locked to take it out-of-service.
+    Entity_Instance_ID: host=<hostname>
+    Severity: warning
+    Proposed_Repair_Action: Administratively unlock Host to bring it back in-service.
+    Maintenance_Action: none
+    Inhibit_Alarms: True
+    Alarm_Type: operational-violation
+    Probable_Cause: out-of-service
+    Service_Affecting: True
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+200.004:
+    Type: Alarm
+    Description: |-
+        <hostname> experienced a service-affecting failure.
+        Host is being auto recovered by Reboot.
+    Entity_Instance_ID: host=<hostname>
+    Severity: critical
+    Proposed_Repair_Action: If auto-recovery is consistently unable to recover host to the unlocked-enabled state contact next level of support or lock and replace failing host.
+    Maintenance_Action: auto recover
+    Inhibit_Alarms: False
+    Alarm_Type: operational-violation
+    Probable_Cause: application-subsystem-failure
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+200.011:
+    Type: Alarm
+    Description: <hostname> experienced a configuration failure during initialization. Host is being re-configured by Reboot.
+    Entity_Instance_ID: host=<hostname>
+    Severity: critical
+    Proposed_Repair_Action: If auto-recovery is consistently unable to recover host to the unlocked-enabled state contact next level of support or lock and replace failing host.
+    Maintenance_Action: auto-recover
+    Inhibit_Alarms: False
+    Alarm_Type: operational-violation
+    Probable_Cause: configuration-or-customization-error
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+200.010:
+    Type: Alarm
+    Description: <hostname> access to board management module has failed.
+    Entity_Instance_ID: host=<hostname>
+    Severity: warning
+    Proposed_Repair_Action: Check Host's board management configuration and connectivity.
+    Maintenance_Action: auto recover
+    Inhibit_Alarms: False
+    Alarm_Type: operational-violation
+    Probable_Cause: communication-subsystem-failure
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+200.012:
+    Type: Alarm
+    Description: <hostname> controller function has in-service failure while compute services remain healthy.
+    Entity_Instance_ID: host=<hostname>
+    Severity: major
+    Proposed_Repair_Action: Lock and then Unlock host to recover. Avoid using 'Force Lock' action as that will impact compute services running on this host.  If lock action fails then contact next level of support to investigate and recover.
+    Maintenance_Action: "degrade - requires manual action"
+    Inhibit_Alarms: False
+    Alarm_Type: operational-violation
+    Probable_Cause: communication-subsystem-failure
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: major
+
+200.013:
+    Type: Alarm
+    Description: <hostname> compute service of the only available controller is not poperational. Auto-recovery is disabled. Deggrading host instead.
+    Entity_Instance_ID: host=<hostname>
+    Severity: major
+    Proposed_Repair_Action: Enable second controller and Switch Activity (Swact) over to it as soon as possible. Then Lock and Unlock host to recover its local compute service.
+    Maintenance_Action: "degrade - requires manual action"
+    Inhibit_Alarms: False
+    Alarm_Type: operational-violation
+    Probable_Cause: communication-subsystem-failure
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: major
+
+200.005:
+    Type: Alarm
+    Description: |-
+        Degrade:
+        <hostname> is experiencing an intermittent 'Management Network'  communication failures that have exceeded its lower alarming threshold.
+
+        Failure:
+        <hostname> is experiencing a persistent critical 'Management Network' communication failure."
+    Entity_Instance_ID: host=<hostname>
+    Severity: [critical, major]
+    Proposed_Repair_Action: "Check 'Management Network' connectivity and support for multicast messaging. If problem consistently occurs after that and Host is reset, then contact next level of support or lock and replace failing host."
+    Maintenance_Action: auto recover
+    Inhibit_Alarms: False
+    Alarm_Type: communication
+    Probable_Cause: unknown
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+200.009:
+    Type: Alarm
+    Description: |-
+        Degrade:
+        <hostname> is experiencing an intermittent 'Cluster-host Network'  communication failures that have exceeded its lower alarming threshold.
+
+        Failure:
+        <hostname> is experiencing a persistent critical 'Cluster-host Network' communication failure."
+    Entity_Instance_ID: host=<hostname>
+    Severity: [critical, major]
+    Proposed_Repair_Action: "Check 'Cluster-host Network' connectivity and support for multicast messaging. If problem consistently occurs after that and Host is reset, then contact next level of support or lock and replace failing host."
+    Maintenance_Action: auto recover
+    Inhibit_Alarms: False
+    Alarm_Type: communication
+    Probable_Cause: unknown
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+
+200.006:
+    Type: Alarm
+    Description: |-
+        Main Process Monitor Daemon Failure (major):
+            <hostname> 'Process Monitor' (pmond) process is not running or functioning properly. The system is trying to recover this process.
+
+        Monitored Process Failure (critical/major/minor):
+            Critical: <hostname> critical '<processname>' process has failed and could not be auto-recovered gracefully.
+                      Auto-recovery progression by host reboot is required and in progress.
+            Major:    <hostname> is degraded due to the failure of its '<processname>' process. Auto recovery of this major process is in progress.
+            Minor:    <hostname> '<processname>' process has failed. Auto recovery of this minor process is in progress.
+                      OR
+                      <hostname> '<processname>' process has failed. Manual recovery is required.
+    Entity_Instance_ID: host=<hostname>.process=<processname>
+    Severity: [critical, major, minor]
+    Proposed_Repair_Action: |-
+        If this alarm does not automatically clear after some time and continues to be asserted after Host is locked and unlocked then contact next level of support for root cause analysis and recovery.
+
+        If problem consistently occurs after Host is locked and unlocked then contact next level of support for root cause analysis and recovery."
+    Maintenance_Action:
+        critical: auto-recover
+        major: degrade
+        minor:
+    Inhibit_Alarms: False
+    Alarm_Type: operational-violation
+    Probable_Cause: unknown
+    Service_Affecting:
+        critical: True
+        major: True
+        minor: False
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: major
+
+# 200.006:      // NOTE using duplicate ID of a completely analogous Alarm for this
+#     Type: Log
+#     Description: |-
+#         Main Process Monitor Daemon Failure (major)
+#             <hostname> 'Process Monitor' (pmond) process is not running or functioning properly.
+#             The system is trying to recover this process.
+#
+#         Monitored Process Failure (critical/major/minor)
+#             critical: <hostname> critical '<processname>' process has failed and could not be auto-recovered gracefully.
+#                       Auto-recovery progression by host reboot is required and in progress.
+#             major:    <hostname> is degraded due to the failure of its '<processname>' process. Auto recovery of this major process is in progress.
+#             minor:    <hostname> '<processname>' process has failed. Auto recovery of this minor process is in progress.
+#                       OR
+#                       <hostname> '<processname>' process has failed. Manual recovery is required.
+#     Entity_Instance_ID: host=<hostname>.process=<process-name>
+#     Severity: minor
+#     Alarm_Type: other
+#     Probable_Cause: unspecified-reason
+#     Service_Affecting: True
+
+
+200.007:
+    Type: Alarm
+    Description:
+        critical: "Host is degraded due to a 'critical' out-of-tolerance reading from  the '<sensorname>' sensor"
+        major: "Host is degraded due to a 'major' out-of-tolerance reading from  the '<sensorname>' sensor"
+        minor: "Host is reporting a 'minor' out-of-tolerance reading from the '<sensorname>' sensor"
+    Entity_Instance_ID: host=<hostname>.sensor=<sensorname>
+    Severity: [critical, major, minor]
+    Proposed_Repair_Action: "If problem consistently occurs after Host is power cycled and or reset, contact next level of support or lock and replace failing host."
+    Maintenance_Action:
+        critical: degrade
+        major: degrade
+        minor: auto-recover (polling)
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: unspecified-reason
+    Service_Affecting:
+        critical: True
+        major: False
+        minor: False
+    Suppression: True
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: critical
+
+200.014:
+    Type: Alarm
+    Description: "The Hardware Monitor was unable to load, configure and monitor one or more hardware sensors."
+    Entity_Instance_ID: host=<hostname>
+    Severity: minor
+    Proposed_Repair_Action: Check Board Management Controller provisioning. Try reprovisioning the BMC. If problem persists try power cycling the host and then the entire server including the BMC power. If problem persists then contact next level of support.
+    Maintenance_Action: None
+    Inhibit_Alarms: False
+    Alarm_Type: operational-violation
+    Probable_Cause: unknown
+    Service_Affecting: False
+    Suppression: True
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+200.015:
+    Type: Alarm
+    Description: Unable to read one or more sensor groups from this host's board management controller
+    Entity_Instance_ID: host=<hostname>
+    Severity: major
+    Proposed_Repair_Action: Check board management connectivity and try rebooting the board management controller. If problem persists contact next level of support or lock and replace failing host.
+    Maintenance_Action: None
+    Inhibit_Alarms: False
+    Alarm_Type: operational-violation
+    Probable_Cause: unknown
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+
+200.020:
+    Type: Log
+    Description: ["<hostname> has been 'discovered' on the network",
+                  "<hostname> has been 'added' to the system",
+                  "<hostname> has 'entered' multi-node failure avoidance",
+                  "<hostname> has 'exited' multi-node failure avoidance"]
+    Entity_Instance_ID: [host=<hostname>.event=discovered,
+                         host=<hostname>.event=add,
+                         host=<hostname>.event=mnfa_enter,
+                         host=<hostname>.event=mnfa_exit]
+    Severity: warning
+    Alarm_Type: other
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+
+
+200.021:
+    Type: Log
+    Description: ["<hostname> board management controller has been 'provisioned'",
+                  "<hostname> board management controller has been 're-provisioned'",
+                  "<hostname> board management controller has been 'de-provisioned'",
+                  "<hostname> manual 'unlock' request",
+                  "<hostname> manual 'reboot' request",
+                  "<hostname> manual 'reset' request",
+                  "<hostname> manual 'power-off' request",
+                  "<hostname> manual 'power-on' request",
+                  "<hostname> manual 'reinstall' request",
+                  "<hostname> manual 'force-lock' request",
+                  "<hostname> manual 'delete' request",
+                  "<hostname> manual 'controller switchover' request"]
+    Entity_Instance_ID: [host=<hostname>.command=provision,
+                         host=<hostname>.command=reprovision,
+                         host=<hostname>.command=deprovision,
+                         host=<hostname>.command=unlock,
+                         host=<hostname>.command=reboot,
+                         host=<hostname>.command=reset,
+                         host=<hostname>.command=power-off,
+                         host=<hostname>.command=power-on,
+                         host=<hostname>.command=reinstall,
+                         host=<hostname>.command=force-lock,
+                         host=<hostname>.command=delete,
+                         host=<hostname>.command=swact]
+    Severity: warning
+    Alarm_Type: other
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+
+200.022:
+    Type: Log
+    Description: ["<hostname> is now 'disabled'",
+                  "<hostname> is now 'enabled'",
+                  "<hostname> is now 'online'",
+                  "<hostname> is now 'offline'",
+                  "<hostname> is 'disabled-failed' to the system",
+                  "<hostname> reinstall failed",
+                  "<hostname> reinstall completed successfully"]
+    Entity_Instance_ID: [host=<hostname>.state=disabled,
+                         host=<hostname>.state=enabled,
+                         host=<hostname>.status=online,
+                         host=<hostname>.status=offline,
+                         host=<hostname>.status=failed,
+                         host=<hostname>.status=reinstall-failed,
+                         host=<hostname>.status=reinstall-complete]
+    Severity: warning
+    Alarm_Type: other
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+
+
+#---------------------------------------------------------------------------
+#   BACKUP AND RESTORE
+#---------------------------------------------------------------------------
+
+210.001:
+    Type: Alarm
+    Description: System Backup in progress.
+    Entity_Instance_ID: host=controller
+    Severity: minor
+    Proposed_Repair_Action: No action required.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+
+#---------------------------------------------------------------------------
+#   SYSTEM CONFIGURATION
+#---------------------------------------------------------------------------
+
+250.001:
+    Type: Alarm
+    Description: <hostname> Configuration is out-of-date.
+    Entity_Instance_ID: host=<hostname>
+    Severity: major
+    Proposed_Repair_Action: Administratively lock and unlock <hostname>  to update config.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+250.002:
+    Type: Alarm
+    Description: <hostname> Ceph cache tiering configuration is out-of-date.
+    Entity_Instance_ID: cluster=<dist-fs-uuid>
+    Severity: major
+    Proposed_Repair_Action: Apply Ceph service parameter settings.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+250.003:
+    Type: Alarm
+    Description: "Kubernetes certificates rotation failed on host[, reason = <reason_text>]"
+    Entity_Instance_ID: host=<hostname>
+    Severity: major
+    Proposed_Repair_Action: Lock and unlock the host to update services with new certificates (Manually renew kubernetes certificates first if renewal failed).
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+#---------------------------------------------------------------------------
+#   Deployment Manager Monitor
+#---------------------------------------------------------------------------
+260.001:
+    Type: Alarm
+    Description: "Deployment Manager resource not reconciled: <name>"
+    Entity_Instance_ID: resource=<crd-resource>,name=<resource-name>
+    Severity: major
+    Proposed_Repair_Action: Monitor and if condition persists, validate deployment configuration.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: configuration-out-of-date
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+#---------------------------------------------------------------------------
+#   VM Compute Services
+#---------------------------------------------------------------------------
+270.001:
+    Type: Alarm
+    Description: "Host <host_name> compute services failure[, reason = <reason_text>]"
+    Entity_Instance_ID: host=<host_name>.services=compute
+    Severity: critical
+    Proposed_Repair_Action: Wait for host services recovery to complete; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: processing-error
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+270.101:
+    Type: Log
+    Description: "Host <host_name> compute services failure[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+270.102:
+    Type: Log
+    Description: Host <host_name> compute services enabled
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+270.103:
+    Type: Log
+    Description: Host <host_name> compute services disabled
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+
+275.001:
+    Type: Log
+    Description: Host <host_name> hypervisor is now <administrative_state>-<operational_state>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+
+#---------------------------------------------------------------------------
+#   DISTRIBUTED CLOUD
+#---------------------------------------------------------------------------
+
+280.001:
+    Type: Alarm
+    Description: <subcloud> is offline
+    Entity_Instance_ID: subcloud=<subcloud>
+    Severity: critical
+    Proposed_Repair_Action: Wait for subcloud to become online; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: communication
+    Probable_Cause: loss-of-signal
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+280.002:
+    Type: Alarm
+    Description: <subcloud> <resource> sync_status is out-of-sync
+    Entity_Instance_ID: [subcloud=<subcloud>.resource=<compute | network | platform | volumev2>]
+    Severity: major
+    Proposed_Repair_Action: If problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: other
+    Probable_Cause: application-subsystem-failure
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+280.003:
+    Type: Alarm
+    Description: Subcloud Backup Failure
+    Entity_Instance_ID: subcloud=<subcloud>
+    Severity: minor
+    Proposed_Repair_Action: Retry subcloud backup after checking backup input file. If problem persists contact next level of support.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: processing-error
+    Probable_Cause: unknown
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+#---------------------------------------------------------------------------
+#   NETWORK
+#---------------------------------------------------------------------------
+
+300.001:
+    Type: Alarm
+    Description: "'Data' Port failed."
+    Entity_Instance_ID: host=<hostname>.port=<port-uuid>
+    Severity: major
+    Proposed_Repair_Action: Check cabling and far-end port configuration and status on adjacent equipment.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: loss-of-signal
+    Service_Affecting: True
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+
+300.002:
+    Type: Alarm
+    Description: |-
+        'Data' Interface degraded.
+        OR
+        'Data' Interface failed.
+    Entity_Instance_ID: host=<hostname>.interface=<if-uuid>
+    Severity: [critical, major]
+    Proposed_Repair_Action: Check cabling and far-end port configuration and status on adjacent equipment.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: loss-of-signal
+    Service_Affecting: True
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: critical
+
+
+300.003:
+    Type: Alarm
+    Description: Networking Agent not responding.
+    Entity_Instance_ID: host=<hostname>.agent=<agent-uuid>
+    Severity: major
+    Proposed_Repair_Action: "If condition persists, attempt to clear issue by administratively locking and unlocking the Host."
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: underlying-resource-unavailable
+    Service_Affecting: True
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+
+300.004:
+    Type: Alarm
+    Description: No enabled compute host with connectivity to provider network.
+    Entity_Instance_ID: service=networking.providernet=<pnet-uuid>
+    Severity: major
+    Proposed_Repair_Action: Enable compute hosts with required provider network connectivity.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: underlying-resource-unavailable
+    Service_Affecting: True
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+
+300.005:
+    Type: Alarm
+    Description: |-
+        Communication failure detected over provider network x% for ranges y% on host z%.
+        OR
+        Communication failure detected over provider network x% on host z%.
+    Entity_Instance_ID: host=<hostname>.service=networking.providernet=<pnet-uuid>
+    Severity: major
+    Proposed_Repair_Action: Check neighbour switch port VLAN assignments.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: underlying-resource-unavailable
+    Service_Affecting: True
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+
+300.010:
+    Type: Alarm
+    Description: |-
+        ML2 Driver Agent non-reachable
+        OR
+        ML2 Driver Agent reachable but non-responsive
+        OR
+        ML2 Driver Agent authentication failure
+        OR
+        ML2 Driver Agent is unable to sync Neutron database
+    Entity_Instance_ID: host=<hostname>.ml2driver=<driver>
+    Severity: major
+    Proposed_Repair_Action: "Monitor and if condition persists, contact next level of support."
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: processing-error
+    Probable_Cause: underlying-resource-unavailable
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+
+300.012:
+    Type: Alarm
+    Description: "Openflow Controller connection failed."
+    Entity_Instance_ID: host=<hostname>.openflow-controller=<uri>
+    Severity: major
+    Proposed_Repair_Action: Check cabling and far-end port configuration and status on adjacent equipment.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: loss-of-signal
+    Service_Affecting: True
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: critical
+
+
+300.013:
+    Type: Alarm
+    Description: |-
+        No active Openflow controller connections found for this network.
+        OR
+        One or more Openflow controller connections in disconnected state for this network.
+    Entity_Instance_ID: host=<hostname>.openflow-network=<name>
+    Severity: [critical, major]
+    Proposed_Repair_Action: Check cabling and far-end port configuration and status on adjacent equipment.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: loss-of-signal
+    Service_Affecting: True
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: critical
+
+
+300.014:
+    Type: Alarm
+    Description: "OVSDB Manager connection failed."
+    Entity_Instance_ID: host=<hostname>.sdn-controller=<uuid>
+    Severity: major
+    Proposed_Repair_Action: Check cabling and far-end port configuration and status on adjacent equipment.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: loss-of-signal
+    Service_Affecting: True
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: critical
+
+
+300.015:
+    Type: Alarm
+    Description: "No active OVSDB connections found."
+    Entity_Instance_ID: host=<hostname>
+    Severity: critical
+    Proposed_Repair_Action: Check cabling and far-end port configuration and status on adjacent equipment.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: loss-of-signal
+    Service_Affecting: True
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: critical
+
+300.016:
+    Type: Alarm
+    Description: "Dynamic routing agent x% lost connectivity to peer y%."
+    Entity_Instance_ID: host=<hostname>,agent=<agent-uuid>,bgp-peer=<bgp-peer>
+    Severity: major
+    Proposed_Repair_Action: If condition persists, fix connectivity to peer.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: loss-of-signal
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+
+#---------------------------------------------------------------------------
+#   HIGH AVAILABILITY
+#---------------------------------------------------------------------------
+
+400.001:
+    Type: Alarm
+    Description: |-
+        Service group failure; <list of affected services>.
+        OR
+        Service group degraded; <list of affected services>.
+        OR
+        Service group warning; <list of affected services>.
+    Entity_Instance_ID: service_domain=<domain_name>.service_group=<group_name>.host=<hostname>
+    Severity: [critical, major, minor]
+    Proposed_Repair_Action: Contact next level of support.
+    Maintenance_Action:
+    Inhibit_Alarms: False
+    Alarm_Type: processing-error
+    Probable_Cause: underlying-resource-unavailable
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: major
+
+
+400.002:
+    Type: Alarm
+    Description: |-
+        Service group loss of redundancy; expected <num> standby member<s> but only <num> standby member<s> available.
+        OR
+        Service group loss of redundancy; expected <num> standby member<s> but only <num> standby member<s> available.
+        OR
+        Service group loss of redundancy; expected <num> active member<s> but no active members available.
+        OR
+        Service group loss of redundancy; expected <num> active member<s> but only <num> active member<s> available.
+    Entity_Instance_ID: service_domain=<domain_name>.service_group=<group_name>
+    Severity: major
+    Proposed_Repair_Action: "Bring a controller node back in to service, otherwise contact next level of support."
+    Maintenance_Action:
+    Inhibit_Alarms: False
+    Alarm_Type: processing-error
+    Probable_Cause: underlying-resource-unavailable
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+
+400.003:
+    Type: Alarm
+    Description: |-
+        License key is not installed; a valid license key is required for operation.
+        OR
+        License key has expired or is invalid; a valid license key is required for operation.
+        OR
+        Evaluation license key will expire on <date>; there are <num_days> days remaining in this evaluation.
+        OR
+        Evaluation license key will expire on <date>; there is only 1 day remaining in this evaluation.
+    Entity_Instance_ID: host=<hostname>
+    Severity: critical
+    Proposed_Repair_Action: Contact next level of support to obtain a new license key.
+    Maintenance_Action:
+    Inhibit_Alarms: False
+    Alarm_Type: processing-error
+    Probable_Cause: key-expired
+    Service_Affecting: True
+    Suppression: False
+    Management_Affecting_Severity: critical
+    Degrade_Affecting_Severity: none
+
+
+# 400.004:    // NOTE Removed
+#     Type: Alarm
+#     Description: Service group software modification detected; <list of affected files>.
+#     Entity_Instance_ID: host=<hostname>
+#     Severity: major
+#     Proposed_Repair_Action: Contact next level of support.
+#     Maintenance_Action:
+#     Inhibit_Alarms: False
+#     Alarm_Type: processing-error
+#     Probable_Cause: software-program-error
+#     Service_Affecting: True
+#     Suppression: False
+
+
+400.005:
+    Type: Alarm
+    Description: |-
+        Communication failure detected with peer over port <linux-ifname>.
+        OR
+        Communication failure detected with peer over port <linux-ifname> within the last 30 seconds.
+    Entity_Instance_ID: host=<hostname>.network=<mgmt | oam | cluster-host>
+    Severity: major
+    Proposed_Repair_Action: Check cabling and far-end port configuration and status on adjacent equipment.
+    Maintenance_Action:
+    Inhibit_Alarms: False
+    Alarm_Type: communication
+    Probable_Cause: underlying-resource-unavailable
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+
+#---------------------------------------------------------------------------
+#   SM
+#---------------------------------------------------------------------------
+
+401.001:
+    Type: Log
+    Description: Service group <group> state change from <state> to <state> on host <host_name>
+    Entity_Instance_ID: service_domain=<domain>.service_group=<group>.host=<host_name>
+    Severity: critical
+    Alarm_Type: processing-error
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+
+401.002:
+    Type: Log
+    Description: |-
+        Service group <group> loss of redundancy; expected <X> standby member but no standby members available
+        or
+        Service group <group> loss of redundancy; expected <X> standby member but only <Y> standby member(s) available
+        or
+        Service group <group> has no active members available; expected <X> active member(s)
+        or
+        Service group <group> loss of redundancy; expected <X> active member(s) but only <Y> active member(s) available
+    Entity_Instance_ID: service_domain=<domain>.service_group=<group>
+    Severity: critical
+    Alarm_Type: processing-error
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+
+401.003:
+    Type: Log
+    Description: |-
+        License key has expired or is invalid
+        or
+        Evaluation license key will expire on <date>
+        or
+        License key is valid
+    Entity_Instance_ID: host=<host_name>
+    Severity: critical
+    Alarm_Type: processing-error
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+
+401.005:
+    Type: Log
+    Description: |-
+        Communication failure detected with peer over port <port> on host <host name>
+        or
+        Communication failure detected with peer over port <port> on host <host name>  within the last <X> seconds
+        or
+        Communication established  with peer over port <port> on host <host name>
+    Entity_Instance_ID: host=<host_name>.network=<network>
+    Severity: critical
+    Alarm_Type: processing-error
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+
+401.007:
+    Type: Log
+    Description: Swact or swact-force
+    Entity_Instance_ID: host=<host_name>
+    Severity: critical
+    Alarm_Type: processing-error
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+
+
+#---------------------------------------------------------------------------
+#   SECURITY
+#---------------------------------------------------------------------------
+
+500.100:
+    Type: Alarm
+    Description: TPM initialization failed on host.
+    Entity_Instance_ID: host=<hostname>
+    Severity: major
+    Proposed_Repair_Action: reinstall HTTPS certificate; if problem persists contact next level of support.
+    Maintenance_Action: degrade
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: procedural-error
+    Service_Affecting: True
+    Suppression: False
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+500.101:
+    Type: Alarm
+    Description: Developer patch certificate enabled.
+    Entity_Instance_ID: host=controller
+    Severity: critical
+    Proposed_Repair_Action: Reinstall system to disable developer certificate and remove untrusted patches.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+500.200:
+    Type: Alarm
+    Description: |-
+        Certificate 'system certificate-show <uuid>' (mode=<ssl/ssl_ca/docker_registry/openstack/openstack_ca>) expiring soon on <date>.
+        OR
+        Certificate '<Namespace>/<Certificate/Secret>' expiring soon on <date>.
+        OR
+        Certificate '<k8sRootCA/EtcdCA>' expiring soon on <date>.
+    Entity_Instance_ID: |-
+        system.certificate.mode=<mode>.uuid=<uuid>
+        OR
+        namespace=<namespace-name>.certificate=<certificate-name>
+        OR
+        namespace=<namespace-name>.secret=<secret-name>
+        OR
+        system.certificate.k8sRootCA
+    Severity: major
+    Proposed_Repair_Action: Check certificate expiration time. Renew certificate for the entity identified.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: certificate-expiration
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+500.210:
+    Type: Alarm
+    Description: |-
+        Certificate 'system certificate-show <uuid>' (mode=<ssl/ssl_ca/docker_registry/openstack/openstack_ca>) expired.
+        OR
+        Certificate '<Namespace>/<Certificate/Secret>' expired.
+        OR
+        Certificate '<k8sRootCA/EtcdRootCA>' expired.
+    Entity_Instance_ID: |-
+        system.certificate.mode=<mode>.uuid=<uuid>
+        OR
+        namespace=<namespace-name>.certificate=<certificate-name>
+        OR
+        namespace=<namespace-name>.secret=<secret-name>
+        OR
+        system.certificate.k8sRootCA
+    Severity: critical
+    Proposed_Repair_Action: Check certificate expiration time. Renew certificate for the entity identified.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: certificate-expiration
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+500.500:
+    Type: Log
+    Description: "Host <host_name> has IMA Appraisal failure for service <service> when executing <file>, reason = <reason_text>]"
+    Entity_Instance_ID: host=<hostname>.service=<service>
+    Severity: major
+    Alarm_Type: integrity-violation
+    Probable_Cause: information-modification-detected
+    Service_Affecting: False
+
+
+#---------------------------------------------------------------------------
+#   VM
+#---------------------------------------------------------------------------
+
+700.001:
+    Type: Alarm
+    Description: |-
+        Instance <instance_name> owned by <tenant_name> has failed on host <host_name>
+        Instance <instance_name> owned by <tenant_name> has failed to schedule
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Proposed_Repair_Action: The system will attempt recovery; no repair action required
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: processing-error
+    Probable_Cause: software-error
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+700.002:
+    Type: Alarm
+    Description: Instance <instance_name> owned by <tenant_name> is paused on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Proposed_Repair_Action: Unpause the instance
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: processing-error
+    Probable_Cause: procedural-error
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+700.003:
+    Type: Alarm
+    Description: Instance <instance_name> owned by <tenant_name> is suspended on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Proposed_Repair_Action: Resume the instance
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: processing-error
+    Probable_Cause: procedural-error
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+700.004:
+    Type: Alarm
+    Description: Instance <instance_name> owned by <tenant_name> is stopped on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Proposed_Repair_Action: Start the instance
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: processing-error
+    Probable_Cause: procedural-error
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+700.005:
+    Type: Alarm
+    Description: Instance <instance_name> owned by <tenant_name> is rebooting on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Proposed_Repair_Action: Wait for reboot to complete; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: processing-error
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+700.006:
+    Type: Alarm
+    Description: Instance <instance_name> owned by <tenant_name> is rebuilding on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Proposed_Repair_Action: Wait for rebuild to complete; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: processing-error
+    Probable_Cause: underlying-resource-unavailable
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+700.007:
+    Type: Alarm
+    Description: Instance <instance_name> owned by <tenant_name> is evacuating from host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Proposed_Repair_Action: Wait for evacuate to complete; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: processing-error
+    Probable_Cause: underlying-resource-unavailable
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+700.008:
+    Type: Alarm
+    Description: Instance <instance_name> owned by <tenant_name> is live migrating from host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: warning
+    Proposed_Repair_Action: Wait for live migration to complete; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: processing-error
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+700.009:
+    Type: Alarm
+    Description: Instance <instance_name> owned by <tenant_name> is cold migrating from host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Proposed_Repair_Action: Wait for cold migration to complete; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: processing-error
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+700.010:
+    Type: Alarm
+    Description: Instance <instance_name> owned by <tenant_name> has been cold-migrated to host <host_name> waiting for confirmation
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Proposed_Repair_Action: Confirm or revert cold-migrate of instance
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: processing-error
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+700.011:
+    Type: Alarm
+    Description: Instance <instance_name> owned by <tenant_name> is reverting cold migrate to host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Proposed_Repair_Action: "Wait for cold migration revert to complete; if problem persists contact next level of support"
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: other
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+700.012:
+    Type: Alarm
+    Description: Instance <instance_name> owned by <tenant_name> is resizing on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Proposed_Repair_Action: Wait for resize to complete; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: processing-error
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+700.013:
+    Type: Alarm
+    Description: Instance <instance_name> owned by <tenant_name> has been resized on host <host_name> waiting for confirmation
+    Entity_Instance_ID: itenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Proposed_Repair_Action: Confirm or revert resize of instance
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: processing-error
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+700.014:
+    Type: Alarm
+    Description: Instance <instance_name> owned by <tenant_name> is reverting resize on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Proposed_Repair_Action: "Wait for resize revert to complete; if problem  persists contact next level of support"
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: other
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+700.015:
+    Type: Alarm
+    Description: Guest Heartbeat not established for instance <instance_name> owned by <tenant_name> on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: major
+    Proposed_Repair_Action: "Verify that the instance is running the Guest-Client daemon, or disable Guest Heartbeat for the instance if no longer needed, otherwise contact next level of support"
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: communication
+    Probable_Cause: procedural-error
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+700.016:
+    Type: Alarm
+    Description: Multi-Node Recovery Mode
+    Entity_Instance_ID: subsystem=vim
+    Severity: minor
+    Proposed_Repair_Action: "Wait for the system to exit out of this mode"
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+700.017:
+    Type: Alarm
+    Description: Server group <server_group_name> <policy> policy was not satisfied
+    Entity_Instance_ID: server-group<server-group-uuid>
+    Severity: minor
+    Proposed_Repair_Action: "Migrate instances in an attempt to satisfy the policy; if problem persists contact next level of support"
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: processing-error
+    Probable_Cause: procedural-error
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+
+700.101:
+    Type: Log
+    Description: Instance <instance_name> is enabled on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.102:
+    Type: Log
+    Description: Instance <instance_name> owned by <tenant_name> has failed[, reason = <reason_text>]
+        Instance <instance_name> owned by <tenant_name> has failed to schedule[, reason = <reason_text>]
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.103:
+    Type: Log
+    Description: Create issued <by <tenant_name>|by the system> against <instance_name> owned by <tenant_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.104:
+    Type: Log
+    Description: Creating instance <instance_name> owned by <tenant_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.105:
+    Type: Log
+    Description: "Create rejected for instance <instance_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.106:
+    Type: Log
+    Description: "Create cancelled for instance <instance_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.107:
+    Type: Log
+    Description: "Create failed for instance <instance_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.108:
+    Type: Log
+    Description: Inance <instance_name> owned by <tenant_name> has been created
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.109:
+    Type: Log
+    Description: "Delete issued <by tenant <by <tenant_name>|by the system>  against instance <instance_name> owned by <tenant_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.110:
+    Type: Log
+    Description: Deleting instance <instance_name> owned by <tenatn_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.111:
+    Type: Log
+    Description: "Delete rejected for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.112:
+    Type: Log
+    Description: "Delete cancelled for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.113:
+    Type: Log
+    Description: "Delete failed for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.114:
+    Type: Log
+    Description: Deleted instance <instance_name> owned by <tenant_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.115:
+    Type: Log
+    Description: "Pause issued <by <tenant_name>|by the system>  against instance <instance_name> owned by <tenant_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.116:
+    Type: Log
+    Description: Pause inprogress for instance <instance_name> on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.117:
+    Type: Log
+    Description: "Pause rejected for instance <instance_name> enabled on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.118:
+    Type: Log
+    Description: "Pause cancelled for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.119:
+    Type: Log
+    Description: "Pause failed for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.120:
+    Type: Log
+    Description: Pause complete for instance <instance_name> now paused on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.121:
+    Type: Log
+    Description: "Unpause issued <by <tenant_name>|by the system>  against instance <instance_name> owned by <tenant_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.122:
+    Type: Log
+    Description: Unpause inprogress for instance <instance_name> on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.123:
+    Type: Log
+    Description: "Unpause rejected for instance <instance_name> paused on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.124:
+    Type: Log
+    Description: "Unpause cancelled for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.125:
+    Type: Log
+    Description: "Unpause failed for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.126:
+    Type: Log
+    Description: Unpause complete for instance <instance_name> now enabled on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.127:
+    Type: Log
+    Description: "Suspend issued <by <tenant_name>|by the system>  against instance <instance_name> owned by <tenant_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.128:
+    Type: Log
+    Description: Suspend inprogress for instance <instance_name> on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.129:
+    Type: Log
+    Description: "Suspend rejected for instance <instance_name> enabled on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.130:
+    Type: Log
+    Description: "Suspend cancelled for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.131:
+    Type: Log
+    Description: "Suspend failed for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.132:
+    Type: Log
+    Description: Suspend complete for instance <instance_name> now suspended on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.133:
+    Type: Log
+    Description: "Resume issued <by <tenant_name>|by the system>  against instance <instance_name> owned by <tenant_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.134:
+    Type: Log
+    Description: Resume inprogress for instance <instance_name> on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.135:
+    Type: Log
+    Description: "Resume rejected for instance <instance_name> suspended on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.136:
+    Type: Log
+    Description: "Resume cancelled for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.137:
+    Type: Log
+    Description: "Resume failed for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.138:
+    Type: Log
+    Description: Resume complete for instance <instance_name> now enabled on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.139:
+    Type: Log
+    Description: "Start issued <by <tenant_name>|by the system>  against instance <instance_name> owned by <tenant_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.140:
+    Type: Log
+    Description: Start inprogress for instance <instance_name> on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.141:
+    Type: Log
+    Description: "Start rejected for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.142:
+    Type: Log
+    Description: "Start cancelled for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.143:
+    Type: Log
+    Description: "Start failed for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.144:
+    Type: Log
+    Description: Start complete for instance <instance_name> now enabled on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.145:
+    Type: Log
+    Description: "Stop issued <by <tenant_name>|by the system|by the instance>  against instance <instance_name> owned by <tenant_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.146:
+    Type: Log
+    Description: Stop inprogress for instance <instance_name> on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.147:
+    Type: Log
+    Description: "Stop rejected for instance <instance_name> enabled on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.148:
+    Type: Log
+    Description: "Stop cancelled for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.149:
+    Type: Log
+    Description: "Stop failed for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.150:
+    Type: Log
+    Description: Stop complete for instance <instance_name> now disabled on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.151:
+    Type: Log
+    Description: "Live-Migrate issued <by <tenant_name>|by the system>  against instance <instance_name> owned by <tenant_name> from host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.152:
+    Type: Log
+    Description: Live-Migrate inprogress for instance <instance_name> from host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.153:
+    Type: Log
+    Description: "Live-Migrate rejected for instance <instance_name> now on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.154:
+    Type: Log
+    Description: "Live-Migrate cancelled for instance <instance_name> now on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.155:
+    Type: Log
+    Description: "Live-Migrate failed for instance <instance_name> now on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.156:
+    Type: Log
+    Description: Live-Migrate complete for instance <instance_name> now enabled on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.157:
+    Type: Log
+    Description: "Cold-Migrate issued <by <tenant_name>|by the system>  against instance <instance_name> owned by <tenant_name> from host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.158:
+    Type: Log
+    Description: Cold-Migrate inprogress for instance <instance_name> from host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.159:
+    Type: Log
+    Description: "Cold-Migrate rejected for instance <instance_name> now on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.160:
+    Type: Log
+    Description: "Cold-Migrate cancelled for instance <instance_name> now on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.161:
+    Type: Log
+    Description: "Cold-Migrate failed for instance <instance_name> now on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.162:
+    Type: Log
+    Description: Cold-Migrate complete for instance <instance_name> now enabled on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.163:
+    Type: Log
+    Description: "Cold-Migrate-Confirm issued <by <tenant_name>|by the system>  against instance <instance_name> owned by <tenant_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.164:
+    Type: Log
+    Description: Cold-Migrate-Confirm inprogress for instance <instance_name> on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.165:
+    Type: Log
+    Description: "Cold-Migrate-Confirm rejected for instance <instance_name> now enabled on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.166:
+    Type: Log
+    Description: "Cold-Migrate-Confirm cancelled for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.167:
+    Type: Log
+    Description: "Cold-Migrate-Confirm failed for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.168:
+    Type: Log
+    Description: Cold-Migrate-Confirm complete for instance <instance_name> enabled on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.169:
+    Type: Log
+    Description: "Cold-Migrate-Revert issued <by <tenant_name>|by the system>  against instance <instance_name> owned by <tenant_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.170:
+    Type: Log
+    Description: Cold-Migrate-Revert inprogress for instance <instance_name> from host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.171:
+    Type: Log
+    Description: "Cold-Migrate-Revert rejected for instance <instance_name> now on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.172:
+    Type: Log
+    Description: "Cold-Migrate-Revert cancelled for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.173:
+    Type: Log
+    Description: "Cold-Migrate-Revert failed for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.174:
+    Type: Log
+    Description: Cold-Migrate-Revert complete for instance <instance_name> now enabled on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.175:
+    Type: Log
+    Description: "Evacuate issued <by <tenant_name>|by the system>  against instance <instance_name> owned by <tenant_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.176:
+    Type: Log
+    Description: Evacuating instance <instance_name> owned by <tenant_name> from host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.177:
+    Type: Log
+    Description: "Evacuate rejected for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.178:
+    Type: Log
+    Description: "Evacuate cancelled for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.179:
+    Type: Log
+    Description: "Evacuate failed for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.180:
+    Type: Log
+    Description: Evacuate complete for instance <instance_name> now enabled on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.181:
+    Type: Log
+    Description: "Reboot <(soft-reboot)|(hard-reboot)> issued <by <tenant_name>|by the system|by the instance>  against instance <instance_name> owned by <tenant_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.182:
+    Type: Log
+    Description: Reboot inprogress for instance <instance_name> on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.183:
+    Type: Log
+    Description: "Reboot rejected for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.184:
+    Type: Log
+    Description: "Reboot cancelled for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.185:
+    Type: Log
+    Description: "Reboot failed for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.186:
+    Type: Log
+    Description: Reboot complete for instance <instance_name> now enabled on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.187:
+    Type: Log
+    Description: "Rebuild issued <by <tenant_name>|by the system> against instance <instance_name> using image <image_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.188:
+    Type: Log
+    Description: Rebuild inprogress for instance <instance_name> on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.189:
+    Type: Log
+    Description: "Rebuild rejected for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.190:
+    Type: Log
+    Description: "Rebuild cancelled for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.191:
+    Type: Log
+    Description: "Rebuild failed for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.192:
+    Type: Log
+    Description: Rebuild complete for instance <instance_name> now enabled on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.193:
+    Type: Log
+    Description: "Resize issued <by <tenant_name>|by the system>  against instance <instance_name> owned by <tenant_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.194:
+    Type: Log
+    Description: Resize inprogress for instance <instance_name> on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.195:
+    Type: Log
+    Description: "Resize rejected for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.196:
+    Type: Log
+    Description: "Resize cancelled for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.197:
+    Type: Log
+    Description: "Resize failed for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.198:
+    Type: Log
+    Description: Resize complete for instance <instance_name> enabled on host <host_name> waiting for confirmation
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.199:
+    Type: Log
+    Description: "Resize-Confirm issued <by <tenant_name>|by the system>  against instance <instance_name> owned by <tenant_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.200:
+    Type: Log
+    Description: Resize-Confirm inprogress for instance <instance_name> on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.201:
+    Type: Log
+    Description: "Resize-Confirm rejected for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.202:
+    Type: Log
+    Description: "Resize-Confirm cancelled for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.203:
+    Type: Log
+    Description: "Resize-Confirm failed for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.204:
+    Type: Log
+    Description: Resize-Confirm complete for instance <instance_name> enabled on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.205:
+    Type: Log
+    Description: "Resize-Revert issued <by <tenant_name>|by the system>  against instance <instance_name> owned by <tenant_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.206:
+    Type: Log
+    Description: Resize-Revert inprogress for instance <instance_name> on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.207:
+    Type: Log
+    Description: "Resize-Revert rejected for instance <instance_name> owned by <tenant_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.208:
+    Type: Log
+    Description: "Resize-Revert cancelled for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.209:
+    Type: Log
+    Description: "Resize-Revert failed for instance <instance_name> on host <host_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.210:
+    Type: Log
+    Description: Resize-Revert complete for instance <instance_name> enabled on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.211:
+    Type: Log
+    Description: Guest Heartbeat established for instance <instance_name> on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: major
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.212:
+    Type: Log
+    Description: Guest Heartbeat disconnected for instance <instance_name> on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: major
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.213:
+    Type: Log
+    Description: "Guest Heartbeat failed for instance <instance_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.214:
+    Type: Log
+    Description: Instance <instance_name> has been renamed to <new_instance_name> owned by <tenant_name> on host <host_name>
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.215:
+    Type: Log
+    Description: "Guest Health Check failed for instance <instance_name>[, reason = <reason_text>]"
+    Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+700.216:
+    Type: Log
+    Description: "Entered Multi-Node Recovery Mode"
+    Entity_Instance_ID: subsystem=vim
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+
+700.217:
+    Type: Log
+    Description: "Exited Multi-Node Recovery Mode"
+    Entity_Instance_ID: subsystem=vim
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+#---------------------------------------------------------------------------
+#   APPLICATION
+#---------------------------------------------------------------------------
+
+750.001:
+    Type: Alarm
+    Description: "Application Upload Failure"
+    Entity_Instance_ID: k8s_application=<appname>
+    Severity: warning
+    Proposed_Repair_Action: "Check system inventory log for cause."
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: processing-error
+    Probable_Cause: unknown
+    Service_Affecting: False
+    Suppression: True
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+750.002:
+    Type: Alarm
+    Description: "Application Apply Failure"
+    Entity_Instance_ID: k8s_application=<appname>
+    Severity: major
+    Proposed_Repair_Action: "Retry applying the application. Check application is managed by the system application framework.
+                             If the issue persists, please check system inventory log for cause."
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: processing-error
+    Probable_Cause: unknown
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+750.003:
+    Type: Alarm
+    Description: "Application Remove Failure"
+    Entity_Instance_ID: k8s_application=<appname>
+    Severity: major
+    Proposed_Repair_Action: "Retry removing the application. If the issue persists, please check system inventory log for cause."
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: processing-error
+    Probable_Cause: unknown
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+750.004:
+    Type: Alarm
+    Description: "Application Apply In Progress"
+    Entity_Instance_ID: k8s_application=<appname>
+    Severity: warning
+    Proposed_Repair_Action: "No action required."
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: other
+    Probable_Cause: unknown
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+750.005:
+    Type: Alarm
+    Description: "Application Update In Progress"
+    Entity_Instance_ID: k8s_application=<appname>
+    Severity: warning
+    Proposed_Repair_Action: "No action required."
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: other
+    Probable_Cause: unknown
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+750.006:
+    Type: Alarm
+    Description: "Automatic Application Re-Apply Is Pending"
+    Entity_Instance_ID: k8s_application=<appname>
+    Severity: warning
+    Proposed_Repair_Action: "Ensure all hosts are either locked or unlocked.  When the system is stable the application will be automatically reapplied."
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: other
+    Probable_Cause: unknown
+    Service_Affecting: False
+    Suppression: True
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+#---------------------------------------------------------------------------
+#   STORAGE
+#---------------------------------------------------------------------------
+
+800.001:
+    Type: Alarm
+    Description: |-
+        Storage Alarm Condition:
+        1 mons down, quorum 1,2 controller-1,storage-0
+    Entity_Instance_ID: cluster=<dist-fs-uuid>
+    Severity: [critical, major]
+    Proposed_Repair_Action: "If problem persists, contact next level of support."
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: equipment-malfunction
+    Service_Affecting:
+        critical: True
+        major: False
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+800.010:
+    Type: Alarm
+    Description: |-
+        Potential data loss. No available OSDs in storage replication group.
+    Entity_Instance_ID: cluster=<dist-fs-uuid>.peergroup=<group-x>
+    Severity: [critical]
+    Proposed_Repair_Action: "Ensure storage hosts from replication group are unlocked and available.
+                             Check if OSDs of each storage host are up and running.
+                             If problem persists contact next level of support."
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: equipment-malfunction
+    Service_Affecting:
+        critical: True
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+800.011:
+    Type: Alarm
+    Description: |-
+        Loss of replication in peergroup.
+    Entity_Instance_ID: cluster=<dist-fs-uuid>.peergroup=<group-x>
+    Severity: [major]
+    Proposed_Repair_Action: "Ensure storage hosts from replication group are unlocked and available.
+                             Check if OSDs of each storage host are up and running.
+                             If problem persists contact next level of support."
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: equipment-malfunction
+    Service_Affecting:
+        major: True
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+800.002:
+    Type: Alarm
+    Description: ["Image storage media is full: There is not enough disk space on the image storage media.",
+                  "Instance <instance name> snapshot failed: There is not enough disk space on the image storage media.",
+                  "Supplied <attrs> (<supplied>) and <attrs> generated from uploaded image (<actual>) did not match. Setting image status to 'killed'.",
+                  "Error in store configuration. Adding images to store is disabled.",
+                  "Forbidden upload attempt: <exception>",
+                  "Insufficient permissions on image storage media: <exception>",
+                  "Denying attempt to upload image larger than <size> bytes.",
+                  "Denying attempt to upload image because it exceeds the quota: <exception>",
+                  "Received HTTP error while uploading image <image_id>",
+                  "Client disconnected before sending all data to backend",
+                  "Failed to upload image <image_id>"]
+    Entity_Instance_ID: ["image=<image-uuid>, instance=<instance-uuid>",
+                         "tenant=<tenant-uuid>, instance=<instance-uuid>",
+                         "image=<image-uuid>, instance=<instance-uuid>",
+                         "image=<image-uuid>, instance=<instance-uuid>",
+                         "image=<image-uuid>, instance=<instance-uuid>",
+                         "image=<image-uuid>, instance=<instance-uuid>",
+                         "image=<image-uuid>, instance=<instance-uuid>",
+                         "image=<image-uuid>, instance=<instance-uuid>",
+                         "image=<image-uuid>, instance=<instance-uuid>",
+                         "image=<image-uuid>, instance=<instance-uuid>",
+                         "image=<image-uuid>, instance=<instance-uuid>"]
+    Alarm_Type: [physical-violation,
+                 physical-violation,
+                 integrity-violation,
+                 integrity-violation,
+                 security-service-or-mechanism-violation,
+                 security-service-or-mechanism-violation,
+                 security-service-or-mechanism-violation,
+                 security-service-or-mechanism-violation,
+                 communication,
+                 communication,
+                 operational-violation]
+    Severity: warning
+    Proposed_Repair_Action:
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+800.100:
+    Type: Alarm
+    Description: |-
+        Storage Alarm Condition:
+        Cinder I/O Congestion is above normal range and is building
+    Entity_Instance_ID: cinder_io_monitor
+    Severity: major
+    Proposed_Repair_Action: "Reduce the I/O load on the Cinder LVM backend. Use
+                             Cinder QoS mechanisms on high usage volumes."
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: qos
+    Probable_Cause: congestion
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+800.101:
+    Type: Alarm
+    Description: |-
+        Storage Alarm Condition:
+        Cinder I/O Congestion is high and impacting guest performance
+    Entity_Instance_ID: cinder_io_monitor
+    Severity: critical
+    Proposed_Repair_Action: "Reduce the I/O load on the Cinder LVM backend.
+                             Cinder actions may fail until congestion is reduced.
+                             Use Cinder QoS mechanisms on high usage volumes."
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: qos
+    Probable_Cause: congestion
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+800.103:
+    Type: Alarm
+    Description: |-
+        Storage Alarm Condition:
+        [ Metadata usage for LVM thin pool <VG name>/<Pool name> exceeded threshold and automatic extension failed,
+          Metadata usage for LVM thin pool <VG name>/<Pool name> exceeded threshold ]; threshold x%, actual y%.
+    Entity_Instance_ID: <hostname>.lvmthinpool=<VG name>/<Pool name>
+    Severity: critical
+    Proposed_Repair_Action: "Increase Storage Space Allotment for Cinder on the 'lvm' backend.
+                             Consult the System Administration Manual for more details.
+                             If problem persists, contact next level of support."
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: threshold-crossed
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: major
+    Degrade_Affecting_Severity: none
+
+800.104:
+    Type: Alarm
+    Description: |-
+        Storage Alarm Condition:
+        <storage-backend-name> configuration failed to apply on host: <host-uuid>.
+    Entity_Instance_ID: storage_backend=<storage-backend-name>
+    Severity: critical
+    Proposed_Repair_Action: "Update backend setting to reapply configuration.
+                             Consult the System Administration Manual for more details.
+                             If problem persists, contact next level of support."
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: configuration-or-customization-error
+    Service_Affecting: True
+    Suppression: False
+    Management_Affecting_Severity: major
+    Degrade_Affecting_Severity: none
+
+#---------------------------------------------------------------------------
+#   KUBERNETES
+#---------------------------------------------------------------------------
+
+850.001:
+    Type: Alarm
+    Description: Persistent Volume Migration Error
+    Entity_Instance_ID: kubernetes=PV-migration-failed
+    Severity: major
+    Proposed_Repair_Action: "Manually execute /usr/bin/ceph_k8s_update_monitors.sh
+                             to confirm PVs are updated, then lock/unlock to clear
+                             alarms. If problem persists, contact next level of
+                             support."
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: processing-error
+    Probable_Cause: communication-subsystem-failure
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: none
+    Degrade_Affecting_Severity: none
+
+#---------------------------------------------------------------------------
+#   SOFTWARE
+#---------------------------------------------------------------------------
+
+900.001:
+    Type: Alarm
+    Description: Patching operation in progress.
+    Entity_Instance_ID: host=controller
+    Severity: minor
+    Proposed_Repair_Action: Complete reboots of affected hosts.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: environmental
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.002:
+    Type: Alarm
+    Description: Patch host install failure. Command "sw-patch host-install" failed.
+    Entity_Instance_ID: host=<hostname>
+    Severity: major
+    Proposed_Repair_Action: Undo patching operation. Check patch logs on the target host (i.e. /var/log/patching.log)
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: environmental
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.003:
+    Type: Alarm
+    Description: A patch with state 'obsolete' in its metadata has been uploaded.
+    Entity_Instance_ID: host=controller
+    Severity: warning
+    Proposed_Repair_Action: Remove and delete obsolete patches.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: environmental
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.004:
+    Type: Alarm
+    Description: The upgrade and running software version do not match. Command host-upgrade failed.
+    Entity_Instance_ID: host=<hostname>
+    Severity: major
+    Proposed_Repair_Action: Reinstall host to update applied load.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.005:
+    Type: Alarm
+    Description: System Upgrade in progress.
+    Entity_Instance_ID: host=controller
+    Severity: minor
+    Proposed_Repair_Action: No action required.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.006:
+    Type: Alarm
+    Description: Device image update operation in progress.
+    Entity_Instance_ID: host=controller
+    Severity: minor
+    Proposed_Repair_Action: Complete reboots of affected hosts.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: environmental
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.007:
+    Type: Alarm
+    Description: Kubernetes upgrade in progress.
+    Entity_Instance_ID: host=controller
+    Severity: minor
+    Proposed_Repair_Action: No action required.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.008:
+    Type: Alarm
+    Description: Kubernetes rootca update in progress
+    Entity_Instance_ID: host=controller
+    Severity: minor
+    Proposed_Repair_Action: Wait for kubernetes rootca procedure to complete
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.009:
+    Type: Alarm
+    Description: Kubernetes root CA update aborted, certificates may not be fully updated. Command "system kube-rootca-update-abort" has been run.
+    Entity_Instance_ID: host=controller
+    Severity: minor
+    Proposed_Repair_Action: Fully update certificates by a new root CA update.
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: operational-violation
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+    Suppression: False
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.101:
+    Type: Alarm
+    Description: Software patch auto-apply inprogress
+    Entity_Instance_ID: orchestration=sw-patch
+    Severity: major
+    Proposed_Repair_Action: Wait for software patch auto-apply to complete; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.102:
+    Type: Alarm
+    Description: Software patch auto-apply aborting
+    Entity_Instance_ID: orchestration=sw-patch
+    Severity: major
+    Proposed_Repair_Action: Wait for software patch auto-apply abort to complete; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.103:
+    Type: Alarm
+    Description: Software patch auto-apply failed. Command "sw-manager patch-strategy apply" failed.
+    Entity_Instance_ID: orchestration=sw-patch
+    Severity: critical
+    Proposed_Repair_Action: Attempt to apply software patches manually; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: underlying-resource-unavailable
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.111:
+    Type: Log
+    Description: Software patch auto-apply start
+    Entity_Instance_ID: orchestration=sw-patch
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.112:
+    Type: Log
+    Description: Software patch auto-apply inprogress
+    Entity_Instance_ID: orchestration=sw-patch
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.113:
+    Type: Log
+    Description: Software patch auto-apply rejected
+    Entity_Instance_ID: orchestration=sw-patch
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.114:
+    Type: Log
+    Description: Software patch auto-apply cancelled
+    Entity_Instance_ID: orchestration=sw-patch
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.115:
+    Type: Log
+    Description: Software patch auto-apply failed
+    Entity_Instance_ID: orchestration=sw-patch
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.116:
+    Type: Log
+    Description: Software patch auto-apply completed
+    Entity_Instance_ID: orchestration=sw-patch
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.117:
+    Type: Log
+    Description: Software patch auto-apply abort
+    Entity_Instance_ID: orchestration=sw-patch
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.118:
+    Type: Log
+    Description: Software patch auto-apply aborting
+    Entity_Instance_ID: orchestration=sw-patch
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.119:
+    Type: Log
+    Description: Software patch auto-apply abort rejected
+    Entity_Instance_ID: orchestration=sw-patch
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.120:
+    Type: Log
+    Description: Software patch auto-apply abort failed
+    Entity_Instance_ID: orchestration=sw-patch
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.121:
+    Type: Log
+    Description: Software patch auto-apply aborted
+    Entity_Instance_ID: orchestration=sw-patch
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.201:
+    Type: Alarm
+    Description: Software upgrade auto-apply inprogress
+    Entity_Instance_ID: orchestration=sw-upgrade
+    Severity: major
+    Proposed_Repair_Action: Wait for software upgrade auto-apply to complete; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.202:
+    Type: Alarm
+    Description: Software upgrade auto-apply aborting
+    Entity_Instance_ID: orchestration=sw-upgrade
+    Severity: major
+    Proposed_Repair_Action: Wait for software upgrade auto-apply abort to complete; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.203:
+    Type: Alarm
+    Description: Software upgrade auto-apply failed. Command "sw-manager update-strategy apply" failed
+    Entity_Instance_ID: orchestration=sw-upgrade
+    Severity: critical
+    Proposed_Repair_Action: Attempt to apply software upgrade manually; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: underlying-resource-unavailable
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.211:
+    Type: Log
+    Description: Software upgrade auto-apply start
+    Entity_Instance_ID: orchestration=sw-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.212:
+    Type: Log
+    Description: Software upgrade auto-apply inprogress
+    Entity_Instance_ID: orchestration=sw-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.213:
+    Type: Log
+    Description: Software upgrade auto-apply rejected
+    Entity_Instance_ID: orchestration=sw-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.214:
+    Type: Log
+    Description: Software upgrade auto-apply cancelled
+    Entity_Instance_ID: orchestration=sw-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.215:
+    Type: Log
+    Description: Software upgrade auto-apply failed
+    Entity_Instance_ID: orchestration=sw-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.216:
+    Type: Log
+    Description: Software upgrade auto-apply completed
+    Entity_Instance_ID: orchestration=sw-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.217:
+    Type: Log
+    Description: Software upgrade auto-apply abort
+    Entity_Instance_ID: orchestration=sw-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.218:
+    Type: Log
+    Description: Software upgrade auto-apply aborting
+    Entity_Instance_ID: orchestration=sw-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.219:
+    Type: Log
+    Description: Software upgrade auto-apply abort rejected
+    Entity_Instance_ID: orchestration=sw-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.220:
+    Type: Log
+    Description: Software upgrade auto-apply abort failed
+    Entity_Instance_ID: orchestration=sw-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.221:
+    Type: Log
+    Description: Software upgrade auto-apply aborted
+    Entity_Instance_ID: orchestration=sw-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.301:
+    Type: Alarm
+    Description: Firmware Update auto-apply inprogress
+    Entity_Instance_ID: orchestration=fw-update
+    Severity: major
+    Proposed_Repair_Action: Wait for firmware update auto-apply to complete; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.302:
+    Type: Alarm
+    Description: Firmware Update auto-apply aborting
+    Entity_Instance_ID: orchestration=fw-update
+    Severity: major
+    Proposed_Repair_Action: Wait for firmware update auto-apply abort to complete; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.303:
+    Type: Alarm
+    Description: Firmware Update auto-apply failed. Command "sw-manager kube-rootca-update-strategy apply" failed.
+    Entity_Instance_ID: orchestration=fw-update
+    Severity: critical
+    Proposed_Repair_Action: Attempt to apply firmware update manually; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: underlying-resource-unavailable
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.311:
+    Type: Log
+    Description: Firmware update auto-apply start
+    Entity_Instance_ID: orchestration=fw-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.312:
+    Type: Log
+    Description: Firmware update auto-apply inprogress
+    Entity_Instance_ID: orchestration=fw-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.313:
+    Type: Log
+    Description: Firmware update auto-apply rejected
+    Entity_Instance_ID: orchestration=fw-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.314:
+    Type: Log
+    Description: Firmware update auto-apply cancelled
+    Entity_Instance_ID: orchestration=fw-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.315:
+    Type: Log
+    Description: Firmware update auto-apply failed
+    Entity_Instance_ID: orchestration=fw-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.316:
+    Type: Log
+    Description: Firmware update auto-apply completed
+    Entity_Instance_ID: orchestration=fw-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.317:
+    Type: Log
+    Description: Firmware update auto-apply abort
+    Entity_Instance_ID: orchestration=fw-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.318:
+    Type: Log
+    Description: Firmware update auto-apply aborting
+    Entity_Instance_ID: orchestration=fw-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.319:
+    Type: Log
+    Description: Firmware update auto-apply abort rejected
+    Entity_Instance_ID: orchestration=fw-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.320:
+    Type: Log
+    Description: Firmware update auto-apply abort failed
+    Entity_Instance_ID: orchestration=fw-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.321:
+    Type: Log
+    Description: Firmware update auto-apply aborted
+    Entity_Instance_ID: orchestration=fw-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.401:
+    Type: Alarm
+    Description: Kubernetes upgrade auto-apply inprogress
+    Entity_Instance_ID: orchestration=kube-upgrade
+    Severity: major
+    Proposed_Repair_Action: Wait for kubernetes upgrade auto-apply to complete; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.402:
+    Type: Alarm
+    Description: Kubernetes upgrade auto-apply aborting
+    Entity_Instance_ID: orchestration=kube-upgrade
+    Severity: major
+    Proposed_Repair_Action: Wait for kubernetes upgrade auto-apply abort to complete; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.403:
+    Type: Alarm
+    Description: Kubernetes upgrade auto-apply failed
+    Entity_Instance_ID: orchestration=kube-upgrade
+    Severity: critical
+    Proposed_Repair_Action: Attempt to apply kubernetes upgrade manually; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: underlying-resource-unavailable
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.411:
+    Type: Log
+    Description: Kubernetes upgrade auto-apply start
+    Entity_Instance_ID: orchestration=kube-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.412:
+    Type: Log
+    Description: Kubernetes upgrade auto-apply inprogress
+    Entity_Instance_ID: orchestration=kube-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.413:
+    Type: Log
+    Description: Kubernetes upgrade auto-apply rejected
+    Entity_Instance_ID: orchestration=kube-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.414:
+    Type: Log
+    Description: Kubernetes upgrade auto-apply cancelled
+    Entity_Instance_ID: orchestration=kube-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.415:
+    Type: Log
+    Description: Kubernetes upgrade auto-apply failed
+    Entity_Instance_ID: orchestration=kube-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.416:
+    Type: Log
+    Description: Kubernetes upgrade auto-apply completed
+    Entity_Instance_ID: orchestration=kube-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.417:
+    Type: Log
+    Description: Kubernetes upgrade auto-apply abort
+    Entity_Instance_ID: orchestration=kube-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.418:
+    Type: Log
+    Description: Kubernetes upgrade auto-apply aborting
+    Entity_Instance_ID: orchestration=kube-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.419:
+    Type: Log
+    Description: Kubernetes upgrade auto-apply abort rejected
+    Entity_Instance_ID: orchestration=kube-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.420:
+    Type: Log
+    Description: Kubernetes upgrade auto-apply abort failed
+    Entity_Instance_ID: orchestration=kube-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.421:
+    Type: Log
+    Description: Kubernetes upgrade auto-apply aborted
+    Entity_Instance_ID: orchestration=kube-upgrade
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.501:
+    Type: Alarm
+    Description: Kubernetes rootca update auto-apply inprogress
+    Entity_Instance_ID: orchestration=kube-rootca-update
+    Severity: major
+    Proposed_Repair_Action: Wait for kubernetes rootca update auto-apply to complete; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.502:
+    Type: Alarm
+    Description: Kubernetes rootca update auto-apply aborting
+    Entity_Instance_ID: orchestration=kube-rootca-update
+    Severity: major
+    Proposed_Repair_Action: Wait for kubernetes rootca update auto-apply abort to complete; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.503:
+    Type: Alarm
+    Description: Kubernetes rootca update auto-apply failed. Command "sw-manager kube-upgrade-strategy apply" failed.
+    Entity_Instance_ID: orchestration=kube-rootca-update
+    Severity: critical
+    Proposed_Repair_Action: Attempt to apply kubernetes rootca update manually; if problem persists contact next level of support
+    Maintenance_Action:
+    Inhibit_Alarms:
+    Alarm_Type: equipment
+    Probable_Cause: underlying-resource-unavailable
+    Service_Affecting: True
+    Suppression: True
+    Management_Affecting_Severity: warning
+    Degrade_Affecting_Severity: none
+
+900.511:
+    Type: Log
+    Description: Kubernetes rootca update auto-apply start
+    Entity_Instance_ID: orchestration=kube-rootca-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.512:
+    Type: Log
+    Description: Kubernetes rootca update auto-apply inprogress
+    Entity_Instance_ID: orchestration=kube-rootca-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.513:
+    Type: Log
+    Description: Kubernetes rootca update auto-apply rejected
+    Entity_Instance_ID: orchestration=kube-rootca-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.514:
+    Type: Log
+    Description: Kubernetes rootca update auto-apply cancelled
+    Entity_Instance_ID: orchestration=kube-rootca-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.515:
+    Type: Log
+    Description: Kubernetes rootca update auto-apply failed
+    Entity_Instance_ID: orchestration=kube-rootca-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.516:
+    Type: Log
+    Description: Kubernetes rootca update auto-apply completed
+    Entity_Instance_ID: orchestration=kube-rootca-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.517:
+    Type: Log
+    Description: Kubernetes rootca update auto-apply abort
+    Entity_Instance_ID: orchestration=kube-rootca-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.518:
+    Type: Log
+    Description: Kubernetes rootca update auto-apply aborting
+    Entity_Instance_ID: orchestration=kube-rootca-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.519:
+    Type: Log
+    Description: Kubernetes rootca update auto-apply abort rejected
+    Entity_Instance_ID: orchestration=kube-rootca-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.520:
+    Type: Log
+    Description: Kubernetes rootca update auto-apply abort failed
+    Entity_Instance_ID: orchestration=kube-rootca-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+
+900.521:
+    Type: Log
+    Description: Kubernetes rootca update auto-apply aborted
+    Entity_Instance_ID: orchestration=kube-rootca-update
+    Severity: critical
+    Alarm_Type: equipment
+    Probable_Cause: unspecified-reason
+    Service_Affecting: False
+...
index 37b30d3..f046db5 100644 (file)
@@ -21,7 +21,7 @@ from sqlalchemy.orm.session import Session
 from o2common.config import config
 from o2common.service.unit_of_work import AbstractUnitOfWork
 
-from o2ims.adapter import ocloud_repository
+from o2ims.adapter import ocloud_repository, alarm_repository, alarm_loader
 from o2dms.adapter import dms_repository
 
 from o2common.helper import o2logging
@@ -67,6 +67,18 @@ class SqlAlchemyUnitOfWork(AbstractUnitOfWork):
             .NfDeploymentSqlAlchemyRepository(self.session)
         self.ocloudvresources = dms_repository\
             .NfOCloudVResourceSqlAlchemyRepository(self.session)
+        self.alarm_event_records = alarm_repository\
+            .AlarmEventRecordSqlAlchemyRepository(self.session)
+        self.alarm_definitions = alarm_repository\
+            .AlarmDefinitionSqlAlchemyRepository(self.session)
+        self.alarm_subscriptions = alarm_repository\
+            .AlarmSubscriptionSqlAlchemyRepository(self.session)
+        self.alarm_probable_causes = alarm_repository\
+            .AlarmProbableCauseSqlAlchemyRepository(self.session)
+
+        # config file
+        self.alarm_dictionaries = alarm_loader\
+            .AlarmDictionaryConfigFileRepository()
         return super().__enter__()
 
     def __exit__(self, *args):
@@ -111,3 +123,9 @@ class SqlAlchemyUnitOfWork(AbstractUnitOfWork):
         for entry in self.ocloudvresources.seen:
             while hasattr(entry, 'events') and len(entry.events) > 0:
                 yield entry.events.pop(0)
+        for entry in self.alarm_event_records.seen:
+            while hasattr(entry, 'events') and len(entry.events) > 0:
+                yield entry.events.pop(0)
+        for entry in self.alarm_subscriptions.seen:
+            while hasattr(entry, 'events') and len(entry.events) > 0:
+                yield entry.events.pop(0)
index 329d9e2..228b240 100644 (file)
@@ -21,6 +21,7 @@ from o2common.adapter.notifications import AbstractNotifications,\
 from o2common.adapter import redis_eventpublisher
 from o2common.service import unit_of_work
 from o2common.service import messagebus
+from o2common.config import config
 
 from o2app.service import handlers
 from o2app.adapter.unit_of_work import SqlAlchemyUnitOfWork
@@ -28,6 +29,9 @@ 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 o2ims.adapter.clients import alarm_dict_client
+
+
 from o2common.helper import o2logging
 logger = o2logging.get_logger(__name__)
 
index 55385c2..fff1201 100644 (file)
 from flask import Flask
 from flask_restx import Api
 
+
 from o2app import bootstrap
 from o2ims.views import configure_namespace as ims_route_configure_namespace
 from o2dms.api import configure_namespace as dms_route_configure_namespace
 
+from o2ims.adapter.clients.alarm_dict_client import load_alarm_definition
 
 # apibase = config.get_o2ims_api_base()
 app = Flask(__name__)
@@ -31,3 +33,5 @@ bus = bootstrap.bootstrap()
 
 ims_route_configure_namespace(api)
 dms_route_configure_namespace(api)
+
+load_alarm_definition(bus.uow)
index 5630174..04ef31c 100644 (file)
@@ -24,11 +24,13 @@ from o2ims.domain import commands as imscmd
 from o2common.helper import o2logging
 from o2ims.domain.subscription_obj import Message2SMO, NotificationEventEnum,\
     RegistrationMessage
+from o2ims.domain.alarm_obj import AlarmEvent2SMO
 logger = o2logging.get_logger(__name__)
 
 r = redis.Redis(**config.get_redis_host_and_port())
 
 apibase = config.get_o2ims_api_base()
+api_monitoring_base = config.get_o2ims_monitoring_api_base()
 
 
 def main():
@@ -39,16 +41,17 @@ def main():
     pubsub.subscribe('ResourceChanged')
     pubsub.subscribe('ConfigurationChanged')
     pubsub.subscribe('OcloudChanged')
+    pubsub.subscribe('AlarmEventChanged')
 
     for m in pubsub.listen():
         try:
-            handle_dms_changed(m, bus)
+            handle_changed(m, bus)
         except Exception as ex:
             logger.warning("{}".format(str(ex)))
             continue
 
 
-def handle_dms_changed(m, bus):
+def handle_changed(m, bus):
     logger.info("handling %s", m)
     channel = m['channel'].decode("UTF-8")
     if channel == "NfDeploymentStateChanged":
@@ -85,6 +88,16 @@ def handle_dms_changed(m, bus):
         if data['notificationEventType'] == NotificationEventEnum.CREATE:
             cmd = imscmd.Register2SMO(data=RegistrationMessage(is_all=True))
             bus.handle(cmd)
+    elif channel == 'AlarmEventChanged':
+        datastr = m['data']
+        data = json.loads(datastr)
+        logger.info('AlarmEventChanged with cmd:{}'.format(data))
+        ref = api_monitoring_base + '/alarms/' + data['id']
+        cmd = imscmd.PubAlarm2SMO(data=AlarmEvent2SMO(
+            id=data['id'], ref=ref,
+            eventtype=data['notificationEventType'],
+            updatetime=data['updatetime']))
+        bus.handle(cmd)
     else:
         logger.info("unhandled:{}".format(channel))
 
index 98145dc..99d5595 100644 (file)
@@ -21,9 +21,12 @@ from o2common.service.watcher.worker import PollWorker
 from o2ims.service.watcher.ocloud_watcher import OcloudWatcher
 from o2ims.service.watcher.ocloud_watcher import DmsWatcher
 from o2ims.service.watcher.resourcepool_watcher import ResourcePoolWatcher
+from o2ims.service.watcher.alarm_watcher import AlarmWatcher
+
 from o2ims.adapter.clients.ocloud_client import StxDmsClient
 from o2ims.adapter.clients.ocloud_client import StxOcloudClient
 from o2ims.adapter.clients.ocloud_client import StxResourcePoolClient
+from o2ims.adapter.clients.fault_client import StxAlarmClient
 
 from o2ims.service.watcher.pserver_watcher import PServerWatcher
 from o2ims.adapter.clients.ocloud_client import StxPserverClient
@@ -62,6 +65,8 @@ class WatcherService(cotyledon.Service):
                 StxOcloudClient(), self.bus))
             root.addchild(
                 DmsWatcher(StxDmsClient(), self.bus))
+            # root.addchild(
+            #     AlarmWatcher(StxFaultClient(), self.bus))
 
             child_respool = root.addchild(
                 ResourcePoolWatcher(StxResourcePoolClient(),
@@ -81,6 +86,11 @@ class WatcherService(cotyledon.Service):
 
             self.worker.add_watcher(root)
 
+            # Add Alarm watch
+            root = WatcherTree(
+                AlarmWatcher(StxAlarmClient(self.bus.uow), self.bus))
+            self.worker.add_watcher(root)
+
             self.worker.start()
         except Exception as ex:
             logger.warning("WorkerService Exception:" + str(ex))
index 9e88ff8..d630720 100644 (file)
@@ -26,10 +26,11 @@ from o2dms.domain import events as o2dms_events
 from o2ims.service.auditor import ocloud_handler, dms_handler, \
     resourcepool_handler, pserver_handler, pserver_cpu_handler, \
     pserver_mem_handler, pserver_port_handler, pserver_if_handler,\
-    pserver_eth_handler
-from o2ims.service.command import notify_handler, registration_handler
+    pserver_eth_handler, alarm_handler
+from o2ims.service.command import notify_handler, registration_handler,\
+    notify_alarm_handler
 from o2ims.service.event import ocloud_event, resource_event, \
-    resource_pool_event, configuration_event
+    resource_pool_event, configuration_event, alarm_event
 
 # if TYPE_CHECKING:
 #     from . import unit_of_work
@@ -57,12 +58,15 @@ EVENT_HANDLERS = {
                                  notify_resourcepool_change],
     events.ConfigurationChanged: [configuration_event.\
                                   notify_configuration_change],
+    events.AlarmEventChanged: [alarm_event.\
+                               notify_alarm_event_change],
 }  # type: Dict[Type[events.Event], Callable]
 
 
 COMMAND_HANDLERS = {
     commands.UpdateOCloud: ocloud_handler.update_ocloud,
     commands.UpdateDms: dms_handler.update_dms,
+    commands.UpdateAlarm: alarm_handler.update_alarm,
     commands.UpdateResourcePool: resourcepool_handler.update_resourcepool,
     commands.UpdatePserver: pserver_handler.update_pserver,
     commands.UpdatePserverCpu: pserver_cpu_handler.update_pserver_cpu,
@@ -79,5 +83,6 @@ COMMAND_HANDLERS = {
     o2dms_cmmands.DeleteNfDeployment:
     nfdeployment_handler.delete_nfdeployment,
     commands.PubMessage2SMO: notify_handler.notify_change_to_smo,
+    commands.PubAlarm2SMO: notify_alarm_handler.notify_alarm_to_smo,
     commands.Register2SMO: registration_handler.registry_to_smo,
 }  # type: Dict[Type[commands.Command], Callable]
index 6e5d19f..e42c886 100644 (file)
@@ -50,7 +50,11 @@ def get_root_api_base():
 
 
 def get_o2ims_api_base():
-    return get_root_api_base() + 'o2ims_infrastructureInventory/v1'
+    return get_root_api_base() + 'o2ims-infrastructureInventory/v1'
+
+
+def get_o2ims_monitoring_api_base():
+    return get_root_api_base() + 'o2ims-infrastructureMonitoring/v1'
 
 
 def get_provision_api_base():
@@ -150,6 +154,36 @@ def get_dc_access_info():
     return os_client_args
 
 
+def get_fm_access_info():
+    try:
+        client_args = dict(
+            auth_url=os.environ.get('OS_AUTH_URL', _DEFAULT_STX_URL),
+            username=os.environ.get('OS_USERNAME', "admin"),
+            api_key=os.environ.get('OS_PASSWORD', "fakepasswd1"),
+            project_name=os.environ.get('OS_PROJECT_NAME', "admin"),
+        )
+    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
+    auth_url = urlparse(os_client_args.pop('os_auth_url'))
+
+    os_client_args['insecure'] = True
+
+    os_client_args['auth_url'] = auth_url.geturl()
+    os_client_args['username'] = os_client_args.pop('os_username')
+    os_client_args['password'] = os_client_args.pop('os_api_key')
+    os_client_args['project_name'] = os_client_args.pop('os_project_name')
+    os_client_args['user_domain_name'] = 'Default'
+    os_client_args['project_domain_name'] = 'Default'
+
+    return os_client_args
+
+
 def get_k8s_api_endpoint():
     K8S_KUBECONFIG = os.environ.get("K8S_KUBECONFIG", None)
     K8S_APISERVER = os.environ.get("K8S_APISERVER", None)
@@ -221,3 +255,17 @@ def get_helmcli_access():
     helm_pass = os.environ.get("HELM_USER_PASSWD")
 
     return helm_host_with_port, helm_user, helm_pass
+
+
+def get_alarm_yaml_filename():
+    alarm_yaml_name = os.environ.get("ALARM_YAML")
+    if alarm_yaml_name is not None and os.path.isfile(alarm_yaml_name):
+        return alarm_yaml_name
+    return "/configs/alarm.yaml"
+
+
+def get_events_yaml_filename():
+    events_yaml_name = os.environ.get("EVENTS_YAML")
+    if events_yaml_name is not None and os.path.isfile(events_yaml_name):
+        return events_yaml_name
+    return "/configs/events.yaml"
index a7d025e..0fc7853 100644 (file)
@@ -43,7 +43,8 @@ class BaseWatcher(object):
             # return self._probe(parent)
             return cmds
         except Exception as ex:
-            logger.warning("Failed to probe resource due to: " + str(ex))
+            logger.warning("Failed to probe %s watcher due to: %s - %s" %
+                           (self._targetname(), type(ex), str(ex)))
             return []
 
     def _probe(self, parent: object = None, tags: object = None) \
index 3eef230..d47fb27 100644 (file)
@@ -48,7 +48,8 @@ class PollWorker(object):
                 # logger.debug("about to probe:"+w)
                 w.probe(None)
             except Exception as ex:
-                logger.warning("Worker raises exception:" + str(ex))
+                logger.warning("Worker raises exception %s: %s -  %s "
+                               % (w, type(ex), str(ex)))
                 continue
 
         # handle events
diff --git a/o2ims/adapter/alarm_loader.py b/o2ims/adapter/alarm_loader.py
new file mode 100644 (file)
index 0000000..823d0d5
--- /dev/null
@@ -0,0 +1,42 @@
+# 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.
+
+from typing import List
+
+from o2ims.domain import alarm_obj
+from o2ims.domain.alarm_repo import AlarmDictionaryRepository
+from o2common.helper import o2logging
+logger = o2logging.get_logger(__name__)
+
+
+class AlarmDictionaryConfigFileRepository(AlarmDictionaryRepository):
+    def __init__(self):
+        super().__init__()
+        self.dictionary = {}
+
+    def _add(self, alarm_dict: alarm_obj.AlarmDictionary):
+        self.dictionary[alarm_dict.entityType] = alarm_dict
+
+    def _get(self, alarm_entity_type) -> alarm_obj.AlarmDictionary:
+        return self.dictionary[alarm_entity_type]
+
+    def _list(self) -> List[alarm_obj.AlarmDictionary]:
+        return [alarm_dict for alarm_dict in self.dictionary.items()]
+
+    def _update(self, alarm_dict: alarm_obj.AlarmDictionary):
+        self.dictionary[alarm_dict.entityType] = alarm_dict
+
+    def _delete(self, alarm_entity_type):
+        if alarm_entity_type in self.dictionary.keys():
+            del self.dictionary[alarm_entity_type]
diff --git a/o2ims/adapter/alarm_repository.py b/o2ims/adapter/alarm_repository.py
new file mode 100644 (file)
index 0000000..ef20e6a
--- /dev/null
@@ -0,0 +1,114 @@
+# 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.
+
+from typing import List
+
+from o2ims.domain import alarm_obj
+from o2ims.domain.alarm_repo import AlarmDefinitionRepository, \
+    AlarmEventRecordRepository, AlarmSubscriptionRepository, \
+    AlarmProbableCauseRepository
+from o2common.helper import o2logging
+logger = o2logging.get_logger(__name__)
+
+
+class AlarmEventRecordSqlAlchemyRepository(AlarmEventRecordRepository):
+    def __init__(self, session):
+        super().__init__()
+        self.session = session
+
+    def _add(self, alarm_event_record: alarm_obj.AlarmEventRecord):
+        self.session.add(alarm_event_record)
+
+    def _get(self, alarm_event_record_id) -> alarm_obj.AlarmEventRecord:
+        return self.session.query(alarm_obj.AlarmEventRecord).filter_by(
+            alarmEventRecordId=alarm_event_record_id).first()
+
+    def _list(self) -> List[alarm_obj.AlarmEventRecord]:
+        return self.session.query(alarm_obj.AlarmEventRecord)
+
+    def _update(self, alarm_event_record: alarm_obj.AlarmEventRecord):
+        self.session.add(alarm_event_record)
+
+    def _delete(self, alarm_event_record_id):
+        self.session.query(alarm_obj.AlarmEventRecord).filter_by(
+            alarmEventRecordId=alarm_event_record_id).delete()
+
+
+class AlarmDefinitionSqlAlchemyRepository(AlarmDefinitionRepository):
+    def __init__(self, session):
+        super().__init__()
+        self.session = session
+
+    def _add(self, definition: alarm_obj.AlarmDefinition):
+        self.session.add(definition)
+
+    def _get(self, definition_id) -> alarm_obj.AlarmDefinition:
+        return self.session.query(alarm_obj.AlarmDefinition).filter_by(
+            alarmDefinitionId=definition_id).first()
+
+    def _list(self) -> List[alarm_obj.AlarmDefinition]:
+        return self.session.query(alarm_obj.AlarmDefinition)
+
+    def _update(self, definition: alarm_obj.AlarmDefinition):
+        self.session.add(definition)
+
+    def _delete(self, alarm_definition_id):
+        self.session.query(alarm_obj.AlarmDefinition).filter_by(
+            alarmDefinitionId=alarm_definition_id).delete()
+
+
+class AlarmSubscriptionSqlAlchemyRepository(AlarmSubscriptionRepository):
+    def __init__(self, session):
+        super().__init__()
+        self.session = session
+
+    def _add(self, subscription: alarm_obj.AlarmSubscription):
+        self.session.add(subscription)
+
+    def _get(self, subscription_id) -> alarm_obj.AlarmSubscription:
+        return self.session.query(alarm_obj.AlarmSubscription).filter_by(
+            alarmSubscriptionId=subscription_id).first()
+
+    def _list(self) -> List[alarm_obj.AlarmSubscription]:
+        return self.session.query(alarm_obj.AlarmSubscription)
+
+    def _update(self, subscription: alarm_obj.AlarmSubscription):
+        self.session.add(subscription)
+
+    def _delete(self, alarm_subscription_id):
+        self.session.query(alarm_obj.AlarmSubscription).filter_by(
+            alarmSubscriptionId=alarm_subscription_id).delete()
+
+
+class AlarmProbableCauseSqlAlchemyRepository(AlarmProbableCauseRepository):
+    def __init__(self, session):
+        super().__init__()
+        self.session = session
+
+    def _add(self, probable_cause: alarm_obj.ProbableCause):
+        self.session.add(probable_cause)
+
+    def _get(self, probable_cause_id) -> alarm_obj.ProbableCause:
+        return self.session.query(alarm_obj.ProbableCause).filter_by(
+            probableCauseId=probable_cause_id).first()
+
+    def _list(self) -> List[alarm_obj.ProbableCause]:
+        return self.session.query(alarm_obj.ProbableCause)
+
+    def _update(self, probable_cause: alarm_obj.ProbableCause):
+        self.session.add(probable_cause)
+
+    def _delete(self, probable_cause_id):
+        self.session.query(alarm_obj.ProbableCause).filter_by(
+            probableCauseId=probable_cause_id).delete()
diff --git a/o2ims/adapter/clients/alarm_dict_client.py b/o2ims/adapter/clients/alarm_dict_client.py
new file mode 100644 (file)
index 0000000..e15531a
--- /dev/null
@@ -0,0 +1,161 @@
+# 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.
+
+import os
+import json
+import yaml
+import errno
+import collections
+import uuid as uuid_gen
+
+from o2common.service import unit_of_work
+from o2common.config import config
+from o2ims.domain import alarm_obj as alarm
+
+from o2common.helper import o2logging
+logger = o2logging.get_logger(__name__)
+
+
+def load_alarm_dictionary_from_conf_file(conf_path: str,
+                                         uow: unit_of_work.AbstractUnitOfWork):
+
+    logger.info("Converting alarm.yaml to dict: ")
+
+    if not os.path.isfile(conf_path):
+        logger.error("file %s doesn't exist. Ending execution" %
+                     (conf_path))
+        raise OSError(
+            errno.ENOENT, os.strerror(errno.ENOENT), conf_path
+        )
+
+    try:
+        with open(conf_path, 'r') as stream:
+            alarm_yaml = yaml.load(stream, Loader=yaml.FullLoader)
+            dictionaries = alarm_yaml.get('dictionary')
+    except Exception as exp:
+        logger.error(exp)
+        raise RuntimeError(exp)
+
+    for dictionary in list(dictionaries.keys()):
+        with uow:
+            # res_type = uow.resource_types.get_by_name(dictionary)
+            # logger.info('res_type: ' + res_type.resourceTypeName)
+            alarm_dict = alarm.AlarmDictionary(dictionary)
+            alarm_dict.entityType = dictionary
+            alarm_dict.alarmDictionaryVersion = \
+                dictionaries[dictionary]['version']
+            alarm_dict.alarmDefinition = \
+                dictionaries[dictionary]['alarmDefinition']
+            uow.alarm_dictionaries.add(alarm_dict)
+
+
+def prettyDict(dict):
+    output = json.dumps(dict, sort_keys=True, indent=4)
+    return output
+
+
+def load_alarm_definition(uow: unit_of_work.AbstractUnitOfWork):
+    logger.info("Converting events.yaml to dict: ")
+    EVENT_TYPES_FILE = config.get_events_yaml_filename()
+
+    if not os.path.isfile(EVENT_TYPES_FILE):
+        logger.error("file %s doesn't exist. Ending execution" %
+                     (EVENT_TYPES_FILE))
+        raise OSError(
+            errno.ENOENT, os.strerror(errno.ENOENT), EVENT_TYPES_FILE
+        )
+
+    try:
+        with open(EVENT_TYPES_FILE, 'r') as stream:
+            event_types = yaml.load(stream, Loader=yaml.FullLoader)
+    except Exception as exp:
+        logger.error(exp)
+        raise RuntimeError(exp)
+
+    for alarm_id in list(event_types.keys()):
+        if isinstance(alarm_id, float):
+            # force 3 digits after the decimal point,
+            # to include trailing zero's (ex.: 200.010)
+            formatted_alarm_id = "{:.3f}".format(alarm_id)
+            event_types[formatted_alarm_id] = event_types.pop(alarm_id)
+
+    event_types = collections.OrderedDict(sorted(event_types.items()))
+
+    yaml_event_list = []
+    uneditable_descriptions = {'100.114', '200.007',
+                               '200.02', '200.021', '200.022', '800.002'}
+
+    # Parse events.yaml dict, and add any new alarm to definition table:
+    logger.info(
+        "Parsing events.yaml and adding any new alarm to definition table: ")
+    for event_type in event_types:
+
+        if event_types.get(event_type).get('Type') == "Alarm":
+            event_uuid = str(uuid_gen.uuid3(
+                uuid_gen.NAMESPACE_URL, str(event_type)))
+
+            string_event_type = str(event_type)
+
+            yaml_event_list.append(string_event_type)
+
+            if str(event_type) not in uneditable_descriptions:
+                event_description = (event_types.get(event_type)
+                                     .get('Description'))
+            else:
+                event_description = event_types.get(
+                    event_type).get('Description')
+
+            event_description = str(event_description)
+            event_description = (event_description[:250] + ' ...') \
+                if len(event_description) > 250 else event_description
+            prop_action = event_types.get(
+                event_type).get("Proposed_Repair_Action")
+
+            with uow:
+                alarm_def = uow.alarm_definitions.get(event_uuid)
+                event_mgmt_affecting = str(event_types.get(event_type).get(
+                    'Management_Affecting_Severity', 'warning'))
+#
+                event_degrade_affecting = str(event_types.get(event_type).get(
+                    'Degrade_Affecting_Severity', 'none'))
+
+                if alarm_def:
+                    alarm_def.description = event_description
+                    alarm_def.mgmt_affecting = event_mgmt_affecting
+                    alarm_def.degrade_affecting = event_degrade_affecting
+                else:
+                    alarm_def = alarm.AlarmDefinition(
+                        id=event_uuid,
+                        name=str(event_type),
+                        last_change=alarm.AlarmLastChangeEnum.ADDED,
+                        desc=event_description, prop_action=prop_action,
+                        clearing_type=alarm.ClearingTypeEnum.MANUAL,
+                        pk_noti_field=""
+                    )
+                    logger.info(str(event_type))
+                    uow.alarm_definitions.add(alarm_def)
+
+                uow.commit()
+
+            prob_cause = event_types.get(event_type).get("Probable_Cause")
+            prob_cause_uuid = str(uuid_gen.uuid3(
+                uuid_gen.NAMESPACE_URL, prob_cause))
+
+            with uow:
+                probable_cause = uow.alarm_probable_causes.get(prob_cause_uuid)
+                if probable_cause is None:
+                    pc = alarm.ProbableCause(
+                        prob_cause_uuid, prob_cause, prob_cause)
+                    uow.alarm_probable_causes.add(pc)
+                    uow.commit()
diff --git a/o2ims/adapter/clients/fault_client.py b/o2ims/adapter/clients/fault_client.py
new file mode 100644 (file)
index 0000000..b37a4d2
--- /dev/null
@@ -0,0 +1,191 @@
+# 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.
+
+# client talking to Stx standalone
+
+from typing import List  # Optional,  Set
+import uuid as uuid
+
+# from dcmanagerclient.api import client
+# from cgtsclient.client import get_client as get_stx_client
+# from cgtsclient.exc import EndpointException
+# from dcmanagerclient.api.client import client as get_dc_client
+from fmclient.client import get_client as get_fm_client
+from fmclient.common.exceptions import HTTPNotFound
+
+from o2common.service.client.base_client import BaseClient
+from o2common.config import config
+from o2ims.domain import alarm_obj as alarmModel
+from o2ims.domain.resource_type import ResourceTypeEnum
+from o2app.adapter import unit_of_work
+
+from o2common.helper import o2logging
+logger = o2logging.get_logger(__name__)
+
+
+CGTSCLIENT_ENDPOINT_ERROR_MSG = \
+    'Must provide Keystone credentials or user-defined endpoint and token'
+
+
+class StxAlarmClient(BaseClient):
+    def __init__(self, uow: unit_of_work.AbstractUnitOfWork, driver=None):
+        super().__init__()
+        self.driver = driver if driver else StxFaultClientImp()
+        self.uow = uow
+
+    def _get(self, id) -> alarmModel.FaultGenericModel:
+        return self.driver.getAlarmInfo(id)
+
+    def _list(self, **filters) -> List[alarmModel.FaultGenericModel]:
+        # filters['resourcetypeid']
+        newmodels = self.driver.getAlarmList(**filters)
+        uow = self.uow
+        exist_alarms = {}
+        with uow:
+            rs = uow.session.execute(
+                '''
+                SELECT "alarmEventRecordId"
+                FROM "alarmEventRecord"
+                WHERE "perceivedSeverity" != :perceived_severity_enum
+                ''',
+                dict(perceived_severity_enum=alarmModel.PerceivedSeverityEnum.
+                     CLEARED)
+            )
+            for row in rs:
+                id = row[0]
+                # logger.debug('Exist alarm: ' + id)
+                exist_alarms[id] = False
+
+        ret = []
+        for m in newmodels:
+            try:
+                if exist_alarms[m.id]:
+                    ret.append(m)
+                    exist_alarms[m.id] = True
+            except KeyError:
+                logger.debug('alarm new: ' + m.id)
+                ret.append(m)
+
+        for alarm in exist_alarms:
+            logger.debug('exist alarm: ' + alarm)
+            if exist_alarms[alarm]:
+                # exist alarm is active
+                continue
+            event = self._get(alarm)
+            ret.append(event)
+
+        return ret
+
+    def _set_stx_client(self):
+        pass
+
+
+class StxEventClient(BaseClient):
+    def __init__(self, driver=None):
+        super().__init__()
+        self.driver = driver if driver else StxFaultClientImp()
+
+    def _get(self, id) -> alarmModel.FaultGenericModel:
+        return self.driver.getEventInfo(id)
+
+    def _list(self, **filters) -> List[alarmModel.FaultGenericModel]:
+        return self.driver.getEventList(**filters)
+
+    def _set_stx_client(self):
+        pass
+
+
+# internal driver which implement client call to Stx Fault Management instance
+class StxFaultClientImp(object):
+    def __init__(self, fm_client=None):
+        super().__init__()
+        self.fmclient = fm_client if fm_client else self.getFmClient()
+        # if subcloud_id is not None:
+        # self.stxclient = self.getSubcloudClient(subcloud_id)
+
+    def getFmClient(self):
+        os_client_args = config.get_fm_access_info()
+        config_client = get_fm_client(1, **os_client_args)
+        return config_client
+
+    def getAlarmList(self, **filters) -> List[alarmModel.FaultGenericModel]:
+        alarms = self.fmclient.alarm.list(expand=True)
+        if len(alarms) == 0:
+            return []
+        logger.debug('alarm 1:' + str(alarms[0].to_dict()))
+        # [print('alarm:' + str(alarm.to_dict())) for alarm in alarms if alarm]
+        return [alarmModel.FaultGenericModel(
+            ResourceTypeEnum.PSERVER, self._alarmconverter(alarm))
+            for alarm in alarms if alarm]
+
+    def getAlarmInfo(self, id) -> alarmModel.FaultGenericModel:
+        try:
+            alarm = self.fmclient.alarm.get(id)
+            logger.debug('get alarm id ' + id + ':' + str(alarm.to_dict()))
+            # print(alarm.to_dict())
+        except HTTPNotFound:
+            event = self.fmclient.event_log.get(id)
+            return alarmModel.FaultGenericModel(
+                ResourceTypeEnum.PSERVER, self._eventconverter(event, True))
+        return alarmModel.FaultGenericModel(
+            ResourceTypeEnum.PSERVER, self._alarmconverter(alarm))
+
+    def getEventList(self, **filters) -> List[alarmModel.FaultGenericModel]:
+        events = self.fmclient.event_log.list(alarms=True, expand=True)
+        logger.debug('event 1:' + str(events[0].to_dict()))
+        # [print('alarm:' + str(event.to_dict())) for event in events if event]
+        return [alarmModel.FaultGenericModel(
+            ResourceTypeEnum.PSERVER, self._eventconverter(event))
+            for event in events if event]
+
+    def getEventInfo(self, id) -> alarmModel.FaultGenericModel:
+        event = self.fmclient.event_log.get(id)
+        logger.debug('get event id ' + id + ':' + str(event.to_dict()))
+        # print(event.to_dict())
+        return alarmModel.FaultGenericModel(
+            ResourceTypeEnum.PSERVER, self._eventconverter(event))
+
+    @ staticmethod
+    def _alarmconverter(alarm):
+        # setattr(alarm, 'alarm_def_id', uuid.uuid3(
+        #         uuid.NAMESPACE_URL, alarm.alarm_id))
+        setattr(alarm, 'state', alarm.alarm_state)
+        setattr(alarm, 'event_log_type', alarm.alarm_type)
+        setattr(alarm, 'event_log_id', alarm.alarm_id)
+
+        setattr(alarm, 'alarm_def_id', uuid.uuid3(
+                uuid.NAMESPACE_URL, alarm.alarm_id))
+        setattr(alarm, 'probable_cause_id', uuid.uuid3(
+                uuid.NAMESPACE_URL, alarm.probale_cause))
+        return alarm
+
+    @ staticmethod
+    def _eventconverter(event, clear=False):
+        setattr(event, 'alarm_id', event.event_log_id)
+        setattr(event, 'alarm_type', event.event_log_type)
+        if clear:
+            logger.debug('alarm is clear')
+            event.state = 'clear'
+        setattr(event, 'alarm_def_id', uuid.uuid3(
+                uuid.NAMESPACE_URL, event.alarm_id))
+        setattr(event, 'probable_cause_id', uuid.uuid3(
+                uuid.NAMESPACE_URL, event.probale_cause))
+        return event
+
+    @ staticmethod
+    def _alarmeventhasher(event, state=''):
+        # The event model and the alarm model have different parameter name
+        # of the state. alarm model is alarm_state, event model is state.
+        status = event.alarm_state if state == '' else state
+        return str(hash((event.uuid, event.timestamp, status)))
index cb3a694..4775f29 100644 (file)
@@ -37,7 +37,9 @@ from sqlalchemy.orm import mapper, relationship
 from o2ims.domain import ocloud as ocloudModel
 from o2ims.domain import subscription_obj as subModel
 from o2ims.domain import configuration_obj as confModel
+from o2ims.domain import alarm_obj as alarmModel
 from o2ims.domain.resource_type import ResourceTypeEnum
+# from o2ims.domain.alarm_obj import AlarmLastChangeEnum, PerceivedSeverityEnum
 
 from o2common.helper import o2logging
 logger = o2logging.get_logger(__name__)
@@ -163,6 +165,66 @@ configuration = Table(
     Column("comments", String(255)),
 )
 
+alarm_definition = Table(
+    "alarmDefinition",
+    metadata,
+    Column("updatetime", DateTime),
+    Column("createtime", DateTime),
+
+    Column("alarmDefinitionId", String(255), primary_key=True),
+    Column("alarmName", String(255), unique=True),
+    Column("alarmLastChange", String(255)),
+    Column("alarmDescription", String(255)),
+    Column("proposeRepairActions", String(255)),
+    Column("clearingType", String(255)),
+    Column("managementInterfaceId", String(255)),
+    Column("pkNotificationField", String(255))
+)
+
+alarm_event_record = Table(
+    "alarmEventRecord",
+    metadata,
+    Column("updatetime", DateTime),
+    Column("createtime", DateTime),
+    Column("hash", String(255)),
+
+    Column("alarmEventRecordId", String(255), primary_key=True),
+    Column("resourceTypeId", ForeignKey("resourcetype.resourceTypeId")),
+    Column("resourceId", ForeignKey("resource.resourceId")),
+    Column("alarmDefinitionId", ForeignKey(
+        "alarmDefinition.alarmDefinitionId")),
+    Column("probableCauseId", String(255)),
+    Column("perceivedSeverity", Integer),
+    Column("alarmRaisedTime", String(255)),
+    Column("alarmChangedTime", String(255)),
+    Column("alarmAcknowledgeTime", String(255)),
+    Column("alarmAcknowledged", String(255)),
+)
+
+alarm_probable_cause = Table(
+    "probableCause",
+    metadata,
+    Column("updatetime", DateTime),
+    Column("createtime", DateTime),
+    Column("hash", String(255)),
+
+    Column("probableCauseId", String(255), primary_key=True),
+    Column("name", String(255)),
+    Column("description", String(255)),
+)
+
+alarm_subscription = Table(
+    "alarmSubscription",
+    metadata,
+    Column("updatetime", DateTime),
+    Column("createtime", DateTime),
+
+    Column("alarmSubscriptionId", String(255), primary_key=True),
+    Column("callback", String(255)),
+    Column("consumerSubscriptionId", String(255)),
+    Column("filter", String(255)),
+)
+
 
 @retry((exc.IntegrityError), tries=3, delay=2)
 def wait_for_metadata_ready(engine):
@@ -174,6 +236,7 @@ def wait_for_metadata_ready(engine):
 def start_o2ims_mappers(engine=None):
     logger.info("Starting O2 IMS mappers")
 
+    # IMS Infrastructure Inventory Mappering
     dm_mapper = mapper(ocloudModel.DeploymentManager, deploymentmanager)
     resourcepool_mapper = mapper(ocloudModel.ResourcePool, resourcepool)
     resourcetype_mapper = mapper(ocloudModel.ResourceType, resourcetype)
@@ -196,5 +259,11 @@ def start_o2ims_mappers(engine=None):
     mapper(subModel.Subscription, subscription)
     mapper(confModel.Configuration, configuration)
 
+    # IMS Infrastruture Monitoring Mappering
+    mapper(alarmModel.AlarmEventRecord, alarm_event_record)
+    mapper(alarmModel.AlarmDefinition, alarm_definition)
+    mapper(alarmModel.ProbableCause, alarm_probable_cause)
+    mapper(alarmModel.AlarmSubscription, alarm_subscription)
+
     if engine is not None:
         wait_for_metadata_ready(engine)
diff --git a/o2ims/domain/alarm_obj.py b/o2ims/domain/alarm_obj.py
new file mode 100644 (file)
index 0000000..fa7cba2
--- /dev/null
@@ -0,0 +1,188 @@
+# 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.
+
+from __future__ import annotations
+from enum import Enum
+import json
+import datetime
+
+from o2common.domain.base import AgRoot, Serializer
+
+
+class FaultGenericModel(AgRoot):
+    def __init__(self, type: str,
+                 api_response: dict = None, content_hash=None) -> None:
+        super().__init__()
+        if api_response:
+            self.id = str(api_response.uuid)
+            self.name = self.id
+            self.type = type
+            self.status = api_response.state
+            # TODO: time less than second
+            self.timestamp = datetime.datetime.strptime(
+                api_response.timestamp.split('.')[0], "%Y-%m-%dT%H:%M:%S") \
+                if api_response.timestamp else None
+
+            # if hasattr(api_response, 'alarm_id'):
+            #     self.alarm_id = api_response.alarm_id
+            # elif hasattr(api_response, 'event_log_id'):
+            #     self.alarm_id = api_response.event_log_id
+
+            self.hash = content_hash if content_hash \
+                else str(hash((self.id, self.timestamp, self.status)))
+            self.content = json.dumps(api_response.to_dict())
+
+    def is_outdated(self, newmodel) -> bool:
+        # return self.updatetime < newmodel.updatetime
+        # logger.warning("hash1: " + self.hash + " vs hash2: " + newmodel.hash)
+        return self.hash != newmodel.hash
+
+    def update_by(self, newmodel) -> None:
+        if self.id != newmodel.id:
+            pass
+            # raise MismatchedModel("Mismatched model")
+        self.name = newmodel.name
+        self.createtime = newmodel.createtime
+        self.updatetime = newmodel.updatetime
+        self.content = newmodel.content
+
+
+class PerceivedSeverityEnum(str, Enum):
+    CRITICAL = 0
+    MAJOR = 1
+    MINOR = 2
+    WARNING = 3
+    INDETERMINATE = 4
+    CLEARED = 5
+
+
+class AlarmEventRecord(AgRoot, Serializer):
+    def __init__(self, id: str, res_type_id: str, res_id: str,
+                 alarm_def_id: str, probable_cause_id: str,
+                 raised_time: str,
+                 perc_severity: PerceivedSeverityEnum =
+                 PerceivedSeverityEnum.WARNING
+                 ) -> None:
+        super().__init__()
+        self.alarmEventRecordId = id
+        self.resourceTypeId = res_type_id
+        self.resourceId = res_id
+        self.alarmDefinitionId = alarm_def_id
+        self.probableCauseId = probable_cause_id
+        self.perceivedSeverity = perc_severity
+        self.alarmRaisedTime = raised_time
+        self.alarmChangedTime = ''
+        self.alarmAcknowledgeTime = ''
+        self.alarmAcknowledged = False
+        self.extensions = []
+
+
+class ProbableCause(AgRoot, Serializer):
+    def __init__(self, id: str, name: str, desc: str = '') -> None:
+        super().__init__()
+        self.probableCauseId = id
+        self.name = name
+        self.description = desc
+
+
+class AlarmLastChangeEnum(str, Enum):
+    ADDED = 'ADDED'
+    DELETED = 'DELETED'
+    MODIFYED = 'MODIFYED'
+
+
+class ClearingTypeEnum(str, Enum):
+    AUTOMATIC = 'AUTOMATIC'
+    MANUAL = 'MANUAL'
+
+
+class AlarmDefinition(AgRoot, Serializer):
+    def __init__(self, id: str, name: str, last_change: AlarmLastChangeEnum,
+                 desc: str, prop_action: str, clearing_type: ClearingTypeEnum,
+                 pk_noti_field: str) -> None:
+        super().__init__()
+        self.alarmDefinitionId = id
+        self.alarmName = name
+        self.alarmLastChange = last_change
+        self.alarmDescription = desc
+        self.proposedRepairActions = prop_action
+        self.clearingType = clearing_type
+        self.managementInterfaceId = "O2IMS"
+        self.pkNotificationField = pk_noti_field
+        self.alarmAdditionalFields = ""
+
+
+class AlarmDictionary(AgRoot, Serializer):
+    def __init__(self, id: str) -> None:
+        super().__init__()
+        self.id = id
+        self.alarmDictionaryVersion = ""
+        self.alarmDictionarySchemaVersion = ""
+        self.entityType = ""
+        self.vendor = ""
+        self.managementInterfaceId = "O2IMS"
+        self.pkNotificationField = ""
+        self.alarmDefinition = ""
+
+
+class AlarmNotificationEventEnum(str, Enum):
+    NEW = 0
+    CHANGE = 1
+    CLEAR = 2
+    ACKNOWLEDGE = 3
+
+
+class AlarmEvent2SMO(Serializer):
+    def __init__(self, eventtype: AlarmNotificationEventEnum,
+                 id: str, ref: str, updatetime: str) -> None:
+        self.notificationEventType = eventtype
+        self.objectRef = ref
+        self.id = id
+        self.updatetime = updatetime
+
+
+class AlarmSubscription(AgRoot, Serializer):
+    def __init__(self, id: str, callback: str, consumersubid: str = '',
+                 filter: str = '') -> None:
+        super().__init__()
+        self.alarmSubscriptionId = id
+        self.version_number = 0
+        self.callback = callback
+        self.consumerSubscriptionId = consumersubid
+        self.filter = filter
+
+
+class AlarmEventNotification(AgRoot, Serializer):
+    def __init__(self, alarm: AlarmEventRecord, to_smo: AlarmEvent2SMO,
+                 consumersubid: str) -> None:
+        super().__init__()
+        self.globalCloudId = ''
+        self.consumerSubscriptionId = consumersubid
+        self._convert_params(alarm, to_smo)
+
+    def _convert_params(self, alarm: AlarmEventRecord, to_smo: AlarmEvent2SMO):
+        self.notificationEventType = to_smo.notificationEventType
+        self.objectRef = to_smo.objectRef
+
+        self.alarmEventRecordId = alarm.alarmEventRecordId
+        self.resourceTypeId = alarm.resourceTypeId
+        self.resourceId = alarm.resourceId
+        self.alarmDefinitionId = alarm.alarmDefinitionId
+        self.probableCauseId = alarm.probableCauseId
+        self.perceivedSeverity = alarm.perceivedSeverity
+        self.alarmRaisedTime = alarm.alarmRaisedTime
+        self.alarmChangedTime = alarm.alarmChangedTime
+        self.alarmAcknowledgeTime = alarm.alarmAcknowledgeTime
+        self.alarmAcknowledged = alarm.alarmAcknowledged
+        self.extensions = []
diff --git a/o2ims/domain/alarm_repo.py b/o2ims/domain/alarm_repo.py
new file mode 100644 (file)
index 0000000..d3e7f52
--- /dev/null
@@ -0,0 +1,221 @@
+# 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.
+
+import abc
+from typing import List, Set
+from o2ims.domain import alarm_obj as obj
+
+
+class AlarmEventRecordRepository(abc.ABC):
+    def __init__(self):
+        self.seen = set()  # type: Set[obj.AlarmEventRecord]
+
+    def add(self, alarm_event_record: obj.AlarmEventRecord):
+        self._add(alarm_event_record)
+        self.seen.add(alarm_event_record)
+
+    def get(self, alarm_event_record_id) -> obj.AlarmEventRecord:
+        alarm_event_record = self._get(alarm_event_record_id)
+        if alarm_event_record:
+            self.seen.add(alarm_event_record)
+        return alarm_event_record
+
+    def list(self) -> List[obj.AlarmEventRecord]:
+        return self._list()
+
+    def update(self, alarm_event_record: obj.AlarmEventRecord):
+        self._update(alarm_event_record)
+
+    def delete(self, alarm_event_record_id):
+        self._delete(alarm_event_record_id)
+
+    @abc.abstractmethod
+    def _add(self, alarm_event_record: obj.AlarmEventRecord):
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def _get(self, alarm_event_record_id) -> obj.AlarmEventRecord:
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def _list(self) -> List[obj.AlarmEventRecord]:
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def _update(self, alarm_event_record: obj.AlarmEventRecord):
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def _delete(self, alarm_event_record_id):
+        raise NotImplementedError
+
+
+class AlarmDefinitionRepository(abc.ABC):
+    def __init__(self):
+        self.seen = set()  # type: Set[obj.AlarmDefinition]
+
+    def add(self, definition: obj.AlarmDefinition):
+        self._add(definition)
+        self.seen.add(definition)
+
+    def get(self, definition_id) -> obj.AlarmDefinition:
+        definition = self._get(definition_id)
+        if definition:
+            self.seen.add(definition)
+        return definition
+
+    def list(self) -> List[obj.AlarmDefinition]:
+        return self._list()
+
+    def update(self, definition: obj.AlarmDefinition):
+        self._update(definition)
+
+    def delete(self, definition_id):
+        self._delete(definition_id)
+
+    @abc.abstractmethod
+    def _add(self, definition: obj.AlarmDefinition):
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def _get(self, definition_id) -> obj.AlarmDefinition:
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def _update(self, definition: obj.AlarmDefinition):
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def _delete(self, definition_id):
+        raise NotImplementedError
+
+
+class AlarmDictionaryRepository(abc.ABC):
+    def __init__(self):
+        self.seen = set()  # type: Set[obj.AlarmDictionary]
+
+    def add(self, dictionary: obj.AlarmDictionary):
+        self._add(dictionary)
+        self.seen.add(dictionary)
+
+    def get(self, dictionary_id) -> obj.AlarmDictionary:
+        dictionary = self._get(dictionary_id)
+        if dictionary:
+            self.seen.add(dictionary)
+        return dictionary
+
+    def list(self) -> List[obj.AlarmDictionary]:
+        return self._list()
+
+    def update(self, dictionary: obj.AlarmDictionary):
+        self._update(dictionary)
+
+    def delete(self, dictionary_id):
+        self._delete(dictionary_id)
+
+    @abc.abstractmethod
+    def _add(self, dictionary: obj.AlarmDictionary):
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def _get(self, dictionary_id) -> obj.AlarmDictionary:
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def _update(self, dictionary: obj.AlarmDictionary):
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def _delete(self, dictionary_id):
+        raise NotImplementedError
+
+
+class AlarmSubscriptionRepository(abc.ABC):
+    def __init__(self):
+        self.seen = set()  # type: Set[obj.AlarmSubscription]
+
+    def add(self, subscription: obj.AlarmSubscription):
+        self._add(subscription)
+        self.seen.add(subscription)
+
+    def get(self, subscription_id) -> obj.AlarmSubscription:
+        subscription = self._get(subscription_id)
+        if subscription:
+            self.seen.add(subscription)
+        return subscription
+
+    def list(self) -> List[obj.AlarmSubscription]:
+        return self._list()
+
+    def update(self, subscription: obj.AlarmSubscription):
+        self._update(subscription)
+
+    def delete(self, subscription_id):
+        self._delete(subscription_id)
+
+    @abc.abstractmethod
+    def _add(self, subscription: obj.AlarmSubscription):
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def _get(self, subscription_id) -> obj.AlarmSubscription:
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def _update(self, subscription: obj.AlarmSubscription):
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def _delete(self, subscription_id):
+        raise NotImplementedError
+
+
+class AlarmProbableCauseRepository(abc.ABC):
+    def __init__(self):
+        self.seen = set()  # type: Set[obj.ProbableCause]
+
+    def add(self, probable_cause: obj.ProbableCause):
+        self._add(probable_cause)
+        self.seen.add(probable_cause)
+
+    def get(self, probable_cause_id) -> obj.ProbableCause:
+        probable_cause = self._get(probable_cause_id)
+        if probable_cause:
+            self.seen.add(probable_cause)
+        return probable_cause
+
+    def list(self) -> List[obj.ProbableCause]:
+        return self._list()
+
+    def update(self, probable_cause: obj.ProbableCause):
+        self._update(probable_cause)
+
+    def delete(self, probable_cause_id):
+        self._delete(probable_cause_id)
+
+    @abc.abstractmethod
+    def _add(self, probable_cause: obj.ProbableCause):
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def _get(self, probable_cause_id) -> obj.ProbableCause:
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def _update(self, probable_cause: obj.ProbableCause):
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def _delete(self, probable_cause_id):
+        raise NotImplementedError
index bcd6e86..4ab1b25 100644 (file)
 
 # 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 typing import List
+
 from o2ims.domain.stx_object import StxGenericModel
+from o2ims.domain.alarm_obj import AlarmEvent2SMO
 from o2ims.domain.subscription_obj import Message2SMO, RegistrationMessage
+# from o2ims.domain.resource_type import ResourceTypeEnum
 from o2common.domain.commands import Command
 
 
@@ -33,6 +34,11 @@ class PubMessage2SMO(Command):
     data: Message2SMO
 
 
+@dataclass
+class PubAlarm2SMO(Command):
+    data: AlarmEvent2SMO
+
+
 @dataclass
 class Register2SMO(Command):
     data: RegistrationMessage
@@ -91,3 +97,8 @@ class UpdatePserverIf(UpdateResource):
 @dataclass
 class UpdatePserverIfPort(UpdateResource):
     pass
+
+
+@dataclass
+class UpdateAlarm(UpdateStxObject):
+    pass
index 4858040..eb0250f 100644 (file)
@@ -18,6 +18,7 @@ from datetime import datetime
 
 from o2common.domain.events import Event
 from o2ims.domain.subscription_obj import NotificationEventEnum
+from o2ims.domain.alarm_obj import AlarmNotificationEventEnum
 
 
 @dataclass
@@ -52,3 +53,10 @@ class ResourceChanged(Event):
 class ConfigurationChanged(Event):
     id: str
     updatetime: datetime.now()
+
+
+@dataclass
+class AlarmEventChanged(Event):
+    id: str
+    notificationEventType: AlarmNotificationEventEnum
+    updatetime: datetime.now()
diff --git a/o2ims/service/auditor/alarm_handler.py b/o2ims/service/auditor/alarm_handler.py
new file mode 100644 (file)
index 0000000..6288531
--- /dev/null
@@ -0,0 +1,230 @@
+# 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.
+
+# pylint: disable=unused-argument
+from __future__ import annotations
+import json
+
+# from o2common.config import config
+# from o2common.service.messagebus import MessageBus
+from o2common.service.unit_of_work import AbstractUnitOfWork
+from o2ims.domain import events, commands, alarm_obj
+from o2ims.domain.alarm_obj import AlarmEventRecord, FaultGenericModel,\
+    AlarmNotificationEventEnum
+
+from o2common.helper import o2logging
+logger = o2logging.get_logger(__name__)
+
+
+def update_alarm(
+    cmd: commands.UpdateAlarm,
+    uow: AbstractUnitOfWork
+):
+    fmobj = cmd.data
+    logger.info("add alarm event record:" + fmobj.name
+                + " update_at: " + str(fmobj.updatetime)
+                + " id: " + str(fmobj.id)
+                + " hash: " + str(fmobj.hash))
+    with uow:
+        logger.debug('+++test alarm dict:' +
+                     str(len(uow.alarm_dictionaries.list())))
+        alarm_event_record = uow.alarm_event_records.get(fmobj.id)
+        if not alarm_event_record:
+            logger.info("add alarm event record:" + fmobj.name
+                        + " update_at: " + str(fmobj.updatetime)
+                        + " id: " + str(fmobj.id)
+                        + " hash: " + str(fmobj.hash))
+            localmodel = create_by(fmobj)
+            content = json.loads(fmobj.content)
+            entity_type_id = content['entity_type_id']
+            entity_instance_id = content['entity_instance_id']
+            logger.info('alarm entity instance id: ' + entity_instance_id)
+            if 'host' == entity_type_id:
+                # TODO: handle different resource type
+                hostname = entity_instance_id.split('.')[0].split('=')[1]
+                logger.debug('hostname: ' + hostname)
+                respools = uow.resource_pools.list()
+                respoolids = [respool.resourcePoolId for respool in
+                              respools if respool.oCloudId ==
+                              respool.resourcePoolId]
+                restype = uow.resource_types.get_by_name('pserver')
+                localmodel.resourceTypeId = restype.resourceTypeId
+                hosts = uow.resources.list(respoolids[0], **{
+                    'resourceTypeId': restype.resourceTypeId
+                })
+                for host in hosts:
+                    if host.name == hostname:
+                        localmodel.resourceId = host.resourceId
+                uow.alarm_event_records.add(localmodel)
+                logger.info("Add the alarm event record: " + fmobj.id
+                            + ", name: " + fmobj.name)
+            # localmodel.resourceTypeId = check_restype_id(uow, fmobj)
+            # logger.debug("resource type ID: " + localmodel.resourceTypeId)
+            # localmodel.resourceId = check_res_id(uow, fmobj)
+            # logger.debug("resource ID: " + localmodel.resourceId)
+            # uow.alarm_event_records.add(localmodel)
+
+        else:
+            localmodel = alarm_event_record
+            if is_outdated(localmodel, fmobj):
+                logger.info("update alarm event record:" + fmobj.name
+                            + " update_at: " + str(fmobj.updatetime)
+                            + " id: " + str(fmobj.id)
+                            + " hash: " + str(fmobj.hash))
+                update_by(localmodel, fmobj)
+                uow.alarm_event_records.update(localmodel)
+
+            logger.info("Update the alarm event record: " + fmobj.id
+                        + ", name: " + fmobj.name)
+        uow.commit()
+
+
+def is_outdated(alarm_event_record: AlarmEventRecord,
+                fmobj: FaultGenericModel):
+    return True if alarm_event_record.hash != fmobj.hash else False
+
+
+def create_by(fmobj: FaultGenericModel) -> AlarmEventRecord:
+    content = json.loads(fmobj.content)
+    # globalcloudId = fmobj.id  # to be updated
+    alarm_definition_id = fmobj.alarm_def_id
+    alarm_event_record = AlarmEventRecord(
+        fmobj.id, "", "",
+        alarm_definition_id, "",
+        fmobj.timestamp)
+
+    def severity_switch(val):
+        if val == 'critical':
+            return alarm_obj.PerceivedSeverityEnum.CRITICAL
+        elif val == 'major':
+            return alarm_obj.PerceivedSeverityEnum.MAJOR
+        elif val == 'minor':
+            return alarm_obj.PerceivedSeverityEnum.MINOR
+        else:
+            return alarm_obj.PerceivedSeverityEnum.WARNING
+    alarm_event_record.perceivedSeverity = severity_switch(content['severity'])
+    alarm_event_record.probableCauseId = content['probable_cause_id']
+    alarm_event_record.hash = fmobj.hash
+    # logger.info('severity: ' + content['severity'])
+    # logger.info('perceived severity: '
+    # + alarm_event_record.perceivedSeverity)
+    alarm_event_record.events.append(events.AlarmEventChanged(
+        id=fmobj.id,
+        notificationEventType=AlarmNotificationEventEnum.NEW,
+        updatetime=fmobj.updatetime
+    ))
+
+    return alarm_event_record
+
+
+def update_by(target: AlarmEventRecord, fmobj: FaultGenericModel
+              ) -> None:
+    # content = json.loads(fmobj.content)
+    target.hash = fmobj.hash
+    if fmobj.status == 'clear':
+        target.perceivedSeverity = alarm_obj.PerceivedSeverityEnum.CLEARED
+    target.events.append(events.AlarmEventChanged(
+        id=fmobj.id,
+        notificationEventType=AlarmNotificationEventEnum.CLEAR,
+        updatetime=fmobj.updatetime
+    ))
+
+
+def check_restype_id(uow: AbstractUnitOfWork, fmobj: FaultGenericModel) -> str:
+    content = json.loads(fmobj.content)
+    entity_type_id = content['entity_type_id']
+    # Entity_Instance_ID: <hostname>.lvmthinpool=<VG name>/<Pool name>
+    # Entity_Instance_ID: ["image=<image-uuid>, instance=<instance-uuid>",
+    # Entity_Instance_ID: [host=<hostname>.command=provision,
+    # Entity_Instance_ID: [host=<hostname>.event=discovered,
+    # Entity_Instance_ID: [host=<hostname>.state=disabled,
+    # Entity_Instance_ID: [subcloud=<subcloud>.resource=<compute | network
+    # | platform | volumev2>]
+    # Entity_Instance_ID: cinder_io_monitor
+    # Entity_Instance_ID: cluster=<dist-fs-uuid>
+    # Entity_Instance_ID: cluster=<dist-fs-uuid>.peergroup=<group-x>
+    # Entity_Instance_ID: fs_name=<image-conversion>
+    # Entity_Instance_ID: host=<host_name>
+    # Entity_Instance_ID: host=<host_name>.network=<network>
+    # Entity_Instance_ID: host=<host_name>.services=compute
+    # Entity_Instance_ID: host=<hostname>
+    # Entity_Instance_ID: host=<hostname>,agent=<agent-uuid>,
+    # bgp-peer=<bgp-peer>
+    # Entity_Instance_ID: host=<hostname>.agent=<agent-uuid>
+    # Entity_Instance_ID: host=<hostname>.interface=<if-name>
+    # Entity_Instance_ID: host=<hostname>.interface=<if-uuid>
+    # Entity_Instance_ID: host=<hostname>.ml2driver=<driver>
+    # Entity_Instance_ID: host=<hostname>.network=<mgmt | oam | cluster-host>
+    # Entity_Instance_ID: host=<hostname>.openflow-controller=<uri>
+    # Entity_Instance_ID: host=<hostname>.openflow-network=<name>
+    # Entity_Instance_ID: host=<hostname>.port=<port-name>
+    # Entity_Instance_ID: host=<hostname>.port=<port-uuid>
+    # Entity_Instance_ID: host=<hostname>.process=<processname>
+    # Entity_Instance_ID: host=<hostname>.processor=<processor>
+    # Entity_Instance_ID: host=<hostname>.sdn-controller=<uuid>
+    # Entity_Instance_ID: host=<hostname>.sensor=<sensorname>
+    # Entity_Instance_ID: host=<hostname>.service=<service>
+    # Entity_Instance_ID: host=<hostname>.service=networking.providernet=
+    # <pnet-uuid>
+    # Entity_Instance_ID: host=controller
+    # Entity_Instance_ID: itenant=<tenant-uuid>.instance=<instance-uuid>
+    # Entity_Instance_ID: k8s_application=<appname>
+    # Entity_Instance_ID: kubernetes=PV-migration-failed
+    # Entity_Instance_ID: orchestration=fw-update
+    # Entity_Instance_ID: orchestration=kube-rootca-update
+    # Entity_Instance_ID: orchestration=kube-upgrade
+    # Entity_Instance_ID: orchestration=sw-patch
+    # Entity_Instance_ID: orchestration=sw-upgrade
+    # Entity_Instance_ID: resource=<crd-resource>,name=<resource-name>
+    # Entity_Instance_ID: server-group<server-group-uuid>
+    # Entity_Instance_ID: service=networking.providernet=<pnet-uuid>
+    # Entity_Instance_ID: service_domain=<domain>.service_group=<group>
+    # Entity_Instance_ID: service_domain=<domain>.service_group=<group>.
+    # host=<host_name>
+    # Entity_Instance_ID: service_domain=<domain_name>.service_group=
+    # <group_name>
+    # Entity_Instance_ID: service_domain=<domain_name>.service_group=
+    # <group_name>.host=<hostname>
+    # Entity_Instance_ID: storage_backend=<storage-backend-name>
+    # Entity_Instance_ID: subcloud=<subcloud>
+    # Entity_Instance_ID: subsystem=vim
+    # Entity_Instance_ID: tenant=<tenant-uuid>.instance=<instance-uuid>
+    if 'host' == entity_type_id:
+        with uow:
+            restype = uow.resource_types.get_by_name('pserver')
+            return restype.resourceTypeId
+    else:
+        return ""
+
+
+def check_res_id(uow: AbstractUnitOfWork, fmobj: FaultGenericModel) -> str:
+    content = json.loads(fmobj.content)
+    entity_type_id = content['entity_type_id']
+    entity_instance_id = content['entity_instance_id']
+    if 'host' == entity_type_id:
+        logger.info('host: ' + entity_instance_id)
+        hostname = entity_instance_id.split('.')[0].split('=')[1]
+        with uow:
+            respools = uow.resource_pools.list()
+            respoolids = [respool.resourcePoolId for respool in respools
+                          if respool.oCloudId == respool.resourcePoolId]
+            restype = uow.resource_types.get_by_name('pserver')
+            hosts = uow.resources.list(respoolids[0], **{
+                'resourceTypeId': restype.resourceTypeId
+            })
+            for host in hosts:
+                if host.name == hostname:
+                    return host.resourceId
+    else:
+        return ""
diff --git a/o2ims/service/command/notify_alarm_handler.py b/o2ims/service/command/notify_alarm_handler.py
new file mode 100644 (file)
index 0000000..b2ca61c
--- /dev/null
@@ -0,0 +1,67 @@
+# 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
+# import requests
+import http.client
+from urllib.parse import urlparse
+
+# from o2common.config import config
+from o2common.service.unit_of_work import AbstractUnitOfWork
+from o2ims.domain import commands
+from o2ims.domain.alarm_obj import AlarmSubscription, AlarmEvent2SMO
+
+from o2common.helper import o2logging
+logger = o2logging.get_logger(__name__)
+
+
+def notify_alarm_to_smo(
+    cmd: commands.PubAlarm2SMO,
+    uow: AbstractUnitOfWork,
+):
+    logger.info('In notify_alarm_to_smo')
+    data = cmd.data
+    with uow:
+        subs = uow.alarm_subscriptions.list()
+        for sub in subs:
+            sub_data = sub.serialize()
+            logger.debug('Alarm Subscription: {}'.format(
+                sub_data['alarmSubscriptionId']))
+
+            callback_smo(sub, data)
+
+
+def callback_smo(sub: AlarmSubscription, msg: AlarmEvent2SMO):
+    sub_data = sub.serialize()
+    callback_data = json.dumps({
+        'consumerSubscriptionId': sub_data['consumerSubscriptionId'],
+        'notificationEventType': msg.notificationEventType,
+        'objectRef': msg.objectRef,
+        'updateTime': msg.updatetime
+    })
+    logger.info('URL: {}, data: {}'.format(
+        sub_data['callback'], callback_data))
+    o = urlparse(sub_data['callback'])
+    conn = http.client.HTTPConnection(o.netloc)
+    headers = {'Content-type': 'application/json'}
+    conn.request('POST', o.path, callback_data, headers)
+    resp = conn.getresponse()
+    data = resp.read().decode('utf-8')
+    # json_data = json.loads(data)
+    if resp.status == 202 or resp.status == 200:
+        logger.info('Notify to SMO successed, response code {} {}, data {}'.
+                    format(resp.status, resp.reason, data))
+        return
+    logger.error('Response code is: {}'.format(resp.status))
diff --git a/o2ims/service/event/alarm_event.py b/o2ims/service/event/alarm_event.py
new file mode 100644 (file)
index 0000000..a58c52b
--- /dev/null
@@ -0,0 +1,30 @@
+# 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 Callable
+
+from o2ims.domain import events
+
+from o2common.helper import o2logging
+logger = o2logging.get_logger(__name__)
+
+
+def notify_alarm_event_change(
+    event: events.AlarmEventChanged,
+    publish: Callable,
+):
+    logger.info('In notify_alarm_event_change')
+    publish("AlarmEventChanged", event)
+    logger.debug("published Alarm Event Changed: {}".format(
+        event.id))
diff --git a/o2ims/service/watcher/alarm_watcher.py b/o2ims/service/watcher/alarm_watcher.py
new file mode 100644 (file)
index 0000000..3581ef2
--- /dev/null
@@ -0,0 +1,92 @@
+# Copyright (C) 2021 Wind River Systems, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+# from o2ims.domain.resource_type import ResourceTypeEnum
+from o2common.service.client.base_client import BaseClient
+# from o2ims.domain.stx_object import StxGenericModel
+# from o2common.service.unit_of_work import AbstractUnitOfWork
+from o2common.service.watcher.base import BaseWatcher
+from o2common.service.messagebus import MessageBus
+from o2ims.domain import commands
+
+from o2common.helper import o2logging
+logger = o2logging.get_logger(__name__)
+
+
+class AlarmWatcher(BaseWatcher):
+    def __init__(self, fault_client: BaseClient,
+                 bus: MessageBus) -> None:
+        super().__init__(fault_client, bus)
+
+    def _targetname(self):
+        return "alarm"
+
+    def _probe(self, parent: object = None, tags: object = None):
+        newmodels = self._client.list()
+        # if len(newmodels) == 0:
+        #     return []
+
+        # uow = self._bus.uow
+        # exist_alarms = {}
+        # with uow:
+        #     rs = uow.session.execute(
+        #         '''
+        #         SELECT "alarmEventRecordId"
+        #         FROM "alarmEventRecord"
+        #         WHERE "perceivedSeverity" != :perceived_severity_enum
+        #         ''',
+        #         dict(perceived_severity_enum=alarm_obj.PerceivedSeverityEnum.
+        #              CLEARED)
+        #     )
+        #     for row in rs:
+        #         id = row[0]
+        #         # logger.debug('Exist alarm: ' + id)
+        #         exist_alarms[id] = False
+
+        # ret = []
+        # for m in newmodels:
+        #     try:
+        #         if exist_alarms[m.id]:
+        #             ret.append(commands.UpdateAlarm(m))
+        #             exist_alarms[m.id] = True
+        #     except KeyError:
+        #         logger.debug('alarm new: ' + m.id)
+        #         ret.append(commands.UpdateAlarm(m))
+
+        # for alarm in exist_alarms:
+        #     logger.debug('exist alarm: ' + alarm)
+        #     if exist_alarms[alarm]:
+        #         # exist alarm is active
+        #         continue
+        #     event = self._client.get(alarm)
+        #     ret.append(commands.UpdateAlarm(event))
+
+        # return ret
+
+        return [commands.UpdateAlarm(m) for m in newmodels] \
+            if len(newmodels) > 0 else []
+
+
+# class EventWatcher(BaseWatcher):
+#     def __init__(self, fault_client: BaseClient,
+#                  bus: MessageBus) -> None:
+#         super().__init__(fault_client, bus)
+
+#     def _targetname(self):
+#         return "event"
+
+#     def _probe(self, parent: object = None, tags: object = None):
+#         newmodels = self._client.list()
+#         return [commands.UpdateAlarm(m) for m in newmodels] \
+#             if len(newmodels) > 0 else []
index b465764..f67a23f 100644 (file)
@@ -14,7 +14,7 @@
 
 
 from o2common.config import config
-from . import ocloud_route, provision_route
+from . import ocloud_route, provision_route, alarm_route
 from . import api_ns
 
 from o2common.helper import o2logging
@@ -24,11 +24,15 @@ logger = o2logging.get_logger(__name__)
 def configure_namespace(app):
     apiims = config.get_o2ims_api_base()
     apiprovision = config.get_provision_api_base()
+    apimonitoring = config.get_o2ims_monitoring_api_base()
     logger.info(
-        "Expose the O2 IMS API:{}\nExpose Provision API: {}".
-        format(apiims, apiprovision))
+        "Expose the O2 IMS API:{}\nExpose Provision API: {} \
+        \nExpose Monitoring API: {}".
+        format(apiims, apiprovision, apimonitoring))
 
     ocloud_route.configure_api_route()
     provision_route.configure_api_route()
+    alarm_route.configure_api_route()
     app.add_namespace(api_ns.api_ims_inventory_v1, path=apiims)
     app.add_namespace(api_ns.api_provision_v1, path=apiprovision)
+    app.add_namespace(api_ns.api_monitoring_v1, path=apimonitoring)
diff --git a/o2ims/views/alarm_dto.py b/o2ims/views/alarm_dto.py
new file mode 100644 (file)
index 0000000..54bfe7d
--- /dev/null
@@ -0,0 +1,69 @@
+# 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 fields
+
+from o2ims.views.api_ns import api_monitoring_v1
+
+
+class AlarmDTO:
+
+    alarm_event_record_get = api_monitoring_v1.model(
+        "AlarmGetDto",
+        {
+            'alarmEventRecordId': fields.String(
+                required=True,
+                description='Alarm Event Record ID'),
+            'resourceTypeId': fields.String,
+            'resourceId': fields.String,
+            'alarmDefinitionId': fields.String,
+            'alarmRaisedTime': fields.String,
+            'perceivedSeverity': fields.String,
+        }
+    )
+
+
+class SubscriptionDTO:
+
+    subscription_get = api_monitoring_v1.model(
+        "AlarmSubscriptionGetDto",
+        {
+            'alarmSubscriptionId': fields.String(
+                required=True,
+                description='Alarm Subscription ID'),
+            'callback': fields.String,
+            'consumerSubscriptionId': fields.String,
+            'filter': fields.String,
+        }
+    )
+
+    subscription = api_monitoring_v1.model(
+        "AlarmSubscriptionCreateDto",
+        {
+            'callback': fields.String(
+                required=True,
+                description='Alarm Subscription callback address'),
+            'consumerSubscriptionId': fields.String,
+            'filter': fields.String,
+        }
+    )
+
+    subscription_post_resp = api_monitoring_v1.model(
+        "AlarmSubscriptionCreatedRespDto",
+        {
+            'alarmSubscriptionId': fields.String(
+                required=True,
+                description='Alarm Subscription ID'),
+        }
+    )
diff --git a/o2ims/views/alarm_route.py b/o2ims/views/alarm_route.py
new file mode 100644 (file)
index 0000000..91ca8f8
--- /dev/null
@@ -0,0 +1,103 @@
+# 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 Resource
+
+from o2common.service.messagebus import MessageBus
+from o2ims.views import alarm_view
+from o2ims.views.api_ns import api_monitoring_v1
+from o2ims.views.alarm_dto import AlarmDTO, SubscriptionDTO
+
+from o2common.helper import o2logging
+logger = o2logging.get_logger(__name__)
+
+
+def configure_api_route():
+    # Set global bus for resource
+    global bus
+    bus = MessageBus.get_instance()
+
+
+# ----------  Alarm Event Record ---------- #
+@api_monitoring_v1.route("/alarms")
+class AlarmListRouter(Resource):
+
+    model = AlarmDTO.alarm_event_record_get
+
+    @api_monitoring_v1.marshal_list_with(model)
+    def get(self):
+        return alarm_view.alarm_event_records(bus.uow)
+
+
+@api_monitoring_v1.route("/alarms/<alarmEventRecordId>")
+@api_monitoring_v1.param('alarmEventRecordId', 'ID of the alarm event record')
+@api_monitoring_v1.response(404, 'Alarm Event Record not found')
+class AlarmGetRouter(Resource):
+
+    model = AlarmDTO.alarm_event_record_get
+
+    @api_monitoring_v1.doc('Get resource type')
+    @api_monitoring_v1.marshal_with(model)
+    def get(self, alarmEventRecordId):
+        result = alarm_view.alarm_event_record_one(alarmEventRecordId, bus.uow)
+        if result is not None:
+            return result
+        api_monitoring_v1.abort(
+            404, "Resource type {} doesn't exist".format(alarmEventRecordId))
+
+
+# ----------  Alarm Subscriptions ---------- #
+@api_monitoring_v1.route("/alarmSubscriptions")
+class SubscriptionsListRouter(Resource):
+
+    model = SubscriptionDTO.subscription_get
+    expect = SubscriptionDTO.subscription
+    post_resp = SubscriptionDTO.subscription_post_resp
+
+    @api_monitoring_v1.doc('List alarm subscriptions')
+    @api_monitoring_v1.marshal_list_with(model)
+    def get(self):
+        return alarm_view.subscriptions(bus.uow)
+
+    @api_monitoring_v1.doc('Create a alarm subscription')
+    @api_monitoring_v1.expect(expect)
+    @api_monitoring_v1.marshal_with(post_resp, code=201)
+    def post(self):
+        data = api_monitoring_v1.payload
+        result = alarm_view.subscription_create(data, bus.uow)
+        return result, 201
+
+
+@api_monitoring_v1.route("/alarmSubscriptions/<alarmSubscriptionID>")
+@api_monitoring_v1.param('alarmSubscriptionID', 'ID of the Alarm Subscription')
+@api_monitoring_v1.response(404, 'Alarm Subscription not found')
+class SubscriptionGetDelRouter(Resource):
+
+    model = SubscriptionDTO.subscription_get
+
+    @api_monitoring_v1.doc('Get Alarm Subscription by ID')
+    @api_monitoring_v1.marshal_with(model)
+    def get(self, alarmSubscriptionID):
+        result = alarm_view.subscription_one(
+            alarmSubscriptionID, bus.uow)
+        if result is not None:
+            return result
+        api_monitoring_v1.abort(404, "Subscription {} doesn't exist".format(
+            alarmSubscriptionID))
+
+    @api_monitoring_v1.doc('Delete subscription by ID')
+    @api_monitoring_v1.response(204, 'Subscription deleted')
+    def delete(self, alarmSubscriptionID):
+        result = alarm_view.subscription_delete(alarmSubscriptionID, bus.uow)
+        return result, 204
diff --git a/o2ims/views/alarm_view.py b/o2ims/views/alarm_view.py
new file mode 100644 (file)
index 0000000..258e323
--- /dev/null
@@ -0,0 +1,71 @@
+# Copyright (C) 2021 Wind River Systems, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+import uuid as uuid
+
+from o2common.service import unit_of_work
+from o2ims.views.alarm_dto import SubscriptionDTO
+from o2ims.domain.alarm_obj import AlarmSubscription
+
+from o2common.helper import o2logging
+# from o2common.config import config
+logger = o2logging.get_logger(__name__)
+
+
+def alarm_event_records(uow: unit_of_work.AbstractUnitOfWork):
+    with uow:
+        li = uow.alarm_event_records.list()
+    return [r.serialize() for r in li]
+
+
+def alarm_event_record_one(alarmEventRecordId: str,
+                           uow: unit_of_work.AbstractUnitOfWork):
+    with uow:
+        first = uow.alarm_event_records.get(alarmEventRecordId)
+        return first.serialize() if first is not None else None
+
+
+def subscriptions(uow: unit_of_work.AbstractUnitOfWork):
+    with uow:
+        li = uow.alarm_subscriptions.list()
+    return [r.serialize() for r in li]
+
+
+def subscription_one(subscriptionId: str,
+                     uow: unit_of_work.AbstractUnitOfWork):
+    with uow:
+        first = uow.alarm_subscriptions.get(subscriptionId)
+        return first.serialize() if first is not None else None
+
+
+def subscription_create(subscriptionDto: SubscriptionDTO.subscription,
+                        uow: unit_of_work.AbstractUnitOfWork):
+
+    sub_uuid = str(uuid.uuid4())
+    subscription = AlarmSubscription(
+        sub_uuid, subscriptionDto['callback'],
+        subscriptionDto['consumerSubscriptionId'],
+        subscriptionDto['filter'])
+    with uow:
+        uow.alarm_subscriptions.add(subscription)
+        uow.commit()
+    return {"alarmSubscriptionId": sub_uuid}
+
+
+def subscription_delete(subscriptionId: str,
+                        uow: unit_of_work.AbstractUnitOfWork):
+    with uow:
+        uow.alarm_subscriptions.delete(subscriptionId)
+        uow.commit()
+    return True
index a633a94..3fbdc18 100644 (file)
@@ -8,3 +8,7 @@ api_ims_inventory_v1 = Namespace(
 api_provision_v1 = Namespace(
     "PROVISION",
     description='Provision related operations.')
+
+api_monitoring_v1 = Namespace(
+    "O2IMS_InfrastructureMonitoring",
+    description='O2 IMS Monitoring related operations.')
index 4f5ef1a..31b4dab 100644 (file)
@@ -1,3 +1,4 @@
 -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/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
index c5ae7f0..4abb891 100644 (file)
@@ -10,6 +10,7 @@ pytest-icdiff
 mock
 
 tenacity
+pyOpenSSL
 
 # -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
\ No newline at end of file
index 09667d5..d09ba1c 100644 (file)
@@ -24,6 +24,9 @@ from o2ims.views import configure_namespace
 
 from o2app.bootstrap import bootstrap
 
+#import os
+#os.environ['ALARM_YAML'] = 'configs/alarm.yaml'
+
 
 @pytest.fixture
 def mock_uow():
diff --git a/tests/integration-ocloud/test_clientdriver_stx_fault.py b/tests/integration-ocloud/test_clientdriver_stx_fault.py
new file mode 100644 (file)
index 0000000..3c8699b
--- /dev/null
@@ -0,0 +1,89 @@
+# 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.
+
+# import sys
+# import logging
+import pytest
+
+from o2common.config import config
+from o2ims.adapter.clients.fault_client import StxFaultClientImp
+# from o2ims.adapter.clients.ocloud_client import StxClientImp
+from cgtsclient.client import get_client as get_stx_client
+from dcmanagerclient.api.client import client as get_dc_client
+from fmclient.client import get_client as get_fm_client
+
+
+@pytest.fixture
+def real_stx_aio_client():
+    os_client_args = config.get_stx_access_info()
+    config_client = get_stx_client(**os_client_args)
+    yield config_client
+
+
+@pytest.fixture
+def real_stx_dc_client():
+    os_client_args = config.get_dc_access_info()
+    config_client = get_dc_client(**os_client_args)
+    yield config_client
+
+
+@pytest.fixture
+def real_stx_fm_client():
+    os_client_args = config.get_fm_access_info()
+    config_client = get_fm_client(1, **os_client_args)
+    yield config_client
+
+# pytestmark = pytest.mark.usefixtures("mappers")
+
+
+def test_get_alarmlist(real_stx_fm_client):
+    fmClientImp = StxFaultClientImp(real_stx_fm_client)
+    assert fmClientImp is not None
+    alarms = fmClientImp.getAlarmList()
+    assert alarms is not None
+    assert len(alarms) > 0
+
+
+def test_get_alarminfo(real_stx_fm_client):
+    fmClientImp = StxFaultClientImp(real_stx_fm_client)
+    assert fmClientImp is not None
+    alarms = fmClientImp.getAlarmList()
+    assert alarms is not None
+    assert len(alarms) > 0
+    alarm1 = alarms[0]
+    alarm2 = fmClientImp.getAlarmInfo(alarm1.id)
+    assert alarm1 != alarm2
+    assert alarm1.id == alarm2.id
+    # fmClientImp.getAlarmInfo('f87478e9-4cec-44dc-8f13-9304445d4070')
+    # assert fmClientImp is None
+
+
+def test_get_eventlist(real_stx_fm_client):
+    fmClientImp = StxFaultClientImp(real_stx_fm_client)
+    assert fmClientImp is not None
+    events = fmClientImp.getEventList()
+    assert events is not None
+    assert len(events) > 0
+
+
+def test_get_eventinfo(real_stx_fm_client):
+    fmClientImp = StxFaultClientImp(real_stx_fm_client)
+    assert fmClientImp is not None
+    events = fmClientImp.getEventList()
+    assert events is not None
+    assert len(events) > 0
+    event1 = events[0]
+    event2 = fmClientImp.getEventInfo(event1.id)
+    assert event1 != event2
+    assert event1.id == event2.id
diff --git a/tests/unit/test_alarm.py b/tests/unit/test_alarm.py
new file mode 100644 (file)
index 0000000..5bcde82
--- /dev/null
@@ -0,0 +1,322 @@
+# 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 uuid
+import time
+import json
+from datetime import datetime
+from unittest.mock import MagicMock
+from typing import Callable
+
+from o2common.service.watcher import worker
+from o2common.service.unit_of_work import AbstractUnitOfWork
+from o2common.service.client.base_client import BaseClient
+from o2common.service.watcher.base import BaseWatcher, WatcherTree
+from o2common.service import messagebus
+from o2common.config import config
+
+from o2ims.domain.resource_type import ResourceTypeEnum
+from o2ims.domain import alarm_obj
+from o2ims.domain import commands
+from o2ims.views import alarm_view
+from o2ims.service.watcher.alarm_watcher import AlarmWatcher
+
+from o2app.service import handlers
+from o2app import bootstrap
+
+
+def test_new_alarm_event_record():
+    alarm_event_record_id1 = str(uuid.uuid4())
+    alarm_event_record = alarm_obj.AlarmEventRecord(
+        alarm_event_record_id1, '',
+        '', '', '', alarm_obj.PerceivedSeverityEnum.CRITICAL)
+    assert alarm_event_record_id1 is not None and \
+        alarm_event_record.alarmEventRecordId == alarm_event_record_id1
+
+
+def test_view_alarm_event_records(mock_uow):
+    session, uow = mock_uow
+
+    alarm_event_record_id1 = str(uuid.uuid4())
+    alarm_event_record1 = MagicMock()
+    alarm_event_record1.serialize.return_value = {
+        "alarmEventRecordId": alarm_event_record_id1}
+    session.return_value.query.return_value = [alarm_event_record1]
+
+    alarm_event_record_list = alarm_view.alarm_event_records(uow)
+    assert str(alarm_event_record_list[0].get(
+        "alarmEventRecordId")) == alarm_event_record_id1
+
+
+def test_view_alarm_event_record_one(mock_uow):
+    session, uow = mock_uow
+
+    alarm_event_record_id1 = str(uuid.uuid4())
+    session.return_value.query.return_value.filter_by.return_value.first.\
+        return_value.serialize.return_value = None
+
+    # Query return None
+    alarm_event_record1 = alarm_view.alarm_event_record_one(
+        alarm_event_record_id1, uow)
+    assert alarm_event_record1 is None
+
+    session.return_value.query.return_value.filter_by.return_value.first.\
+        return_value.serialize.return_value = {
+            "alarmEventRecordId": alarm_event_record_id1}
+
+    alarm_event_record1 = alarm_view.alarm_event_record_one(
+        alarm_event_record_id1, uow)
+    assert str(alarm_event_record1.get(
+        "alarmEventRecordId")) == alarm_event_record_id1
+
+
+def test_alarm_dictionary(mock_uow):
+    session, uow = mock_uow
+    alarm_dict1 = alarm_obj.AlarmDictionary('test1')
+    alarm_dict1.entityType = 'test1'
+    with uow:
+        uow.alarm_dictionaries.add(alarm_dict1)
+
+        alarm_dict2 = uow.alarm_dictionaries.get('test1')
+        assert alarm_dict1 == alarm_dict2
+
+        dict_list = uow.alarm_dictionaries.list()
+        assert len(dict_list) > 0
+
+
+def test_flask_get_list(mock_flask_uow):
+    session, app = mock_flask_uow
+    session.query.return_value = []
+    apibase = config.get_o2ims_monitoring_api_base()
+
+    with app.test_client() as client:
+        # Get list and return empty list
+        ##########################
+        resp = client.get(apibase+"/alarms")
+        assert resp.get_data() == b'[]\n'
+
+        resp = client.get(apibase+"/alarmSubscriptions")
+        assert resp.get_data() == b'[]\n'
+
+
+def test_flask_get_one(mock_flask_uow):
+    session, app = mock_flask_uow
+
+    session.return_value.query.return_value.filter_by.return_value.\
+        first.return_value = None
+    apibase = config.get_o2ims_monitoring_api_base()
+
+    with app.test_client() as client:
+        # Get one and return 404
+        ###########################
+        alarm_id1 = str(uuid.uuid4())
+        resp = client.get(apibase+"/alarms/"+alarm_id1)
+        assert resp.status_code == 404
+
+        sub_id1 = str(uuid.uuid4())
+        resp = client.get(apibase+"/alarmSubscriptions/"+sub_id1)
+        assert resp.status_code == 404
+
+
+def test_flask_post(mock_flask_uow):
+    session, app = mock_flask_uow
+    apibase = config.get_o2ims_monitoring_api_base()
+
+    with app.test_client() as client:
+        session.return_value.execute.return_value = []
+
+        sub_callback = 'http://subscription/callback/url'
+        resp = client.post(apibase+'/alarmSubscriptions', json={
+            'callback': sub_callback,
+            'consumerSubscriptionId': 'consumerSubId1',
+            'filter': 'empty'
+        })
+        assert resp.status_code == 201
+        assert 'alarmSubscriptionId' in resp.get_json()
+
+
+def test_flask_delete(mock_flask_uow):
+    session, app = mock_flask_uow
+    apibase = config.get_o2ims_monitoring_api_base()
+
+    with app.test_client() as client:
+        session.return_value.execute.return_value.first.return_value = {}
+
+        subscription_id1 = str(uuid.uuid4())
+        resp = client.delete(apibase+"/alarmSubscriptions/"+subscription_id1)
+        assert resp.status_code == 204
+
+
+def test_flask_not_allowed(mock_flask_uow):
+    _, app = mock_flask_uow
+    apibase = config.get_o2ims_monitoring_api_base()
+
+    with app.test_client() as client:
+        # Testing resource type not support method
+        ##########################
+        uri = apibase + "/alarms"
+        resp = client.post(uri)
+        assert resp.status == '405 METHOD NOT ALLOWED'
+        resp = client.put(uri)
+        assert resp.status == '405 METHOD NOT ALLOWED'
+        resp = client.patch(uri)
+        assert resp.status == '405 METHOD NOT ALLOWED'
+        resp = client.delete(uri)
+        assert resp.status == '405 METHOD NOT ALLOWED'
+
+
+class FakeAlarmClient(BaseClient):
+    def __init__(self):
+        super().__init__()
+        fakeAlarm = alarm_obj.FaultGenericModel(ResourceTypeEnum.OCLOUD)
+        fakeAlarm.id = str(uuid.uuid4())
+        fakeAlarm.name = 'alarm'
+        fakeAlarm.content = json.dumps({})
+        fakeAlarm.createtime = datetime.now()
+        fakeAlarm.updatetime = datetime.now()
+        fakeAlarm.hash = str(hash((fakeAlarm.id, fakeAlarm.updatetime)))
+        self.fakeAlarm = fakeAlarm
+
+    def _get(self, id) -> alarm_obj.FaultGenericModel:
+        return self.fakeAlarm
+
+    def _list(self):
+        return [self.fakeAlarm]
+
+    def _set_stx_client(self):
+        pass
+
+
+# class FakeStxObjRepo(StxObjectRepository):
+#     def __init__(self):
+#         super().__init__()
+#         self.alarms = []
+
+#     def _add(self, alarm: alarm_obj.AlarmEventRecord):
+#         self.alarms.append(alarm)
+
+#     def _get(self, alarmid) -> alarm_obj.AlarmEventRecord:
+#         filtered = [a for a in self.alarms if a.id == alarmid]
+#         return filtered.pop()
+
+#     def _list(self) -> List[alarm_obj.AlarmEventRecord]:
+#         return [x for x in self.oclouds]
+
+#     def _update(self, alarm: alarm_obj.AlarmEventRecord):
+#         filtered = [a for a in self.alarms if a.id == alarm.id]
+#         assert len(filtered) == 1
+#         ocloud1 = filtered.pop()
+#         ocloud1.update_by(alarm)
+
+
+class FakeUnitOfWork(AbstractUnitOfWork):
+    def __init__(self, session_factory=None):
+        self.session_factory = session_factory
+
+    def __enter__(self):
+        self.session = self.session_factory
+        # self.stxobjects = FakeStxObjRepo()
+        return super().__enter__()
+
+    def __exit__(self, *args):
+        super().__exit__(*args)
+        # self.session.close()
+
+    def _commit(self):
+        pass
+        # self.session.commit()
+
+    def rollback(self):
+        pass
+        # self.session.rollback()
+
+    def collect_new_events(self):
+        yield
+        # return super().collect_new_events()
+
+
+def create_alarm_fake_bus(uow):
+    def update_alarm(
+            cmd: commands.UpdateAlarm,
+            uow: AbstractUnitOfWork,
+            publish: Callable):
+        return
+
+    handlers.EVENT_HANDLERS = {}
+    handlers.COMMAND_HANDLERS = {
+        commands.UpdateAlarm: update_alarm,
+    }
+    bus = bootstrap.bootstrap(False, uow)
+    return bus
+
+
+def test_probe_new_alarm():
+    session = MagicMock()
+    session.return_value.execute.return_value = []
+    fakeuow = FakeUnitOfWork(session)
+    bus = create_alarm_fake_bus(fakeuow)
+    fakeClient = FakeAlarmClient()
+    alarmwatcher = AlarmWatcher(fakeClient, bus)
+    cmds = alarmwatcher.probe()
+    assert cmds is not None
+    assert len(cmds) == 1
+    assert cmds[0].data.name == "alarm"
+    # assert len(fakeuow.stxobjects.oclouds) == 1
+    # assert fakeuow.stxobjects.oclouds[0].name == "stx1"
+
+
+def test_watchers_worker():
+    testedworker = worker.PollWorker()
+
+    class FakeAlarmWatcher(BaseWatcher):
+        def __init__(self, client: BaseClient,
+                     bus: messagebus) -> None:
+            super().__init__(client, None)
+            self.fakeOcloudWatcherCounter = 0
+            self._client = client
+            self._bus = bus
+
+        def _targetname(self):
+            return "fakealarmwatcher"
+
+        def _probe(self, parent: object = None, tags=None):
+            # import pdb; pdb.set_trace()
+            self.fakeOcloudWatcherCounter += 1
+            # hacking to stop the blocking sched task
+            if self.fakeOcloudWatcherCounter > 2:
+                testedworker.stop()
+            return []
+
+    # fakeRepo = FakeOcloudRepo()
+    fakeuow = FakeUnitOfWork()
+    bus = create_alarm_fake_bus(fakeuow)
+
+    fakeClient = FakeAlarmClient()
+    fakewatcher = FakeAlarmWatcher(fakeClient, bus)
+
+    root = WatcherTree(fakewatcher)
+
+    testedworker.set_interval(1)
+    testedworker.add_watcher(root)
+    assert fakewatcher.fakeOcloudWatcherCounter == 0
+
+    count1 = fakewatcher.fakeOcloudWatcherCounter
+    testedworker.start()
+    time.sleep(20)
+    assert fakewatcher.fakeOcloudWatcherCounter > count1
+
+    # assumed hacking: probe has stopped the sched task
+    count3 = fakewatcher.fakeOcloudWatcherCounter
+    time.sleep(3)
+    assert fakewatcher.fakeOcloudWatcherCounter == count3
index 3359230..a29c2a6 100644 (file)
@@ -14,7 +14,7 @@
 
 import uuid
 from unittest.mock import MagicMock
-from o2dms.domain import dms
+from o2dms.domain import dms
 
 from o2ims.domain import ocloud, subscription_obj, configuration_obj
 from o2ims.domain import resource_type as rt
index 99c4fde..96d53f7 100644 (file)
@@ -94,19 +94,19 @@ def test_flask_get_one(mock_flask_uow):
         assert resp.status_code == 404
 
 
-def test_flask_post(mock_flask_uow):
-    session, app = mock_flask_uow
-    apibase = config.get_provision_api_base()
-
-    with app.test_client() as client:
-        session.return_value.execute.return_value = []
-
-        conf_callback = 'http://registration/callback/url'
-        resp = client.post(apibase+'/smo-endpoint', json={
-            'endpoint': conf_callback
-        })
-        assert resp.status_code == 201
-        assert 'id' in resp.get_json()
+def test_flask_post(mock_flask_uow):
+    session, app = mock_flask_uow
+    apibase = config.get_provision_api_base()
+
+    with app.test_client() as client:
+        session.return_value.execute.return_value = []
+
+        conf_callback = 'http://registration/callback/url'
+        resp = client.post(apibase+'/smo-endpoint', json={
+            'endpoint': conf_callback
+        })
+        assert resp.status_code == 201
+        assert 'id' in resp.get_json()
 
 
 def test_flask_delete(mock_flask_uow):