From: Benjamin Diaz Date: Thu, 17 May 2018 22:02:24 +0000 (-0300) Subject: Adds vdu, ns, threshold and operation info to alarm notification X-Git-Tag: v4.0.0~2 X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=ffe5a8e4e35d3fc7860eb9231618dc0e84e448b7;p=osm%2FMON.git Adds vdu, ns, threshold and operation info to alarm notification Signed-off-by: Benjamin Diaz Change-Id: Icbdfa11fa81bfda664e98d3cfc365ef1389fac46 --- diff --git a/docker/Dockerfile b/docker/Dockerfile index b07f781..4b77102 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -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 diff --git a/docker/scripts/runInstall.sh b/docker/scripts/runInstall.sh index 611bbe8..a5231ba 100755 --- a/docker/scripts/runInstall.sh +++ b/docker/scripts/runInstall.sh @@ -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 diff --git a/osm_mon/core/database.py b/osm_mon/core/database.py index 857e8e5..e763a5b 100644 --- a/osm_mon/core/database.py +++ b/osm_mon/core/database.py @@ -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) diff --git a/osm_mon/core/message_bus/common_consumer.py b/osm_mon/core/message_bus/common_consumer.py index 69abee5..dc5816e 100755 --- a/osm_mon/core/message_bus/common_consumer.py +++ b/osm_mon/core/message_bus/common_consumer.py @@ -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'] diff --git a/osm_mon/core/models/notify_alarm.json b/osm_mon/core/models/notify_alarm.json index 1fcd18e..ae39a78 100644 --- a/osm_mon/core/models/notify_alarm.json +++ b/osm_mon/core/models/notify_alarm.json @@ -28,6 +28,12 @@ "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" } diff --git a/osm_mon/plugins/OpenStack/Aodh/alarming.py b/osm_mon/plugins/OpenStack/Aodh/alarming.py index 7dd5d4b..13b6541 100644 --- a/osm_mon/plugins/OpenStack/Aodh/alarming.py +++ b/osm_mon/plugins/OpenStack/Aodh/alarming.py @@ -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, diff --git a/osm_mon/plugins/OpenStack/Aodh/notifier.py b/osm_mon/plugins/OpenStack/Aodh/notifier.py index f7d50a8..7a917d9 100644 --- a/osm_mon/plugins/OpenStack/Aodh/notifier.py +++ b/osm_mon/plugins/OpenStack/Aodh/notifier.py @@ -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.") diff --git a/osm_mon/plugins/OpenStack/response.py b/osm_mon/plugins/OpenStack/response.py index c41f772..319e0bc 100644 --- a/osm_mon/plugins/OpenStack/response.py +++ b/osm_mon/plugins/OpenStack/response.py @@ -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']}} diff --git a/osm_mon/plugins/vRealiseOps/vROPs_Webservice/install.sh b/osm_mon/plugins/vRealiseOps/vROPs_Webservice/install.sh index 669f0fb..2948ec3 100755 --- a/osm_mon/plugins/vRealiseOps/vROPs_Webservice/install.sh +++ b/osm_mon/plugins/vRealiseOps/vROPs_Webservice/install.sh @@ -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 ' diff --git a/osm_mon/test/OpenStack/integration/test_alarm_integration.py b/osm_mon/test/OpenStack/integration/test_alarm_integration.py index b04019b..32532e1 100644 --- a/osm_mon/test/OpenStack/integration/test_alarm_integration.py +++ b/osm_mon/test/OpenStack/integration/test_alarm_integration.py @@ -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") diff --git a/osm_mon/test/OpenStack/unit/test_alarm_req.py b/osm_mon/test/OpenStack/unit/test_alarm_req.py index 41b6836..0d2016b 100644 --- a/osm_mon/test/OpenStack/unit/test_alarm_req.py +++ b/osm_mon/test/OpenStack/unit/test_alarm_req.py @@ -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'}, {})