From 9677cd53b9d597e4bafd47a1aa290921ea5d4c5a Mon Sep 17 00:00:00 2001 From: Sundaresan Rajangam Date: Tue, 2 Aug 2016 22:33:44 -0700 Subject: [PATCH] Change in schema for operand2 in alarm config - operand2 in AlarmExpression can be either a uve attribute or a json value. Presently, it is defined as a string. Schema of operand2 has been changed to make it explicit that operand2 can take either uve attribute or json value. Closes-Bug: #1607030 Presently, severity level for alarm is 0-7. Restricted the severity level to 0-2 (0- critical, 1 - major, 2 - minor) Change-Id: I3cfe2d987da023976f674a2c8c4c21e216a7d994 Closes-Bug: #1606676 --- src/config/api-server/vnc_cfg_types.py | 33 +++- src/opserver/alarmgen.py | 24 ++- src/opserver/alarmgen_config_handler.py | 7 +- .../plugins/alarm_address_mismatch/main.py | 17 +- src/opserver/plugins/alarm_base.py | 7 +- .../plugins/alarm_bgp_connectivity/main.py | 10 +- .../plugins/alarm_config_incorrect/main.py | 6 +- src/opserver/plugins/alarm_disk_usage/main.py | 6 +- .../plugins/alarm_node_status/main.py | 6 +- .../plugins/alarm_partial_sysinfo/main.py | 18 +- .../plugins/alarm_phyif_bandwidth/main.py | 16 +- .../alarm_process_connectivity/main.py | 10 +- .../plugins/alarm_process_status/main.py | 10 +- .../alarm_prouter_connectivity/main.py | 18 +- src/opserver/plugins/alarm_storage/main.py | 6 +- .../plugins/alarm_vrouter_interface/main.py | 6 +- .../plugins/alarm_xmpp_connectivity/main.py | 10 +- src/opserver/test/test_alarm.py | 178 ++++++++++++------ src/opserver/test/test_alarm_plugins.py | 25 ++- .../test/test_alarmgen_config_handler.py | 10 +- src/opserver/test/test_analytics_uve.py | 6 +- src/opserver/test/utils/generator_fixture.py | 16 +- src/schema/alarm.xsd | 11 +- 23 files changed, 311 insertions(+), 145 deletions(-) diff --git a/src/config/api-server/vnc_cfg_types.py b/src/config/api-server/vnc_cfg_types.py index 00624f62e09..a8878fed3cd 100644 --- a/src/config/api-server/vnc_cfg_types.py +++ b/src/config/api-server/vnc_cfg_types.py @@ -2010,24 +2010,53 @@ def pre_dbe_update(cls, id, fq_name, obj_dict, db_conn, **kwargs): return (True, '') # end class ForwardingClassServer + class AlarmServer(Resource, Alarm): @classmethod def pre_dbe_create(cls, tenant_name, obj_dict, db_conn): if 'alarm_rules' not in obj_dict or obj_dict['alarm_rules'] is None: return (False, (400, 'alarm_rules not specified or null')) + (ok, error) = cls._check_alarm_rules(obj_dict['alarm_rules']) + if not ok: + return (False, error) return True, '' # end pre_dbe_create @classmethod def pre_dbe_update(cls, id, fq_name, obj_dict, db_conn, **kwargs): - if 'alarm_rules' in obj_dict and obj_dict['alarm_rules'] is None: - return (False, (400, 'alarm_rules cannot be removed')) + if 'alarm_rules' in obj_dict: + if obj_dict['alarm_rules'] is None: + return (False, (400, 'alarm_rules cannot be removed')) + (ok, error) = cls._check_alarm_rules(obj_dict['alarm_rules']) + if not ok: + return (False, error) return True, '' # end pre_dbe_update + @classmethod + def _check_alarm_rules(cls, alarm_rules): + try: + for and_list in alarm_rules['or_list']: + for and_cond in and_list['and_list']: + if 'json_value' in and_cond['operand2']: + if 'uve_attribute' in and_cond['operand2']: + return (False, (400, 'operand2 should have either ' + '"uve_attribute" or "json_value", not both')) + try: + json.loads(and_cond['operand2']['json_value']) + except ValueError: + return (False, (400, 'Invalid json_value %s ' + 'specified in alarm_rules' % + (and_cond['operand2']['json_value']))) + except Exception as e: + return (False, (400, 'Invalid alarm_rules')) + return (True, '') + # end _check_alarm_rules + # end class AlarmServer + class QosConfigServer(Resource, QosConfig): @classmethod def _check_qos_values(cls, obj_dict, db_conn): diff --git a/src/opserver/alarmgen.py b/src/opserver/alarmgen.py index 9e3be6c4f12..29194b17cb0 100644 --- a/src/opserver/alarmgen.py +++ b/src/opserver/alarmgen.py @@ -30,8 +30,8 @@ from pysandesh.sandesh_logger import SandeshLogger from pysandesh.gen_py.sandesh_alarm.ttypes import SandeshAlarmAckResponseCode from sandesh.alarmgen_ctrl.sandesh_alarm_base.ttypes import AlarmTrace, \ - UVEAlarms, UVEAlarmInfo, UVEAlarmConfig, AlarmCondition, AlarmMatch, \ - AlarmConditionMatch, AlarmAndList, AlarmRules + UVEAlarms, UVEAlarmInfo, UVEAlarmConfig, AlarmOperand2, AlarmCondition, \ + AlarmMatch, AlarmConditionMatch, AlarmAndList, AlarmRules from sandesh.analytics.ttypes import * from sandesh.nodeinfo.ttypes import NodeStatusUVE, NodeStatus from sandesh.nodeinfo.cpuinfo.ttypes import * @@ -288,7 +288,8 @@ def _get_json_variables(self, uve, exp, operand1_val, var_val = \ operand1_val['parent_attr'].get(var.rsplit('.', 1)[1]) elif not is_operand2_json_val and \ - var.rsplit('.', 1)[0] == exp.operand2.rsplit('.', 1)[0]: + var.rsplit('.', 1)[0] == exp.operand2.uve_attribute.rsplit( + '.', 1)[0]: var_val = \ operand2_val['parent_attr'].get(var.rsplit('.', 1)[1]) else: @@ -342,7 +343,7 @@ def _get_alarm_match(self, uve, exp, operand1_val, operand2_val, else: json_operand2_val = None return AlarmMatch(json_operand1_value=json_operand1_val, - json_operand2_value=json_operand2_val, json_vars=json_vars) + json_operand2_value=json_operand2_val, json_variables=json_vars) # end _get_alarm_match def _get_alarm_condition_match(self, uve, exp, operand1_val, operand2_val, @@ -352,8 +353,10 @@ def _get_alarm_condition_match(self, uve, exp, operand1_val, operand2_val, operand2_val, is_operand2_json_val)] return AlarmConditionMatch( condition=AlarmCondition(operation=exp.operation, - operand1=exp.operand1, operand2=exp.operand2, - vars=exp.variables), + operand1=exp.operand1, operand2=AlarmOperand2( + uve_attribute=exp.operand2.uve_attribute, + json_value=exp.operand2.json_value), + variables=exp.variables), match=match_list) # end _get_alarm_condition_match @@ -375,11 +378,12 @@ def _evaluate_uve_for_alarms(self, alarm_cfg, uve_key, uve): operand1_val['status'] is False: and_list_fail = True break - try: - operand2_val = json.loads(exp.operand2) + if exp.operand2.json_value is not None: + operand2_val = json.loads(exp.operand2.json_value) is_operand2_json_val = True - except ValueError: - operand2_val = self._get_operand_value(uve, exp.operand2) + else: + operand2_val = self._get_operand_value(uve, + exp.operand2.uve_attribute) if isinstance(operand2_val, dict) and \ operand2_val['status'] is False: and_list_fail = True diff --git a/src/opserver/alarmgen_config_handler.py b/src/opserver/alarmgen_config_handler.py index 384a692a6a7..83f3e7d46ed 100644 --- a/src/opserver/alarmgen_config_handler.py +++ b/src/opserver/alarmgen_config_handler.py @@ -7,7 +7,7 @@ from vnc_api.gen.resource_client import Alarm from vnc_api.gen.resource_xsd import IdPermsType, AlarmExpression, \ - AlarmAndList, AlarmOrList, UveKeysType + AlarmOperand2, AlarmAndList, AlarmOrList, UveKeysType from pysandesh.gen_py.sandesh.ttypes import SandeshLevel from config_handler import ConfigHandler from opserver_util import camel_case_to_hyphen, inverse_dict @@ -102,7 +102,10 @@ def _create_inbuilt_alarms_config(self): alarm_and_list.append(AlarmExpression( operation=exp['operation'], operand1=exp['operand1'], - operand2=exp['operand2'], + operand2=AlarmOperand2(uve_attribute= + exp['operand2'].get('uve_attribute'), + json_value=exp['operand2'].get( + 'json_value')), variables=exp.get('variables'))) alarm_or_list.append(AlarmAndList(alarm_and_list)) desc = ' '.join([l.strip() \ diff --git a/src/opserver/plugins/alarm_address_mismatch/main.py b/src/opserver/plugins/alarm_address_mismatch/main.py index 07ab4b4ea71..313becd29fd 100644 --- a/src/opserver/plugins/alarm_address_mismatch/main.py +++ b/src/opserver/plugins/alarm_address_mismatch/main.py @@ -14,7 +14,9 @@ class AddressMismatchCompute(AlarmBase): 'operand1': 'ContrailConfig.elements.' + \ 'virtual_router_ip_address', 'operation': 'not in', - 'operand2': 'VrouterAgent.self_ip_list' + 'operand2': { + 'uve_attribute': 'VrouterAgent.self_ip_list' + } } ] }, @@ -24,7 +26,9 @@ class AddressMismatchCompute(AlarmBase): 'operand1': 'ContrailConfig.elements.' + \ 'virtual_router_ip_address', 'operation': '!=', - 'operand2': 'VrouterAgent.control_ip' + 'operand2': { + 'uve_attribute': 'VrouterAgent.control_ip' + } } ] } @@ -32,7 +36,7 @@ class AddressMismatchCompute(AlarmBase): } def __init__(self): - AlarmBase.__init__(self, AlarmBase.SYS_ERR) + AlarmBase.__init__(self, AlarmBase.ALARM_MAJOR) class AddressMismatchControl(AlarmBase): @@ -48,7 +52,10 @@ class AddressMismatchControl(AlarmBase): 'operand1': 'ContrailConfig.elements.' + \ 'bgp_router_parameters.address', 'operation': 'not in', - 'operand2': 'BgpRouterState.bgp_router_ip_list' + 'operand2': { + 'uve_attribute': + 'BgpRouterState.bgp_router_ip_list' + } } ] } @@ -56,4 +63,4 @@ class AddressMismatchControl(AlarmBase): } def __init__(self): - AlarmBase.__init__(self, AlarmBase.SYS_ERR) + AlarmBase.__init__(self, AlarmBase.ALARM_MAJOR) diff --git a/src/opserver/plugins/alarm_base.py b/src/opserver/plugins/alarm_base.py index de4f5e1deaf..a01ed948929 100644 --- a/src/opserver/plugins/alarm_base.py +++ b/src/opserver/plugins/alarm_base.py @@ -5,14 +5,13 @@ class AlarmBase(object): """Base class for Alarms """ - SYS_EMERG, SYS_ALERT, SYS_CRIT, SYS_ERR,\ - SYS_WARN, SYS_NOTICE, SYS_INFO, SYS_DEBUG = range(8) + ALARM_CRITICAL, ALARM_MAJOR, ALARM_MINOR = range(3) _RULES = None def __init__(self, sev=None, at=0, it=0, fec=False, fcs=0, fct=0, config=None): - self._sev = sev or self.SYS_ERR + self._sev = sev or self.ALARM_MAJOR self._ActiveTimer = at self._IdleTimer = it self._FreqExceededCheck = fec @@ -89,5 +88,5 @@ def is_enabled(self): alarm processing engine. :param uve_key: Key of the UVE (a string) :param uve_data: UVE Contents - :returns: list of AlarmRuleMatch + :returns: list of AlarmAndList """ diff --git a/src/opserver/plugins/alarm_bgp_connectivity/main.py b/src/opserver/plugins/alarm_bgp_connectivity/main.py index 45d672ce8cd..861a7c0782e 100644 --- a/src/opserver/plugins/alarm_bgp_connectivity/main.py +++ b/src/opserver/plugins/alarm_bgp_connectivity/main.py @@ -12,7 +12,9 @@ class BgpConnectivity(AlarmBase): { 'operand1': 'BgpRouterState.num_up_bgp_peer', 'operation': '==', - 'operand2': 'null' + 'operand2': { + 'json_value': 'null' + } } ] }, @@ -21,7 +23,9 @@ class BgpConnectivity(AlarmBase): { 'operand1': 'BgpRouterState.num_up_bgp_peer', 'operation': '!=', - 'operand2': 'BgpRouterState.num_bgp_peer' + 'operand2': { + 'uve_attribute': 'BgpRouterState.num_bgp_peer' + } } ] } @@ -29,4 +33,4 @@ class BgpConnectivity(AlarmBase): } def __init__(self): - AlarmBase.__init__(self, AlarmBase.SYS_WARN) + AlarmBase.__init__(self, AlarmBase.ALARM_MAJOR) diff --git a/src/opserver/plugins/alarm_config_incorrect/main.py b/src/opserver/plugins/alarm_config_incorrect/main.py index 2b2d4d0ee88..d4504f90014 100644 --- a/src/opserver/plugins/alarm_config_incorrect/main.py +++ b/src/opserver/plugins/alarm_config_incorrect/main.py @@ -12,12 +12,14 @@ class ConfIncorrect(AlarmBase): { 'operand1': 'ContrailConfig', 'operation': '==', - 'operand2': 'null' + 'operand2': { + 'json_value': 'null' + } } ] } ] } - def __init__(self, sev = AlarmBase.SYS_ERR): + def __init__(self, sev = AlarmBase.ALARM_MAJOR): AlarmBase.__init__(self, sev) diff --git a/src/opserver/plugins/alarm_disk_usage/main.py b/src/opserver/plugins/alarm_disk_usage/main.py index 79a522745ce..e52b0b38ed4 100644 --- a/src/opserver/plugins/alarm_disk_usage/main.py +++ b/src/opserver/plugins/alarm_disk_usage/main.py @@ -13,7 +13,9 @@ class DiskUsage(AlarmBase): 'operand1': 'NodeStatus.disk_usage_info.' + \ 'percentage_partition_space_used', 'operation': '>=', - 'operand2': '90', + 'operand2': { + 'json_value': '90' + }, 'variables': \ ['NodeStatus.disk_usage_info.partition_name'] } @@ -23,4 +25,4 @@ class DiskUsage(AlarmBase): } def __init__(self): - AlarmBase.__init__(self, AlarmBase.SYS_ERR) + AlarmBase.__init__(self, AlarmBase.ALARM_CRITICAL) diff --git a/src/opserver/plugins/alarm_node_status/main.py b/src/opserver/plugins/alarm_node_status/main.py index d0fe9924ff6..42cc63d82d2 100644 --- a/src/opserver/plugins/alarm_node_status/main.py +++ b/src/opserver/plugins/alarm_node_status/main.py @@ -12,7 +12,9 @@ class NodeStatus(AlarmBase): { 'operand1': 'NodeStatus', 'operation': '==', - 'operand2': 'null' + 'operand2': { + 'json_value': 'null' + } } ] } @@ -20,4 +22,4 @@ class NodeStatus(AlarmBase): } def __init__(self): - AlarmBase.__init__(self, AlarmBase.SYS_CRIT) + AlarmBase.__init__(self, AlarmBase.ALARM_CRITICAL) diff --git a/src/opserver/plugins/alarm_partial_sysinfo/main.py b/src/opserver/plugins/alarm_partial_sysinfo/main.py index ab9c3d99449..15600f10a1c 100644 --- a/src/opserver/plugins/alarm_partial_sysinfo/main.py +++ b/src/opserver/plugins/alarm_partial_sysinfo/main.py @@ -4,7 +4,7 @@ class PartialSysinfo(AlarmBase): def __init__(self): - AlarmBase.__init__(self, AlarmBase.SYS_WARN) + AlarmBase.__init__(self, AlarmBase.ALARM_MAJOR) class PartialSysinfoCompute(PartialSysinfo): @@ -18,7 +18,9 @@ class PartialSysinfoCompute(PartialSysinfo): { 'operand1': 'VrouterAgent.build_info', 'operation': '==', - 'operand2': 'null' + 'operand2': { + 'json_value': 'null' + } } ] } @@ -37,7 +39,9 @@ class PartialSysinfoAnalytics(PartialSysinfo): { 'operand1': 'CollectorState.build_info', 'operation': '==', - 'operand2': 'null' + 'operand2': { + 'json_value': 'null' + } } ] } @@ -56,7 +60,9 @@ class PartialSysinfoConfig(PartialSysinfo): { 'operand1': 'ModuleCpuState.build_info', 'operation': '==', - 'operand2': 'null' + 'operand2': { + 'json_value': 'null' + } } ] } @@ -75,7 +81,9 @@ class PartialSysinfoControl(PartialSysinfo): { 'operand1': 'BgpRouterState.build_info', 'operation': '==', - 'operand2': 'null' + 'operand2': { + 'json_value': 'null' + } } ] } diff --git a/src/opserver/plugins/alarm_phyif_bandwidth/main.py b/src/opserver/plugins/alarm_phyif_bandwidth/main.py index 67bdf96b194..0d42133a7a4 100644 --- a/src/opserver/plugins/alarm_phyif_bandwidth/main.py +++ b/src/opserver/plugins/alarm_phyif_bandwidth/main.py @@ -7,7 +7,7 @@ class PhyifBandwidth(AlarmBase): Physical Bandwidth usage anomaly as per VrouterStatsAgent.out_bps_ewm or VrouterStatsAgent.in_bps_ewm""" def __init__(self): - AlarmBase.__init__(self, AlarmBase.SYS_WARN) + AlarmBase.__init__(self, AlarmBase.ALARM_MINOR) def checkbw(self, stat, sname, vname, thresh): alm = [] @@ -16,24 +16,26 @@ def checkbw(self, stat, sname, vname, thresh): for k,val in stat.iteritems(): if val["sigma"] >= thresh: match_list_o.append(AlarmMatch(json_operand1_value=json.dumps( - val["sigma"]), json_vars={ + val["sigma"]), json_variables={ vname:json.dumps(k)})) if val["sigma"] <= (-thresh): match_list_u.append(AlarmMatch(json_operand1_value=json.dumps( - val["sigma"]), json_vars={ + val["sigma"]), json_variables={ vname:json.dumps(k)})) if len(match_list_o): alm.append(AlarmAndList(and_list=[AlarmConditionMatch( condition=AlarmCondition(operation=">=", - operand1=sname, operand2=json.dumps(thresh), - vars=[vname]), + operand1=sname, operand2=AlarmOperand2( + json_value=json.dumps(thresh)), + variables=[vname]), match=match_list_o)])) if len(match_list_u): alm.append(AlarmAndList(and_list=[AlarmConditionMatch( condition=AlarmCondition(operation="<=", - operand1=sname, operand2=json.dumps(-thresh), - vars=[vname]), + operand1=sname, operand2=AlarmOperand2( + json_value=json.dumps(-thresh)), + variables=[vname]), match=match_list_u)])) return alm diff --git a/src/opserver/plugins/alarm_process_connectivity/main.py b/src/opserver/plugins/alarm_process_connectivity/main.py index 7778bb70ad3..17733ce7537 100644 --- a/src/opserver/plugins/alarm_process_connectivity/main.py +++ b/src/opserver/plugins/alarm_process_connectivity/main.py @@ -12,7 +12,9 @@ class ProcessConnectivity(AlarmBase): { 'operand1': 'NodeStatus.process_status', 'operation': '==', - 'operand2': 'null' + 'operand2': { + 'json_value': 'null' + } } ] }, @@ -21,7 +23,9 @@ class ProcessConnectivity(AlarmBase): { 'operand1': 'NodeStatus.process_status.state', 'operation': '!=', - 'operand2': '"Functional"', + 'operand2': { + 'json_value': '"Functional"' + }, 'variables': ['NodeStatus.process_status.module_id', 'NodeStatus.process_status.instance_id'] } @@ -31,4 +35,4 @@ class ProcessConnectivity(AlarmBase): } def __init__(self): - AlarmBase.__init__(self, AlarmBase.SYS_ERR) + AlarmBase.__init__(self, AlarmBase.ALARM_CRITICAL) diff --git a/src/opserver/plugins/alarm_process_status/main.py b/src/opserver/plugins/alarm_process_status/main.py index 765aa91a6c9..46d0fcae90f 100644 --- a/src/opserver/plugins/alarm_process_status/main.py +++ b/src/opserver/plugins/alarm_process_status/main.py @@ -12,7 +12,9 @@ class ProcessStatus(AlarmBase): { 'operand1': 'NodeStatus.process_info', 'operation': '==', - 'operand2': 'null' + 'operand2': { + 'json_value': 'null' + } } ] }, @@ -21,7 +23,9 @@ class ProcessStatus(AlarmBase): { 'operand1': 'NodeStatus.process_info.process_state', 'operation': '!=', - 'operand2': '"PROCESS_STATE_RUNNING"', + 'operand2': { + 'json_value': '"PROCESS_STATE_RUNNING"' + }, 'variables': ['NodeStatus.process_info.process_name'] } ] @@ -30,5 +34,5 @@ class ProcessStatus(AlarmBase): } def __init__(self): - AlarmBase.__init__(self, AlarmBase.SYS_ERR, at=10, it=10, fec=True, + AlarmBase.__init__(self, AlarmBase.ALARM_CRITICAL, at=10, it=10, fec=True, fcs=300, fct=4) diff --git a/src/opserver/plugins/alarm_prouter_connectivity/main.py b/src/opserver/plugins/alarm_prouter_connectivity/main.py index e01434db0c0..7318421fded 100644 --- a/src/opserver/plugins/alarm_prouter_connectivity/main.py +++ b/src/opserver/plugins/alarm_prouter_connectivity/main.py @@ -17,12 +17,16 @@ class ProuterConnectivity(AlarmBase): 'operand1': 'ContrailConfig.elements.' + \ 'virtual_router_refs', 'operation': '!=', - 'operand2': 'null' + 'operand2': { + 'json_value': 'null' + } }, { 'operand1': 'ProuterData.connected_agent_list', 'operation': '==', - 'operand2': 'null' + 'operand2': { + 'json_value': 'null' + } } ] }, @@ -32,12 +36,16 @@ class ProuterConnectivity(AlarmBase): 'operand1': 'ContrailConfig.elements.' + \ 'virtual_router_refs', 'operation': '!=', - 'operand2': 'null' + 'operand2': { + 'json_value': 'null' + } }, { 'operand1': 'ProuterData.connected_agent_list', 'operation': 'size!=', - 'operand2': '1' + 'operand2': { + 'json_value': '1' + } } ] } @@ -45,4 +53,4 @@ class ProuterConnectivity(AlarmBase): } def __init__(self): - AlarmBase.__init__(self, AlarmBase.SYS_ERR) + AlarmBase.__init__(self, AlarmBase.ALARM_MAJOR) diff --git a/src/opserver/plugins/alarm_storage/main.py b/src/opserver/plugins/alarm_storage/main.py index 05892426a82..82fa80068e5 100644 --- a/src/opserver/plugins/alarm_storage/main.py +++ b/src/opserver/plugins/alarm_storage/main.py @@ -12,7 +12,9 @@ class StorageClusterState(AlarmBase): { 'operand1': 'StorageCluster.info_stats.status', 'operation': '!=', - 'operand2': '0', + 'operand2': { + 'json_value': '0' + }, 'variables': \ ['StorageCluster.info_stats.health_summary'] } @@ -22,4 +24,4 @@ class StorageClusterState(AlarmBase): } def __init__(self): - AlarmBase.__init__(self, AlarmBase.SYS_ERR) + AlarmBase.__init__(self, AlarmBase.ALARM_MAJOR) diff --git a/src/opserver/plugins/alarm_vrouter_interface/main.py b/src/opserver/plugins/alarm_vrouter_interface/main.py index 3c70af65366..3088a3029cc 100644 --- a/src/opserver/plugins/alarm_vrouter_interface/main.py +++ b/src/opserver/plugins/alarm_vrouter_interface/main.py @@ -12,7 +12,9 @@ class VrouterInterface(AlarmBase): { 'operand1': 'VrouterAgent.down_interface_count', 'operation': '>=', - 'operand2': '1', + 'operand2': { + 'json_value': '1' + }, 'variables': ['VrouterAgent.error_intf_list', \ 'VrouterAgent.no_config_intf_list'] }, @@ -22,4 +24,4 @@ class VrouterInterface(AlarmBase): } def __init__(self): - AlarmBase.__init__(self, AlarmBase.SYS_WARN) + AlarmBase.__init__(self, AlarmBase.ALARM_MAJOR) diff --git a/src/opserver/plugins/alarm_xmpp_connectivity/main.py b/src/opserver/plugins/alarm_xmpp_connectivity/main.py index d74a6318f93..2421b5d141b 100644 --- a/src/opserver/plugins/alarm_xmpp_connectivity/main.py +++ b/src/opserver/plugins/alarm_xmpp_connectivity/main.py @@ -12,7 +12,9 @@ class XmppConnectivity(AlarmBase): { 'operand1': 'BgpRouterState.num_up_xmpp_peer', 'operation': '==', - 'operand2': 'null' + 'operand2': { + 'json_value': 'null' + } } ] }, @@ -21,7 +23,9 @@ class XmppConnectivity(AlarmBase): { 'operand1': 'BgpRouterState.num_up_xmpp_peer', 'operation': '!=', - 'operand2': 'BgpRouterState.num_xmpp_peer' + 'operand2': { + 'uve_attribute': 'BgpRouterState.num_xmpp_peer' + } } ] } @@ -29,4 +33,4 @@ class XmppConnectivity(AlarmBase): } def __init__(self): - AlarmBase.__init__(self, AlarmBase.SYS_WARN) + AlarmBase.__init__(self, AlarmBase.ALARM_MAJOR) diff --git a/src/opserver/test/test_alarm.py b/src/opserver/test/test_alarm.py index c8717e1dff2..9ab6d2879d5 100755 --- a/src/opserver/test/test_alarm.py +++ b/src/opserver/test/test_alarm.py @@ -19,14 +19,15 @@ from kafka.common import OffsetAndMessage,Message from vnc_api.gen.resource_client import Alarm -from vnc_api.gen.resource_xsd import AlarmExpression, AlarmAndList, \ - AlarmOrList, UveKeysType +from vnc_api.gen.resource_xsd import AlarmExpression, AlarmOperand2, \ + AlarmAndList, AlarmOrList, UveKeysType from pysandesh.util import UTCTimestampUsec from pysandesh.gen_py.sandesh_alarm.ttypes import SandeshAlarmAckRequest, \ SandeshAlarmAckResponseCode from opserver.sandesh.alarmgen_ctrl.sandesh_alarm_base.ttypes import \ - UVEAlarmInfo, UVEAlarmConfig, UVEAlarms, AlarmRules, AlarmAndList, \ - AlarmCondition, AlarmMatch, AlarmConditionMatch + UVEAlarmInfo, UVEAlarmConfig, UVEAlarms, AlarmRules, \ + AlarmAndList as SandeshAlarmAndList, AlarmCondition, AlarmMatch, \ + AlarmConditionMatch, AlarmOperand2 as SandeshAlarmOperand2 from opserver.sandesh.alarmgen_ctrl.ttypes import UVEAlarmOperState, \ UVEAlarmStateMachineInfo, UVEAlarmState from opserver.uveserver import UVEServer @@ -34,6 +35,7 @@ UveStreamer, UveStreamPart, PartInfo from opserver.alarmgen import Controller, AlarmStateMachine, AlarmProcessor from opserver.alarmgen_cfg import CfgParser +from opserver.plugins.alarm_base import AlarmBase logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s %(message)s') @@ -279,10 +281,10 @@ def create_test_alarm_info(self, table, name, alarm_type): or_list = [] condition_match = AlarmConditionMatch( condition=AlarmCondition(operation="!=", operand1="dummytoken", - operand2=json.dumps("UP")), + operand2=SandeshAlarmOperand2(json_value=json.dumps("UP"))), match=[AlarmMatch(json_operand1_value=json.dumps("DOWN"))]) - or_list.append(AlarmAndList([condition_match])) - uai = UVEAlarmInfo(type=alarm_type, severity=1, + or_list.append(SandeshAlarmAndList([condition_match])) + uai = UVEAlarmInfo(type=alarm_type, severity=AlarmBase.ALARM_MAJOR, timestamp=UTCTimestampUsec(), token="dummytoken", alarm_rules=AlarmRules(or_list), ack=False) @@ -320,7 +322,9 @@ def get_alarm_config_object(self, config_dict): alarm_and_list.append(AlarmExpression( operation=exp['operation'], operand1=exp['operand1'], - operand2=exp['operand2'], + operand2=AlarmOperand2(uve_attribute=exp['operand2'].get( + 'uve_attribute'), json_value=exp['operand2'].get( + 'json_value')), variables=exp.get('variables'))) alarm_or_list.append(AlarmAndList(alarm_and_list)) return Alarm(name=config_dict['name'], @@ -768,7 +772,7 @@ def test_05_evaluate_uve_for_alarms(self): { 'name': 'alarm1', 'uve_keys': ['key1', 'key2'], - 'alarm_severity': 3, + 'alarm_severity': AlarmBase.ALARM_MINOR, 'alarm_rules': { 'or_list': [ { @@ -776,7 +780,9 @@ def test_05_evaluate_uve_for_alarms(self): { 'operand1': 'A', 'operation': '==', - 'operand2': 'null' + 'operand2': { + 'json_value': 'null' + } } ] } @@ -793,7 +799,7 @@ def test_05_evaluate_uve_for_alarms(self): { 'name': 'alarm2', 'uve_keys': ['key1'], - 'alarm_severity': 3, + 'alarm_severity': AlarmBase.ALARM_MAJOR, 'alarm_rules': { 'or_list': [ { @@ -801,7 +807,9 @@ def test_05_evaluate_uve_for_alarms(self): { 'operand1': 'A.B.C', 'operation': 'not in', - 'operand2': 'X.Y' + 'operand2': { + 'uve_attribute': 'X.Y' + } } ] } @@ -818,7 +826,7 @@ def test_05_evaluate_uve_for_alarms(self): { 'name': 'alarm3', 'uve_keys': ['key1'], - 'alarm_severity': 1, + 'alarm_severity': AlarmBase.ALARM_CRITICAL, 'alarm_rules': { 'or_list': [ { @@ -826,7 +834,9 @@ def test_05_evaluate_uve_for_alarms(self): { 'operand1': 'A.B', 'operation': '!=', - 'operand2': 'A.C' + 'operand2': { + 'uve_attribute': 'A.C' + } } ] } @@ -843,7 +853,7 @@ def test_05_evaluate_uve_for_alarms(self): { 'name': 'alarm4', 'uve_keys': ['key1'], - 'alarm_severity': 2, + 'alarm_severity': AlarmBase.ALARM_MAJOR, 'alarm_rules': { 'or_list': [ { @@ -851,7 +861,9 @@ def test_05_evaluate_uve_for_alarms(self): { 'operand1': 'A.B', 'operation': '!=', - 'operand2': '2' + 'operand2': { + 'json_value': '2' + } } ] } @@ -868,7 +880,7 @@ def test_05_evaluate_uve_for_alarms(self): { 'name': 'alarm5', 'uve_keys': ['key5'], - 'alarm_severity': 5, + 'alarm_severity': AlarmBase.ALARM_MINOR, 'alarm_rules': { 'or_list': [ { @@ -876,7 +888,9 @@ def test_05_evaluate_uve_for_alarms(self): { 'operand1': 'A.B', 'operation': '<=', - 'operand2': 'A.C.D', + 'operand2': { + 'uve_attribute': 'A.C.D' + }, 'variables': ['A.C.N'] } ] @@ -894,7 +908,7 @@ def test_05_evaluate_uve_for_alarms(self): { 'name': 'alarm6', 'uve_keys': ['key1'], - 'alarm_severity': 2, + 'alarm_severity': AlarmBase.ALARM_MAJOR, 'alarm_rules': { 'or_list': [ { @@ -902,13 +916,17 @@ def test_05_evaluate_uve_for_alarms(self): { 'operand1': 'A.B', 'operation': '<=', - 'operand2': 'A.C.D', + 'operand2': { + 'uve_attribute': 'A.C.D' + }, 'variables': ['A.C.N'] }, { 'operand1': 'A.B', 'operation': '>=', - 'operand2': 'A.C.E', + 'operand2': { + 'uve_attribute': 'A.C.E' + }, 'variables': ['A.C.N'] } ] @@ -926,7 +944,7 @@ def test_05_evaluate_uve_for_alarms(self): { 'name': 'alarm7', 'uve_keys': ['key1'], - 'alarm_severity': 2, + 'alarm_severity': AlarmBase.ALARM_CRITICAL, 'alarm_rules': { 'or_list': [ { @@ -934,12 +952,16 @@ def test_05_evaluate_uve_for_alarms(self): { 'operand1': 'A', 'operation': '!=', - 'operand2': 'null' + 'operand2': { + 'json_value': 'null' + } }, { 'operand1': 'A.B', 'operation': 'not in', - 'operand2': '["abc", "def"]' + 'operand2': { + 'json_value': '["abc", "def"]' + } } ] }, @@ -948,12 +970,16 @@ def test_05_evaluate_uve_for_alarms(self): { 'operand1': 'A', 'operation': '!=', - 'operand2': 'null' + 'operand2': { + 'json_value': 'null' + } }, { 'operand1': 'A.B', 'operation': '==', - 'operand2': 'A.D' + 'operand2': { + 'uve_attribute': 'A.D' + } } ] } @@ -977,7 +1003,9 @@ def test_05_evaluate_uve_for_alarms(self): { 'condition': { 'operand1': 'A', - 'operand2': 'null', + 'operand2': { + 'json_value': 'null' + }, 'operation': '==' }, 'match': [ @@ -1010,7 +1038,9 @@ def test_05_evaluate_uve_for_alarms(self): { 'condition': { 'operand1': 'A.B.C', - 'operand2': 'X.Y', + 'operand2': { + 'uve_attribute': 'X.Y' + }, 'operation': 'not in' }, 'match': [ @@ -1087,7 +1117,9 @@ def test_05_evaluate_uve_for_alarms(self): { 'condition': { 'operand1': 'A.B', - 'operand2': 'A.C', + 'operand2': { + 'uve_attribute': 'A.C' + }, 'operation': '!=' }, 'match': [ @@ -1136,7 +1168,9 @@ def test_05_evaluate_uve_for_alarms(self): { 'condition': { 'operand1': 'A.B', - 'operand2': '2', + 'operand2': { + 'json_value': '2' + }, 'operation': '!=' }, 'match': [ @@ -1197,7 +1231,9 @@ def test_05_evaluate_uve_for_alarms(self): { 'condition': { 'operand1': 'A.B', - 'operand2': '2', + 'operand2': { + 'json_value': '2' + }, 'operation': '!=' }, 'match': [ @@ -1265,7 +1301,9 @@ def test_05_evaluate_uve_for_alarms(self): { 'condition': { 'operand1': 'A.B.C', - 'operand2': 'X.Y', + 'operand2': { + 'uve_attribute': 'X.Y' + }, 'operation': 'not in' }, 'match': [ @@ -1343,7 +1381,9 @@ def test_05_evaluate_uve_for_alarms(self): { 'condition': { 'operand1': 'A.B', - 'operand2': 'A.C', + 'operand2': { + 'uve_attribute': 'A.C' + }, 'operation': '!=' }, 'match': [ @@ -1417,22 +1457,24 @@ def test_05_evaluate_uve_for_alarms(self): { 'condition': { 'operand1': 'A.B', - 'operand2': 'A.C.D', + 'operand2': { + 'uve_attribute': 'A.C.D' + }, 'operation': '<=', - 'vars': ['A.C.N'] + 'variables': ['A.C.N'] }, 'match': [ { 'json_operand1_val': '10', 'json_operand2_val': '11', - 'json_vars': { + 'json_variables': { 'A.C.N': '"abc"' } }, { 'json_operand1_val': '10', 'json_operand2_val': '25', - 'json_vars': { + 'json_variables': { 'A.C.N': 'null' } } @@ -1495,22 +1537,24 @@ def test_05_evaluate_uve_for_alarms(self): { 'condition': { 'operand1': 'A.B', - 'operand2': 'A.C.D', + 'operand2': { + 'uve_attribute': 'A.C.D' + }, 'operation': '<=', - 'vars': ['A.C.N'] + 'variables': ['A.C.N'] }, 'match': [ { 'json_operand1_val': '5', 'json_operand2_val': '5', - 'json_vars': { + 'json_variables': { 'A.C.N': '"abc"' } }, { 'json_operand1_val': '5', 'json_operand2_val': '10', - 'json_vars': { + 'json_variables': { 'A.C.N': '"hjk"' } } @@ -1519,22 +1563,24 @@ def test_05_evaluate_uve_for_alarms(self): { 'condition': { 'operand1': 'A.B', - 'operand2': 'A.C.E', + 'operand2': { + 'uve_attribute': 'A.C.E' + }, 'operation': '>=', - 'vars': ['A.C.N'] + 'variables': ['A.C.N'] }, 'match': [ { 'json_operand1_val': '5', 'json_operand2_val': '5', - 'json_vars': { + 'json_variables': { 'A.C.N': '"abc"' } }, { 'json_operand1_val': '5', 'json_operand2_val': '4', - 'json_vars': { + 'json_variables': { 'A.C.N': '"hjk"' } } @@ -1574,7 +1620,9 @@ def test_05_evaluate_uve_for_alarms(self): { 'condition': { 'operand1': 'A', - 'operand2': 'null', + 'operand2': { + 'json_value': 'null' + }, 'operation': '!=' }, 'match': [ @@ -1587,7 +1635,9 @@ def test_05_evaluate_uve_for_alarms(self): { 'condition': { 'operand1': 'A.B', - 'operand2': 'A.D', + 'operand2': { + 'uve_attribute': 'A.D' + }, 'operation': '==' }, 'match': [ @@ -1619,7 +1669,9 @@ def test_05_evaluate_uve_for_alarms(self): { 'condition': { 'operand1': 'A', - 'operand2': 'null', + 'operand2': { + 'json_value': 'null' + }, 'operation': '!=' }, 'match': [ @@ -1632,7 +1684,9 @@ def test_05_evaluate_uve_for_alarms(self): { 'condition': { 'operand1': 'A.B', - 'operand2': '["abc", "def"]', + 'operand2': { + 'json_value': '["abc", "def"]' + }, 'operation': 'not in' }, 'match': [ @@ -1648,7 +1702,9 @@ def test_05_evaluate_uve_for_alarms(self): { 'condition': { 'operand1': 'A', - 'operand2': 'null', + 'operand2': { + 'json_value': 'null' + }, 'operation': '!=' }, 'match': [ @@ -1661,7 +1717,9 @@ def test_05_evaluate_uve_for_alarms(self): { 'condition': { 'operand1': 'A.B', - 'operand2': 'A.D', + 'operand2': { + 'uve_attribute': 'A.D' + }, 'operation': '==' }, 'match': [ @@ -1685,20 +1743,24 @@ def test_05_evaluate_uve_for_alarms(self): for elt in test.output.or_list: and_list = [] for and_elt in elt['and_list']: - condition = and_elt['condition'] + cond = and_elt['condition'] match = and_elt['match'] and_list.append(AlarmConditionMatch( condition=AlarmCondition( - operation=condition['operation'], - operand1=condition['operand1'], - operand2=condition['operand2'], - vars=condition.get('vars') or []), + operation=cond['operation'], + operand1=cond['operand1'], + operand2=SandeshAlarmOperand2( + uve_attribute=cond['operand2'].get( + 'uve_attribute'), + json_value=cond['operand2'].get( + 'json_value')), + variables=cond.get('variables') or []), match=[AlarmMatch( json_operand1_value=m['json_operand1_val'], json_operand2_value=m.get('json_operand2_val'), - json_vars=m.get('json_vars') or {}) \ + json_variables=m.get('json_variables') or {}) \ for m in match])) - exp_or_list.append(AlarmAndList(and_list)) + exp_or_list.append(SandeshAlarmAndList(and_list)) alarm_processor = AlarmProcessor(logging) or_list = alarm_processor._evaluate_uve_for_alarms( test.input.alarm_cfg, test.input.uve_key, test.input.uve) diff --git a/src/opserver/test/test_alarm_plugins.py b/src/opserver/test/test_alarm_plugins.py index 7c1f0d81de2..a87aac86a24 100644 --- a/src/opserver/test/test_alarm_plugins.py +++ b/src/opserver/test/test_alarm_plugins.py @@ -7,12 +7,15 @@ import signal import unittest import logging +import json from collections import namedtuple from vnc_api.gen.resource_client import Alarm from vnc_api.gen.resource_xsd import IdPermsType, AlarmExpression, \ - AlarmAndList, AlarmOrList -from opserver.sandesh.alarmgen_ctrl.sandesh_alarm_base.ttypes import * + AlarmOperand2, AlarmAndList, AlarmOrList +from opserver.sandesh.alarmgen_ctrl.sandesh_alarm_base.ttypes import \ + AlarmOperand2 as SandeshAlarmOperand2, AlarmCondition, AlarmMatch, \ + AlarmConditionMatch, AlarmAndList as SandeshAlarmAndList from opserver.alarmgen import AlarmProcessor from opserver.opserver_util import camel_case_to_hyphen from alarm_process_status.main import ProcessStatus @@ -58,7 +61,9 @@ def get_alarm_config(self, plugin): for exp in and_list['and_list']: alarm_and_list.append(AlarmExpression( operation=exp['operation'], operand1=exp['operand1'], - operand2=exp['operand2'], + operand2=AlarmOperand2(uve_attribute= + exp['operand2'].get('uve_attribute'), + json_value=exp['operand2'].get('json_value')), variables=exp.get('variables'))) alarm_or_list.append(AlarmAndList(alarm_and_list)) alarm_name = camel_case_to_hyphen(plugin.__class__.__name__) @@ -1416,18 +1421,24 @@ def _verify(self, plugin, tests): exp_or_list = [] for elt in test.output.or_list: and_list = [] - for condition, vars, match in elt['and_list']: + for condition, variables, match in elt['and_list']: oper1, tmp = condition.split(' ', 1) oper, oper2 = tmp.rsplit(' ', 1) + try: + json.loads(oper2) + except ValueError: + oper2 = SandeshAlarmOperand2(uve_attribute=oper2) + else: + oper2 = SandeshAlarmOperand2(json_value=oper2) and_list.append(AlarmConditionMatch( condition=AlarmCondition( operation=oper, operand1=oper1, - operand2=oper2, vars=vars or []), + operand2=oper2, variables=variables or []), match=[AlarmMatch( json_operand1_value=e[0], json_operand2_value=e[1], - json_vars=e[2] or {}) for e in match])) - exp_or_list.append(AlarmAndList(and_list)) + json_variables=e[2] or {}) for e in match])) + exp_or_list.append(SandeshAlarmAndList(and_list)) if hasattr(plugin, '__call__'): or_list = plugin.__call__(test.input.uve_key, test.input.uve_data) diff --git a/src/opserver/test/test_alarmgen_config_handler.py b/src/opserver/test/test_alarmgen_config_handler.py index 5af4e4c364c..1c914b13dbd 100644 --- a/src/opserver/test/test_alarmgen_config_handler.py +++ b/src/opserver/test/test_alarmgen_config_handler.py @@ -79,7 +79,7 @@ def test_handle_config_update(self): { 'name': 'alarm1', 'uve_keys': ['analytics-node', 'control-node'], - 'alarm_severity': 3, + 'alarm_severity': AlarmBase.ALARM_CRITICAL, 'alarm_rules': { 'or_list': [ { @@ -103,7 +103,7 @@ def test_handle_config_update(self): { 'name': 'alarm1', 'uve_keys': ['invalid', 'control-node', 'config-node'], - 'alarm_severity': 3, + 'alarm_severity': AlarmBase.ALARM_CRITICAL, 'alarm_rules': { 'or_list': [ { @@ -127,7 +127,7 @@ def test_handle_config_update(self): { 'name': 'alarm1', 'uve_keys': ['virtual-network', 'invalid'], - 'alarm_severity': 4, + 'alarm_severity': AlarmBase.ALARM_MINOR, 'alarm_rules': { 'or_list': [ { @@ -151,7 +151,7 @@ def test_handle_config_update(self): { 'name': 'alarm1', 'uve_keys': ['virtual-network'], - 'alarm_severity': 4, + 'alarm_severity': AlarmBase.ALARM_MINOR, 'alarm_rules': { 'or_list': [ { @@ -175,7 +175,7 @@ def test_handle_config_update(self): { 'name': 'alarm1', 'uve_keys': ['virtual-network'], - 'alarm_severity': 4, + 'alarm_severity': AlarmBase.ALARM_MAJOR, 'alarm_rules': { 'or_list': [ { diff --git a/src/opserver/test/test_analytics_uve.py b/src/opserver/test/test_analytics_uve.py index 72bb9398ae2..f70f7e730fa 100755 --- a/src/opserver/test/test_analytics_uve.py +++ b/src/opserver/test/test_analytics_uve.py @@ -369,7 +369,9 @@ def test_06_alarmgen_basic(self): "condition": { "operation": "==", "operand1": "ObjectVRouter.build_info", - "operand2": "null" + "operand2": { + "json_value": "null" + } }, "match": [{"json_operand1_value": "null"}] }]}] @@ -474,8 +476,6 @@ def test_07_alarm(self): # send process state alarm for analytics-node alarms = alarm_gen1.create_process_state_alarm( 'contrail-query-engine') - alarms += alarm_gen1.create_process_state_alarm( - 'contrail-snmp-collector') alarm_gen1.send_alarm(socket.gethostname()+'_1', alarms, COLLECTOR_INFO_TABLE) analytics_tbl = _OBJECT_TABLES[COLLECTOR_INFO_TABLE].log_query_name diff --git a/src/opserver/test/utils/generator_fixture.py b/src/opserver/test/utils/generator_fixture.py index bfbf79286f1..98e961e6f12 100644 --- a/src/opserver/test/utils/generator_fixture.py +++ b/src/opserver/test/utils/generator_fixture.py @@ -420,14 +420,16 @@ def send_vrouterinfo(self, name, b_info = False, deleted = False): def create_alarm(self, type, name=None, ack=None): alarms = [] - any_of=None + alarm_rules=None if name: - any_of = [AllOf(all_of=[AlarmElement(\ - rule=AlarmTemplate(oper="!=", - operand1=Operand1(keys=[name]), - operand2=Operand2(json_value=json.dumps('UP'))), - json_operand1_value=json.dumps('DOWN'))])] - alarms.append(UVEAlarmInfo(type=type,ack=ack,any_of=any_of)) + alarm_rules = AlarmRules(or_list=[ + AlarmAndList(and_list=[ + AlarmConditionMatch(condition=AlarmCondition( + operation='!=', operand1="test", + operand2=AlarmOperand2(json_value="\"UP\"")), + match=[AlarmMatch(json_operand1_value="\"DOWN\"")])])]) + alarms.append(UVEAlarmInfo(type=type, ack=ack, + alarm_rules=alarm_rules)) return alarms # end create_alarm diff --git a/src/schema/alarm.xsd b/src/schema/alarm.xsd index dfd45c58c6a..8dba00fe246 100644 --- a/src/schema/alarm.xsd +++ b/src/schema/alarm.xsd @@ -17,11 +17,16 @@ + + + + + - + @@ -39,9 +44,9 @@ - + - +