From edbc4ae3d2f0aacd5e371b024ec21559e50da6fc Mon Sep 17 00:00:00 2001
From: Nikolay Stanchev <ns17@it-innovation.soton.ac.uk>
Date: Mon, 8 Oct 2018 10:37:19 +0100
Subject: [PATCH] Updates validation between resource specification and alerts
 specification

---
 .../clmcservice/alertsapi/utilities.py        |  7 +++++--
 src/service/clmcservice/alertsapi/views.py    | 21 ++++++++++++++-----
 .../valid/alerts_test_config-2.yaml           |  2 +-
 .../valid/alerts_test_config-3.yaml           | 17 +++++++++++++++
 .../valid/alerts_test_config-4.yaml           |  3 ++-
 .../valid/alerts_test_config-5.yaml           |  2 +-
 .../alerts/resources_test_config.yaml         |  9 --------
 7 files changed, 42 insertions(+), 19 deletions(-)

diff --git a/src/service/clmcservice/alertsapi/utilities.py b/src/service/clmcservice/alertsapi/utilities.py
index 68dff5e..53a144b 100644
--- a/src/service/clmcservice/alertsapi/utilities.py
+++ b/src/service/clmcservice/alertsapi/utilities.py
@@ -31,6 +31,7 @@ from yaml import load
 
 # CLMC-service imports
 from clmcservice import ROOT_DIR
+from clmcservice.alertsapi.alerts_specification_schema import SFEMC
 
 
 CLMC_ALERTS_TOSCA_DEFINITIONS_REL_PATH = ["static", "flame_clmc_alerts_definitions.yaml"]
@@ -106,8 +107,10 @@ def get_alert_spec_policy_triggers(alerts_spec_tpl):
         for trigger in policy.triggers:
             trigger_id = trigger.name
 
-            policy_trigger_string = "{0}\n{1}".format(policy_id, trigger_id)
-            policy_trigger_ids.append(policy_trigger_string)
+            # only include those triggers that actually POST to SFEMC
+            if SFEMC in trigger.trigger_tpl["action"]["implementation"]:
+                policy_trigger_string = "{0}\n{1}".format(policy_id, trigger_id)
+                policy_trigger_ids.append(policy_trigger_string)
 
     return policy_trigger_ids
 
diff --git a/src/service/clmcservice/alertsapi/views.py b/src/service/clmcservice/alertsapi/views.py
index 7919c02..72681ac 100644
--- a/src/service/clmcservice/alertsapi/views.py
+++ b/src/service/clmcservice/alertsapi/views.py
@@ -100,15 +100,20 @@ class AlertsConfigurationAPI(object):
 
         alert_spec_reference = self.request.POST.get('alert-spec')
         resource_spec_reference = self.request.POST.get('resource-spec')
+
+        # check that the resource specification file was sent
+        if not hasattr(resource_spec_reference, "file") or not hasattr(resource_spec_reference, "filename"):
+            raise HTTPBadRequest("Request to this API endpoint must include a (YAML) file input referenced as 'resource-spec' representing the TOSCA Resource Specification.")
+
         try:
             resource_spec_sfc, resource_spec_sfc_i, resource_spec_policy_triggers = get_resource_spec_policy_triggers(resource_spec_reference)
         except Exception as e:
             log.error("Couldn't extract resource specification event IDs due to error: {0}".format(e))
             raise HTTPBadRequest("Couldn't extract resource specification event IDs - invalid TOSCA resource specification.")
 
-        # check that the specification file was sent
+        # check that the alerts specification file was sent
         if not hasattr(alert_spec_reference, "file") or not hasattr(alert_spec_reference, "filename"):
-            raise HTTPBadRequest("Request to this API endpoint must include a (YAML) file input referenced as 'alert-spec' representing the TOSCA Alerts Specification.")
+            raise HTTPBadRequest("Request to this API endpoint must include a (YAML) file input referenced as 'alert-spec' representing the TOSCA Alert Specification.")
 
         # extract alert specification file and filename
         alerts_input_filename = alert_spec_reference.filename
@@ -185,12 +190,18 @@ class AlertsConfigurationAPI(object):
             raise HTTPBadRequest("Different service function chain instance ID used in the alert and resource specification documents: {0} != {1}".format(alert_spec_sfc_instance, resource_spec_sfc_instance))
 
         alert_spec_triggers_set = set(alert_spec_policy_triggers)
-        missing_policy_triggers = [policy_trigger_id for policy_trigger_id in resource_spec_policy_triggers if policy_trigger_id not in alert_spec_triggers_set]
+        resource_spec_triggers_set = set(resource_spec_policy_triggers)
 
+        # check for triggers defined in the resource specification but missing in the alerts specification
+        missing_policy_triggers = [policy_trigger_id.replace("\n", " : ") for policy_trigger_id in resource_spec_policy_triggers if policy_trigger_id not in alert_spec_triggers_set]
         if len(missing_policy_triggers) > 0:
-            missing_policy_triggers = [policy_trigger_id.replace("\n", " : ") for policy_trigger_id in missing_policy_triggers]
             raise HTTPBadRequest("Couldn't match the following policy triggers from the resource specification with triggers defined in the alerts specification: {0}".format(missing_policy_triggers))
 
