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