示例#1
0
    def update_or_patch_alarm_definition(self,
                                         tenant_id,
                                         alarm_definition_id,
                                         name,
                                         expression,
                                         sub_expr_list,
                                         actions_enabled,
                                         description,
                                         alarm_actions,
                                         ok_actions,
                                         undetermined_actions,
                                         match_by,
                                         severity,
                                         patch=False):

        with self._db_engine.begin() as conn:
            original_row = self._get_alarm_definition(conn, tenant_id,
                                                      alarm_definition_id)
            rows = self._get_sub_alarm_definitions(conn, alarm_definition_id)

            old_sub_alarm_defs_by_id = {}

            for row in rows:
                sad = sub_alarm_definition.SubAlarmDefinition(row=row)
                old_sub_alarm_defs_by_id[sad.id] = sad

            if expression:
                (changed_sub_alarm_defs_by_id, new_sub_alarm_defs_by_id,
                 old_sub_alarm_defs_by_id, unchanged_sub_alarm_defs_by_id
                 ) = self._determine_sub_expr_changes(
                     alarm_definition_id, old_sub_alarm_defs_by_id,
                     sub_expr_list)

                if old_sub_alarm_defs_by_id or new_sub_alarm_defs_by_id:
                    new_count = (len(new_sub_alarm_defs_by_id) +
                                 len(changed_sub_alarm_defs_by_id) +
                                 len(unchanged_sub_alarm_defs_by_id))
                    old_count = len(old_sub_alarm_defs_by_id)
                    if new_count != old_count:
                        msg = 'number of subexpressions must not change'
                    else:
                        msg = 'metrics in subexpression must not change'
                    raise exceptions.InvalidUpdateException(msg.encode('utf8'))
            else:
                unchanged_sub_alarm_defs_by_id = old_sub_alarm_defs_by_id
                changed_sub_alarm_defs_by_id = {}
                new_sub_alarm_defs_by_id = {}
                old_sub_alarm_defs_by_id = {}

            # Get a common update time
            now = datetime.datetime.utcnow()

            if name is None:
                new_name = original_row['name']
            else:
                new_name = name.encode('utf8')

            if description is None:
                if patch:
                    new_description = original_row['description']
                else:
                    new_description = ''
            else:
                new_description = description.encode('utf8')

            if expression is None:
                new_expression = original_row['expression']
            else:
                new_expression = expression.encode('utf8')

            if severity is None:
                if patch:
                    new_severity = original_row['severity']
                else:
                    new_severity = 'LOW'
            else:
                new_severity = severity.encode('utf8')

            if match_by is None:
                if patch:
                    new_match_by = original_row['match_by']
                else:
                    new_match_by = None
            else:
                new_match_by = ",".join(match_by).encode('utf8')

            if new_match_by != original_row['match_by']:
                msg = "match_by must not change".encode('utf8')
                raise exceptions.InvalidUpdateException(msg)

            if actions_enabled is None:
                new_actions_enabled = original_row['actions_enabled']
            else:
                new_actions_enabled = actions_enabled

            conn.execute(
                self.update_or_patch_alarm_definition_update_ad_query.values(
                    name=bindparam('b_name'),
                    description=bindparam('b_description'),
                    expression=bindparam('b_expression'),
                    match_by=bindparam('b_match_by'),
                    severity=bindparam('b_severity'),
                    actions_enabled=bindparam('b_actions_enabled'),
                    updated_at=bindparam('b_updated_at')),
                b_name=new_name,
                b_description=new_description,
                b_expression=new_expression,
                b_match_by=new_match_by,
                b_severity=new_severity,
                b_actions_enabled=bool(new_actions_enabled),
                b_updated_at=now,
                b_tenant_id=tenant_id,
                b_id=alarm_definition_id)

            parms = []
            for sub_alarm_def_id in old_sub_alarm_defs_by_id.values():
                parms.append({'b_id': sub_alarm_def_id.id})

            if len(parms) > 0:
                query = self.update_or_patch_alarm_definition_delete_sad_query
                conn.execute(query, parms)

            parms = []
            for sub_alarm_definition_id, sub_alarm_def in (
                    changed_sub_alarm_defs_by_id.iteritems()):
                parms.append({
                    'b_operator': sub_alarm_def.operator,
                    'b_threshold': sub_alarm_def.threshold,
                    'b_updated_at': now,
                    'b_id': sub_alarm_definition_id
                })
            if len(parms) > 0:
                query = self.update_or_patch_alarm_definition_update_sad_query
                conn.execute(query, parms)

            parms = []
            parms_sadd = []
            for sub_alarm_def in new_sub_alarm_defs_by_id.values():
                adi = sub_alarm_def.alarm_definition_id
                function = sub_alarm_def.function.encode('utf8')
                metric_name = sub_alarm_def.metric_name.encode('utf8')
                operator = sub_alarm_def.operator.encode('utf8')
                threshold = str(sub_alarm_def.threshold).encode('utf8')
                period = str(sub_alarm_def.period).encode('utf8')
                periods = str(sub_alarm_def.periods).encode('utf8')
                parms.append({
                    'b_id': sub_alarm_def.id,
                    'b_alarm_definition_id': adi,
                    'b_function': function,
                    'b_metric_name': metric_name,
                    'b_operator': operator,
                    'b_threshold': threshold,
                    'b_period': period,
                    'b_periods': periods,
                    'b_created_at': now,
                    'b_updated_at': now
                })

                for name, value in sub_alarm_def.dimensions.items():
                    sadi = sub_alarm_def.id
                    parms_sadd.append({
                        'b_sub_alarm_definition_id': sadi,
                        'b_dimension_name': name.encode('utf8'),
                        'b_value': value.encode('utf8')
                    })

            if len(parms) > 0:
                query = self.update_or_patch_alarm_definition_insert_sad_query
                conn.execute(query, parms)

            if len(parms_sadd) > 0:
                query = self.update_or_patch_alarm_definition_insert_sadd_query
                conn.execute(query, parms_sadd)

            # Delete old alarm actions
            if patch:
                if alarm_actions is not None:
                    self._delete_alarm_actions(conn, alarm_definition_id,
                                               'ALARM')
                if ok_actions is not None:
                    self._delete_alarm_actions(conn, alarm_definition_id, 'OK')
                if undetermined_actions is not None:
                    self._delete_alarm_actions(conn, alarm_definition_id,
                                               'UNDETERMINED')
            else:
                conn.execute(self.delete_aa_query,
                             b_alarm_definition_id=alarm_definition_id)

            # Insert new alarm actions
            self._insert_into_alarm_action(conn, alarm_definition_id,
                                           alarm_actions, u"ALARM")

            self._insert_into_alarm_action(conn, alarm_definition_id,
                                           undetermined_actions,
                                           u"UNDETERMINED")

            self._insert_into_alarm_action(conn, alarm_definition_id,
                                           ok_actions, u"OK")

            ad = self.ad_s
            query = (self.base_query.select_from(self.base_query_from).where(
                ad.c.tenant_id == bindparam('b_tenant_id')).where(
                    ad.c.id == bindparam('b_id')).where(
                        ad.c.deleted_at == null()))

            updated_row = conn.execute(query,
                                       b_id=alarm_definition_id,
                                       b_tenant_id=tenant_id).fetchone()

            if updated_row is None:
                raise Exception("Failed to find current alarm definition")

            sub_alarm_defs_dict = {
                'old': old_sub_alarm_defs_by_id,
                'changed': changed_sub_alarm_defs_by_id,
                'new': new_sub_alarm_defs_by_id,
                'unchanged': unchanged_sub_alarm_defs_by_id
            }

            # Return the alarm def and the sub alarm defs
            return updated_row, sub_alarm_defs_dict