+        # check for triggers defined in the alerts specification and posting to flame_sfemc, but missing in the resource specification
+        missing_policy_triggers = [policy_trigger_id.replace("\n", " : ") for policy_trigger_id in alert_spec_policy_triggers if policy_trigger_id not in resource_spec_triggers_set]
+        if len(missing_policy_triggers) > 0:
+            raise HTTPBadRequest("Couldn't match the following policy triggers from the alerts specification with triggers defined in the resource specification: {0}".format(missing_policy_triggers))
+
     def _config_kapacitor_alerts(self, tosca_tpl, sfc, sfc_instance, db, kapacitor_host, kapacitor_port, resource_spec_policy_triggers, alert_tasks_errors, alert_handlers_errors):
         """
         Configures the alerts task and alert handlers within Kapacitor.
@@ -212,7 +223,7 @@ class AlertsConfigurationAPI(object):
             for trigger in policy.triggers:
                 event_id = trigger.name
                 policy_id = policy.name
-                resource_spec_trigger_id = resource_spec_policy_triggers["{0}\n{1}".format(policy_id, event_id)]
+                resource_spec_trigger_id = resource_spec_policy_triggers.get("{0}\n{1}".format(policy_id, event_id))
 
                 event_type = trigger.trigger_tpl["event_type"]
                 template_id = "{0}-template".format(event_type)
diff --git a/src/service/resources/tosca/test-data/clmc-validator/valid/alerts_test_config-2.yaml b/src/service/resources/tosca/test-data/clmc-validator/valid/alerts_test_config-2.yaml
index e618469..9dc4288 100644
--- a/src/service/resources/tosca/test-data/clmc-validator/valid/alerts_test_config-2.yaml
+++ b/src/service/resources/tosca/test-data/clmc-validator/valid/alerts_test_config-2.yaml
@@ -49,4 +49,4 @@ topology_template:
                 flame_sfp: storage
             action:
               implementation:
-                - http://sfemc.flame.eu/notify
\ No newline at end of file
+                - flame_sfemc
\ No newline at end of file
diff --git a/src/service/resources/tosca/test-data/clmc-validator/valid/alerts_test_config-3.yaml b/src/service/resources/tosca/test-data/clmc-validator/valid/alerts_test_config-3.yaml
index d8fa6e8..ed21a67 100644
--- a/src/service/resources/tosca/test-data/clmc-validator/valid/alerts_test_config-3.yaml
+++ b/src/service/resources/tosca/test-data/clmc-validator/valid/alerts_test_config-3.yaml
@@ -50,3 +50,20 @@ topology_template:
               implementation:
                 - flame_sfemc
                 - http://companyA.alert-handler.flame.eu/low-requests
+    - missing_measurement_policy:
+        type: eu.ict-flame.policies.StateChange
+        triggers:
+          missing_storage_measurements:
+            description: This event triggers when the number of storage measurements reported falls below the threshold value.
+            event_type: deadman
+            # deadman trigger instances monitor the whole measurement (storage in this case), so simply put a star for field value
+            # to be compliant with the <measurement>.<field> format
+            metric: storage.*
+            condition:
+              threshold: 0  # if requests are less than or equal to 0 (in other words, no measurements are reported)
+              granularity: 60  # check for for missing data for the last 60 seconds
+              resource_type:
+                flame_sfp: storage
+            action:
+              implementation:
+              - http://companyA.alert-handler.flame.eu/no-measurements
diff --git a/src/service/resources/tosca/test-data/clmc-validator/valid/alerts_test_config-4.yaml b/src/service/resources/tosca/test-data/clmc-validator/valid/alerts_test_config-4.yaml
index 849f037..04a8ed3 100644
--- a/src/service/resources/tosca/test-data/clmc-validator/valid/alerts_test_config-4.yaml
+++ b/src/service/resources/tosca/test-data/clmc-validator/valid/alerts_test_config-4.yaml
@@ -29,7 +29,7 @@ topology_template:
               comparison_operator: neq
             action:
               implementation:
-                - http://sfemc.flame.eu/notify
+                - flame_sfemc
                 - http://companyA.alert-handler.flame.eu/high-latency
     - low_requests_policy:
         type: eu.ict-flame.policies.StateChange
@@ -65,4 +65,5 @@ topology_template:
               comparison_operator: gte # although events of type deadman do not use a comparison operator, the validator will not complain if one is given, it will simply ignore it
             action:
               implementation:
+              - flame_sfemc
               - http://companyA.alert-handler.flame.eu/missing_measurements
diff --git a/src/service/resources/tosca/test-data/clmc-validator/valid/alerts_test_config-5.yaml b/src/service/resources/tosca/test-data/clmc-validator/valid/alerts_test_config-5.yaml
index a341c6c..06dc554 100644
--- a/src/service/resources/tosca/test-data/clmc-validator/valid/alerts_test_config-5.yaml
+++ b/src/service/resources/tosca/test-data/clmc-validator/valid/alerts_test_config-5.yaml
@@ -45,7 +45,7 @@ topology_template:
               comparison_operator: lt
             action:
               implementation:
-                - https://sfemc.flame.eu/notify
+                - flame_sfemc
                 - http://localhost:9999/low-requests  # localhost url is also allowed
     - requests_diff_policy:
         type: eu.ict-flame.policies.StateChange
diff --git a/src/test/clmctest/alerts/resources_test_config.yaml b/src/test/clmctest/alerts/resources_test_config.yaml
index 061c227..161ab8b 100644
--- a/src/test/clmctest/alerts/resources_test_config.yaml
+++ b/src/test/clmctest/alerts/resources_test_config.yaml
@@ -74,15 +74,6 @@ topology_template:
         properties:
           parent: service_paid
         triggers:
-          tigger_a:
-            condition:
-              constraint: clmc::high_requests
-            action:
-              frontend:
-                -
-                  fqdn: frontend.app.ict-flame.eu
-                  lifecycle_actions:
-                    Bristol: eu.ict-flame.sfe.state.lifecycle.connected
           tigger_b:
             condition:
               constraint: clmc::increase_in_running_processes
-- 
GitLab