Adds vdu, ns, threshold and operation info to alarm notification 71/6171/2
authorBenjamin Diaz <bdiaz@whitestack.com>
Thu, 17 May 2018 22:02:24 +0000 (19:02 -0300)
committerBenjamin Diaz <bdiaz@whitestack.com>
Fri, 18 May 2018 14:49:51 +0000 (11:49 -0300)
Signed-off-by: Benjamin Diaz <bdiaz@whitestack.com>
Change-Id: Icbdfa11fa81bfda664e98d3cfc365ef1389fac46

docker/Dockerfile
docker/scripts/runInstall.sh
osm_mon/core/database.py
osm_mon/core/message_bus/common_consumer.py
osm_mon/core/models/notify_alarm.json
osm_mon/plugins/OpenStack/Aodh/alarming.py
osm_mon/plugins/OpenStack/Aodh/notifier.py
osm_mon/plugins/OpenStack/response.py
osm_mon/plugins/vRealiseOps/vROPs_Webservice/install.sh
osm_mon/test/OpenStack/integration/test_alarm_integration.py
osm_mon/test/OpenStack/unit/test_alarm_req.py

index b07f781..4b77102 100644 (file)
@@ -26,7 +26,7 @@ LABEL authors="Guillermo Calvino"
 
 RUN apt-get --yes update \
  && apt-get --yes install git python python-pip python3 python3-pip libmysqlclient-dev libssl-dev libffi-dev \
- && pip install pip==9.0.3
+ && pip3 install pip==9.0.3
 
 COPY requirements.txt /mon/requirements.txt
 
index 611bbe8..a5231ba 100755 (executable)
@@ -21,6 +21,6 @@
 # contact: bdiaz@whitestack.com or glavado@whitestack.com
 ##
 /bin/bash /mon/osm_mon/plugins/vRealiseOps/vROPs_Webservice/install.sh
-nohup python3 /mon/osm_mon/plugins/OpenStack/Aodh/notifier.py &
+python3 /mon/osm_mon/plugins/OpenStack/Aodh/notifier.py &
 python3 /mon/osm_mon/core/message_bus/common_consumer.py
 
index 857e8e5..e763a5b 100644 (file)
@@ -54,6 +54,12 @@ class VimCredentials(BaseModel):
 
 class Alarm(BaseModel):
     alarm_id = CharField()
+    threshold = FloatField()
+    operation = CharField()
+    metric_name = CharField()
+    vdu_name = CharField()
+    vnf_member_index = CharField()
+    ns_id = CharField()
     credentials = ForeignKeyField(VimCredentials, backref='alarms')
 
 
@@ -83,12 +89,26 @@ class DatabaseManager:
             .where(VimCredentials.type == vim_type).get()
         return alarm.credentials
 
-    def save_alarm(self, alarm_id, vim_uuid):
+    def get_alarm(self, alarm_id, vim_type):
+        alarm = Alarm.select() \
+            .where(Alarm.alarm_id == alarm_id) \
+            .join(VimCredentials) \
+            .where(VimCredentials.type == vim_type).get()
+        return alarm
+
+    def save_alarm(self, alarm_id, vim_uuid, threshold=None, operation=None, metric_name=None, vdu_name=None,
+                   vnf_member_index=None, ns_id=None):
         """Saves alarm. If a record with same id and vim_uuid exists, overwrite it."""
         alarm = Alarm()
         alarm.alarm_id = alarm_id
         creds = VimCredentials.get(VimCredentials.uuid == vim_uuid)
         alarm.credentials = creds
+        alarm.threshold = threshold
+        alarm.operation = operation
+        alarm.metric_name = metric_name
+        alarm.vdu_name = vdu_name
+        alarm.vnf_member_index = vnf_member_index
+        alarm.ns_id = ns_id
         exists = Alarm.select(Alarm.alarm_id == alarm.alarm_id) \
             .join(VimCredentials) \
             .where(VimCredentials.uuid == vim_uuid)
index 69abee5..dc5816e 100755 (executable)
@@ -126,15 +126,16 @@ def main():
                 # TODO: Standardize all message models to avoid the need of figuring out where are certain fields
                 contains_list = False
                 list_index = None
-                ns_id = None
                 for k, v in six.iteritems(values):
                     if isinstance(v, dict):
                         if 'ns_id' in v:
-                            ns_id = v['ns_id']
                             contains_list = True
                             list_index = k
+                            break
                 if not contains_list and 'ns_id' in values:
                     ns_id = values['ns_id']
+                else:
+                    ns_id = values[list_index]['ns_id']
 
                 vnf_index = values[list_index]['vnf_member_index'] if contains_list else values['vnf_member_index']
 
index 1fcd18e..ae39a78 100644 (file)
     "description": { "type": "string" },
     "severity": { "type" : "string" },
     "status": { "type": "string" },