示例#2
0
    def test_alarm_definition_update_missing_fields(self):
        self.alarm_def_repo_mock.return_value.get_alarm_definitions.return_value = []
        self.alarm_def_repo_mock.return_value.update_or_patch_alarm_definition.return_value = (
            {
                u'alarm_actions': [],
                u'ok_actions': [],
                u'description': u'Non-ASCII character: \u2603'.encode('utf-8'),
                u'match_by': u'hostname',
                u'name': u'Test Alarm',
                u'actions_enabled': True,
                u'undetermined_actions': [],
                u'expression': u'max(test.metric{hostname=host}) gte 1',
                u'id': u'00000001-0001-0001-0001-000000000001',
                u'is_deterministic': False,
                u'severity': u'LOW'
            }, {
                'old': {
                    '11111':
                    sub_alarm_definition.SubAlarmDefinition(
                        row={
                            'id': '11111',
                            'alarm_definition_id':
                            u'00000001-0001-0001-0001-000000000001',
                            'function': 'max',
                            'metric_name': 'test.metric',
                            'dimensions': 'hostname=host',
                            'operator': 'gte',
                            'threshold': 1,
                            'period': 60,
                            'periods': 1,
                            'is_deterministic': False
                        })
                },
                'changed': {},
                'new': {},
                'unchanged': {
                    '11111':
                    sub_alarm_definition.SubAlarmDefinition(
                        row={
                            'id': '11111',
                            'alarm_definition_id':
                            u'00000001-0001-0001-0001-000000000001',
                            'function': 'max',
                            'metric_name': 'test.metric',
                            'dimensions': 'hostname=host',
                            'operator': 'gte',
                            'threshold': 1,
                            'period': 60,
                            'periods': 1,
                            'is_deterministic': False
                        })
                }
            })

        expected_def = {
            u'id':
            u'00000001-0001-0001-0001-000000000001',
            u'alarm_actions': [],
            u'ok_actions': [],
            u'description':
            u'Non-ASCII character: \u2603',
            u'links': [{
                u'href':
                u'http://falconframework.org/v2.0/alarm-definitions/'
                u'00000001-0001-0001-0001-000000000001/00000001-0001-0001-0001-000000000001',
                u'rel':
                u'self'
            }],
            u'match_by': [u'hostname'],
            u'name':
            u'Test Alarm',
            u'actions_enabled':
            True,
            u'undetermined_actions': [],
            u'expression':
            u'max(test.metric{hostname=host}) gte 1',
            u'severity':
            u'LOW',
            u'deterministic':
            False
        }

        alarm_def = {
            u'alarm_actions': [],
            u'ok_actions': [],
            u'description': u'',
            u'match_by': [u'hostname'],
            u'name': u'Test Alarm',
            u'actions_enabled': True,
            u'undetermined_actions': [],
            u'expression': u'max(test.metric{hostname=host}) gte 1',
            u'severity': u'LOW'
        }

        result = self.simulate_request("/v2.0/alarm-definitions/%s" %
                                       expected_def[u'id'],
                                       headers={
                                           'X-Roles': 'admin',
                                           'X-Tenant-Id': TENANT_ID
                                       },
                                       method="PUT",
                                       body=json.dumps(alarm_def))

        self.assertEqual(self.srmock.status, falcon.HTTP_200)
        result_def = json.loads(result[0])
        self.assertEqual(result_def, expected_def)

        for key, value in alarm_def.iteritems():
            del alarm_def[key]

            self.simulate_request("/v2.0/alarm-definitions/%s" %
                                  expected_def[u'id'],
                                  headers={
                                      'X-Roles': 'admin',
                                      'X-Tenant-Id': TENANT_ID
                                  },
                                  method="PUT",
                                  body=json.dumps(alarm_def))
            self.assertEqual(self.srmock.status, "422 Unprocessable Entity",
                             u"should have failed without key {}".format(key))
            alarm_def[key] = value
