Beispiel #1
0
    def _insert_into_alarm_action(self, conn, alarm_definition_id, actions,
                                  alarm_state):

        if actions is None:
            return

        for action in actions:
            row = conn.execute(self.select_nm_query,
                               b_id=action.encode('utf8')).fetchone()
            if row is None:
                raise exceptions.InvalidUpdateException(
                    "Non-existent notification id {} submitted for {} "
                    "notification action".format(action.encode('utf8'),
                                                 alarm_state.encode('utf8')))
            conn.execute(self.insert_aa_query,
                         b_alarm_definition_id=alarm_definition_id,
                         b_alarm_state=alarm_state.encode('utf8'),
                         b_action_id=action.encode('utf8'))
    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('utf-8') if six.PY2 else name

            if description is None:
                if patch:
                    new_description = original_row['description']
                else:
                    new_description = ''
            else:
                new_description = description.encode(
                    'utf-8') if six.PY2 else description

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

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

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

            if new_match_by != original_row['match_by']:
                msg = u"match_by must not change"
                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_definition_id, sub_alarm_def in (
                    changed_sub_alarm_defs_by_id.items()):
                parms.append({
                    'b_operator': sub_alarm_def.operator,
                    'b_threshold': sub_alarm_def.threshold,
                    'b_is_deterministic': sub_alarm_def.deterministic,
                    '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)

            # 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
    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):

        cnxn, cursor = self._get_cnxn_cursor_tuple()

        with cnxn:

            # Get the original alarm definition from the DB
            parms = [tenant_id, alarm_definition_id]

            where_clause = """ where ad.tenant_id = %s
                            and ad.id = %s
                            and deleted_at is NULL """

            query = AlarmDefinitionsRepository.base_query + where_clause

            cursor.execute(query, parms)

            if cursor.rowcount < 1:
                raise exceptions.DoesNotExistException

            original_row = cursor.fetchall()[0]

            query = """
                select sad.*, sadd.dimensions
                from sub_alarm_definition as sad
                left join (select sub_alarm_definition_id,
                              group_concat(dimension_name, '=',
                              value) as dimensions
                           from sub_alarm_definition_dimension
                           group by sub_alarm_definition_id) as sadd
                    on sadd.sub_alarm_definition_id = sad.id
                where sad.alarm_definition_id = %s"""

            cursor.execute(query, [alarm_definition_id])

            rows = cursor.fetchall()

            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()

            # Update the alarm definition
            query = """
                update alarm_definition
                set name = %s,
                    description = %s,
                    expression = %s,
                    match_by = %s,
                    severity = %s,
                    actions_enabled = %s,
                    updated_at = %s
                    where tenant_id = %s and id = %s"""

            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

            parms = [
                new_name, new_description, new_expression, new_match_by,
                new_severity, 1 if new_actions_enabled else 0, now, tenant_id,
                alarm_definition_id
            ]

            cursor.execute(query, parms)

            # Delete the old sub alarm definitions
            query = """
                delete from sub_alarm_definition where id = %s"""

            for sub_alarm_def_id in old_sub_alarm_defs_by_id.values():
                parms = [sub_alarm_def_id]
                cursor.execute(query, parms)

            # Update changed sub alarm definitions
            query = """
                update sub_alarm_definition
                set operator = %s,
                threshold = %s,
                is_deterministic = %s,
                updated_at = %s,
                where id = %s"""

            for sub_alarm_definition_id, sub_alarm_def in (
                    changed_sub_alarm_defs_by_id.iteritems()):
                parms = [
                    sub_alarm_def.operator, sub_alarm_def.threshold,
                    sub_alarm_def.deterministic, now, sub_alarm_definition_id
                ]
                cursor.execute(query, parms)

            # Insert new sub alarm definitions
            query = """
                insert into sub_alarm_definition(
                   id,
                   alarm_definition_id,
                   function,
                   metric_name,
                   operator,
                   threshold,
                   period,
                   periods,
                   is_deterministic,
                   created_at,
                   updated_at)
                values(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"""

            sub_query = """
                insert into sub_alarm_definition_dimension(
                  sub_alarm_definition_id,
                  dimension_name,
                  value)
                values(%s, %s,%s)"""

            for sub_alarm_def in new_sub_alarm_defs_by_id.values():
                parms = [
                    sub_alarm_def.id, sub_alarm_def.alarm_definition_id,
                    sub_alarm_def.function.encode('utf8'),
                    sub_alarm_def.metric_name.encode('utf8'),
                    sub_alarm_def.operator.encode('utf8'),
                    str(sub_alarm_def.threshold).encode('utf8'),
                    str(sub_alarm_def.period).encode('utf8'),
                    str(sub_alarm_def.periods).encode('utf8'),
                    sub_alarm_def.deterministic, now, now
                ]

                cursor.execute(query, parms)

                for name, value in sub_alarm_def.dimensions.items():
                    parms = [
                        sub_alarm_def.id,
                        name.encode('utf8'),
                        value.encode('utf8')
                    ]

                    cursor.execute(sub_query, parms)

            # Delete old alarm actions
            if patch:
                if alarm_actions is not None:
                    self._delete_alarm_actions(cursor, alarm_definition_id,
                                               'ALARM')
                if ok_actions is not None:
                    self._delete_alarm_actions(cursor, alarm_definition_id,
                                               'OK')
                if undetermined_actions is not None:
                    self._delete_alarm_actions(cursor, alarm_definition_id,
                                               'UNDETERMINED')
            else:
                query = """
                    delete from alarm_action
                    where alarm_definition_id = %s"""

                parms = [alarm_definition_id]

                cursor.execute(query, parms)

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

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

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

            # Get the updated alarm definition from the DB
            parms = [tenant_id, alarm_definition_id]

            where_clause = """ where ad.tenant_id = %s
                            and ad.id = %s
                            and deleted_at is NULL """

            query = AlarmDefinitionsRepository.base_query + where_clause

            cursor.execute(query, parms)

            if cursor.rowcount < 1:
                raise Exception("Failed to find current alarm definition")

            updated_row = cursor.fetchall()[0]

            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