+    "operation": { "type": "string" },
+    "threshold_value": { "type": "string" },
+    "metric_name": { "type": "string" },
+    "ns_id": { "type": "string"},
+    "vnf_member_index": { "type": "integer"},
+    "vdu_name": { "type": "string"},
     "start_date": { "type": "string" },
     "update_date": { "type": "string" },
     "cancel_date": { "type": "string" }
index 7dd5d4b..13b6541 100644 (file)
@@ -31,23 +31,12 @@ from osm_mon.core.auth import AuthManager
 from osm_mon.core.database import DatabaseManager
 from osm_mon.core.message_bus.producer import KafkaProducer
 from osm_mon.core.settings import Config
+from osm_mon.plugins.OpenStack.Gnocchi.metrics import METRIC_MAPPINGS
 from osm_mon.plugins.OpenStack.common import Common
 from osm_mon.plugins.OpenStack.response import OpenStack_Response
 
 log = logging.getLogger(__name__)
 
-METRIC_MAPPINGS = {
-    "average_memory_utilization": "memory.percent",
-    "disk_read_ops": "disk.read.requests",
-    "disk_write_ops": "disk.write.requests",
-    "disk_read_bytes": "disk.read.bytes",
-    "disk_write_bytes": "disk.write.bytes",
-    "packets_dropped": "interface.if_dropped",
-    "packets_received": "interface.if_packets",
-    "packets_sent": "interface.if_packets",
-    "cpu_utilization": "cpu_util",
-}
-
 SEVERITIES = {
     "warning": "low",
     "minor": "low",
@@ -142,7 +131,15 @@ class Alarming(object):
             # Generate a valid response message, send via producer
             if alarm_status is True:
                 log.info("Alarm successfully created")
-                self._database_manager.save_alarm(alarm_id, vim_uuid)
+                self._database_manager.save_alarm(alarm_id,
+                                                  vim_uuid,
+                                                  alarm_details['threshold_value'],
+                                                  alarm_details['operation'].lower(),
+                                                  alarm_details['metric_name'].lower(),
+                                                  alarm_details['vdu_name'].lower(),
+                                                  alarm_details['vnf_member_index'].lower(),
+                                                  alarm_details['ns_id'].lower()
+                                                  )
             try:
                 resp_message = self._response.generate_response(
                     'create_alarm_response', status=alarm_status,
index f7d50a8..7a917d9 100644 (file)
@@ -44,7 +44,6 @@ sys.path.append(os.path.abspath(os.path.join(os.path.realpath(__file__), '..', '
 from osm_mon.core.database import DatabaseManager
 from osm_mon.core.message_bus.producer import KafkaProducer
 
-from osm_mon.plugins.OpenStack.common import Common
 from osm_mon.plugins.OpenStack.response import OpenStack_Response
 from osm_mon.core.settings import Config
 
@@ -91,42 +90,29 @@ class NotifierHandler(BaseHTTPRequestHandler):
             database_manager = DatabaseManager()
 
             alarm_id = values['alarm_id']
-            # Get vim_uuid associated to alarm
-            creds = database_manager.get_credentials_for_alarm_id(alarm_id, 'openstack')
-            auth_token = Common.get_auth_token(creds.uuid)
-            endpoint = Common.get_endpoint("alarming", creds.uuid)
-
-            # If authenticated generate and send response message
-            if auth_token is not None and endpoint is not None:
-                url = "{}/v2/alarms/%s".format(endpoint) % alarm_id
-
-                # Get the resource_id of the triggered alarm
-                result = Common.perform_request(
-                    url, auth_token, req_type="get")
-                alarm_details = json.loads(result.text)
-                gnocchi_rule = alarm_details['gnocchi_resources_threshold_rule']
-                resource_id = gnocchi_rule['resource_id']
-
-                # Process an alarm notification if resource_id is valid
-                if resource_id is not None:
-                    # Get date and time for response message
-                    a_date = time.strftime("%d-%m-%Y") + " " + time.strftime("%X")
-                    # Try generate and send response
-                    try:
-                        resp_message = response.generate_response(
-                            'notify_alarm', a_id=alarm_id,
-                            r_id=resource_id,
-                            sev=values['severity'], date=a_date,
-                            state=values['current'], vim_type="openstack")
-                        producer.notify_alarm(
-                            'notify_alarm', resp_message)
-                        log.info("Sent an alarm response to SO: %s", resp_message)
-                    except Exception as exc:
-                        log.exception("Couldn't notify SO of the alarm:")
-                else:
-                    log.warning("No resource_id for alarm; no SO response sent.")
-            else:
-                log.warning("Authentication failure; SO notification not sent.")
+            alarm = database_manager.get_alarm(alarm_id, 'openstack')
+            # Process an alarm notification if resource_id is valid
+            # Get date and time for response message
+            a_date = time.strftime("%d-%m-%Y") + " " + time.strftime("%X")
+            # Try generate and send response
+            try:
+                resp_message = response.generate_response(
+                    'notify_alarm', a_id=alarm_id,
+                    vdu_name=alarm.vdu_name,
+                    vnf_member_index=alarm.vnf_member_index,
+                    ns_id=alarm.ns_id,
+                    metric_name=alarm.metric_name,
+                    operation=alarm.operation,
+                    threshold_value=alarm.threshold,
+                    sev=values['severity'],
+                    date=a_date,
+                    state=values['current'])
+                producer.notify_alarm(
+                    'notify_alarm', resp_message)
+                log.info("Sent an alarm response to SO: %s", resp_message)
+            except Exception as exc:
+                log.exception("Couldn't notify SO of the alarm:")
+
         except:
             log.exception("Could not notify alarm.")
 
index c41f772..319e0bc 100644 (file)
@@ -161,8 +161,12 @@ class OpenStack_Response(object):
                              "schema_type": "notify_alarm",
                              "notify_details": {
                                  "alarm_uuid": kwargs['a_id'],
-                                 "resource_uuid": kwargs['r_id'],
-                                 "vim_type": kwargs['vim_type'],
+                                 "vdu_name": kwargs['vdu_name'],
+                                 "vnf_member_index": kwargs['vnf_member_index'],
+                                 "ns_id": kwargs['ns_id'],
+                                 "metric_name": kwargs['metric_name'],
+                                 "threshold_value": kwargs['threshold_value'],
+                                 "operation": kwargs['operation'],
                                  "severity": kwargs['sev'],
                                  "status": kwargs['state'],
                                  "start_date": kwargs['date']}}
index 669f0fb..2948ec3 100755 (executable)
@@ -58,7 +58,7 @@ apt-get update  # To get the latest package lists
 [ "$_DISTRO" == "CentOS" -o "$_DISTRO" == "Red" ] && easy_install -U bottle
 
 #required for vmware connector TODO move that to separete opt in install script
-pip install --upgrade pip
+pip install pip==9.0.3
 pip install cherrypy
 
 echo '
index b04019b..32532e1 100644 (file)
@@ -63,6 +63,10 @@ class AlarmIntegrationTest(unittest.TestCase):
         self.alarms = alarming.Alarming()
         self.openstack_auth = Common()
 
+    def tearDown(self):
+        self.producer.close()
+        self.req_consumer.close()
+
     @mock.patch.object(Common, "get_auth_token", mock.Mock())
     @mock.patch.object(Common, "get_endpoint", mock.Mock())
     @mock.patch.object(AuthManager, 'get_credentials')
@@ -113,7 +117,12 @@ class AlarmIntegrationTest(unittest.TestCase):
                         "alarm_name": "my_alarm",
                         "metric_name": "my_metric",
                         "resource_uuid": "my_resource",
-                        "severity": "WARNING"}}
+                        "severity": "WARNING",
+                        "threshold_value": 60,
+                        "operation": "GT",
+                        "vdu_name": "vdu",
+                        "vnf_member_index": "1",
+                        "ns_id": "1"}}
 
         get_creds.return_value = mock_creds
 