示例#3
0
    def test_alarm_definition_patch(self):
        self.alarm_def_repo_mock.return_value.get_alarm_definitions.return_value = []
        description = u'Non-ASCII character: \u2603'
        new_name = u'Test Alarm Updated'
        actions_enabled = True
        alarm_def_id = u'00000001-0001-0001-0001-000000000001'
        alarm_expression = u'max(test.metric{hostname=host}) gte 1'
        severity = u'LOW'
        match_by = u'hostname'
        self.alarm_def_repo_mock.return_value.update_or_patch_alarm_definition.return_value = (
            {
                u'alarm_actions': [],
                u'ok_actions': [],
                u'description': description,
                u'match_by': match_by,
                u'name': new_name,
                u'actions_enabled': actions_enabled,
                u'undetermined_actions': [],
                u'is_deterministic': False,
                u'expression': alarm_expression,
                u'id': alarm_def_id,
                u'severity': severity
            }, {
                'old': {
                    '11111':
                    sub_alarm_definition.SubAlarmDefinition(
                        row={
                            'id': '11111',
                            'alarm_definition_id':
                            u'00000001-0001-0001-0001-000000000001',
                            'function': 'max',
                            'metric_name': 'test.metric',
                            'dimensions': 'hostname=host',
                            'operator': 'gte',
                            'threshold': 1,
                            'period': 60,
                            'is_deterministic': False,
                            'periods': 1
                        })
                },
                'changed': {},
                'new': {},
                'unchanged': {
                    '11111':
                    sub_alarm_definition.SubAlarmDefinition(
                        row={
                            'id': '11111',
                            'alarm_definition_id':
                            u'00000001-0001-0001-0001-000000000001',
                            'function': 'max',
                            'metric_name': 'test.metric',
                            'dimensions': 'hostname=host',
                            'operator': 'gte',
                            'threshold': 1,
                            'period': 60,
                            'is_deterministic': False,
                            'periods': 1
                        })
                }
            })

        expected_def = {
            u'id':
            alarm_def_id,
            u'alarm_actions': [],
            u'ok_actions': [],
            u'description':
            description,
            u'links': [{
                u'href':
                u'http://falconframework.org/v2.0/alarm-definitions/'
                u'00000001-0001-0001-0001-000000000001/00000001-0001-0001-0001-000000000001',
                u'rel':
                u'self'
            }],
            u'match_by': [match_by],
            u'name':
            new_name,
            u'actions_enabled':
            actions_enabled,
            u'undetermined_actions': [],
            u'deterministic':
            False,
            u'expression':
            alarm_expression,
            u'severity':
            severity,
        }

        alarm_def = {
            u'name': u'Test Alarm Updated',
        }

        result = self.simulate_request("/v2.0/alarm-definitions/%s" %
                                       expected_def[u'id'],
                                       headers={
                                           'X-Roles': 'admin',
                                           'X-Tenant-Id': TENANT_ID
                                       },
                                       method="PATCH",
                                       body=json.dumps(alarm_def))

        self.assertEqual(self.srmock.status, falcon.HTTP_200)
        result_def = json.loads(result[0])
        self.assertEqual(result_def, expected_def)
        # If the alarm-definition-updated event does not have all of the
        # fields set, the Threshold Engine will get confused. For example,
        # if alarmActionsEnabled is none, thresh will read that as false
        # and pass that value onto the Notification Engine which will not
        # create a notification even actions_enabled is True in the
        # database. So, ensure all fields are set correctly
        ((_, event), _) = self._send_event.call_args
        expr = u'max(test.metric{hostname=host}, 60) gte 1 times 1'
        sub_expression = {
            '11111': {
                u'expression': expr,
                u'function': 'max',
                u'metricDefinition': {
                    u'dimensions': {
                        u'uname': 'host'
                    },
                    u'name': 'test.metric'
                },
                u'operator': 'gte',
                u'period': 60,
                u'periods': 1,
                u'threshold': 1
            }
        }
        fields = {
            u'alarmActionsEnabled': actions_enabled,
            u'alarmDefinitionId': alarm_def_id,
            u'alarmDescription': description,
            u'alarmExpression': alarm_expression,
            u'alarmName': new_name,
            u'changedSubExpressions': {},
            u'matchBy': [match_by],
            u'severity': severity,
            u'tenantId': u'fedcba9876543210fedcba9876543210',
            u'newAlarmSubExpressions': {},
            u'oldAlarmSubExpressions': sub_expression,
            u'unchangedSubExpressions': sub_expression
        }
        reference = {u'alarm-definition-updated': fields}
        self.assertEqual(reference, event)