@@ -217,10 +226,12 @@ class AlarmIntegrationTest(unittest.TestCase):
                            value=json.dumps(payload))
 
         get_creds.return_value = mock_creds
+        ack_alarm.return_value = True
 
         for message in self.req_consumer:
             if message.key == "acknowledge_alarm":
                 self.alarms.alarming(message, 'test_id')
+                ack_alarm.assert_called_with(mock.ANY, mock.ANY, 'alarm_id')
                 return
 
         self.fail("No message received in consumer")
index 41b6836..0d2016b 100644 (file)
@@ -144,11 +144,19 @@ class TestAlarmKeys(unittest.TestCase):
         # Mock a message with config alarm key and value
         message = Message()
         message.key = 'create_alarm_request'
-        message.value = json.dumps({'alarm_create_request': {'correlation_id': 1}})
+        message.value = json.dumps({'alarm_create_request': {'correlation_id': 1, 'threshold_value': 50,
+                                                             'operation': 'GT', 'metric_name': 'cpu_utilization',
+                                                             'vdu_name': 'vdu',
+                                                             'vnf_member_index': '1',
+                                                             'ns_id': '1'}})
 
         get_creds.return_value = mock_creds
 
         # Call alarming functionality and check config alarm call
         config_alarm.return_value = 'my_alarm_id', True
         self.alarming.alarming(message, 'test_id')
-        config_alarm.assert_called_with(mock.ANY, mock.ANY, mock.ANY, {'correlation_id': 1}, {})
+        config_alarm.assert_called_with(mock.ANY, mock.ANY, mock.ANY, {'correlation_id': 1, 'threshold_value': 50,
+                                                                       'operation': 'GT',
+                                                                       'metric_name': 'cpu_utilization',
+                                                                       'vdu_name': 'vdu',
+                                                                       'vnf_member_index': '1', 'ns_id': '1'}, {})