monasca-api/monasca_api/common/repositories/sqla/alarm_definitions_repositor...

803 lines
35 KiB
Python

# (C) Copyright 2014-2017 Hewlett Packard Enterprise Development LP
# Copyright 2016 FUJITSU LIMITED
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import datetime
import six
from oslo_utils import encodeutils
from oslo_utils import uuidutils
from sqlalchemy import MetaData, update, delete, insert
from sqlalchemy import select, text, bindparam, null, literal_column
from sqlalchemy import or_
from monasca_api.common.repositories import alarm_definitions_repository as adr
from monasca_api.common.repositories import exceptions
from monasca_api.common.repositories.model import sub_alarm_definition
from monasca_api.common.repositories.sqla import models
from monasca_api.common.repositories.sqla import sql_repository
class AlarmDefinitionsRepository(sql_repository.SQLRepository,
adr.AlarmDefinitionsRepository):
def __init__(self):
super(AlarmDefinitionsRepository, self).__init__()
metadata = MetaData()
self.a = models.create_a_model(metadata)
self.aa = models.create_aa_model(metadata)
self.ad = models.create_ad_model(metadata)
self.am = models.create_am_model(metadata)
self.nm = models.create_nm_model(metadata)
self.md = models.create_md_model(metadata)
self.mde = models.create_mde_model(metadata)
self.mdd = models.create_mdd_model(metadata)
self.sa = models.create_sa_model(metadata)
self.sad = models.create_sad_model(metadata)
self.sadd = models.create_sadd_model(metadata)
a = self.a
aa = self.aa
ad = self.ad
am = self.am
nm = self.nm
md = self.md
sa = self.sa
mdd = self.mdd
mde = self.mde
sad = self.sad
sadd = self.sadd
a_s = a.alias('a')
ad_s = ad.alias('ad')
self.ad_s = ad_s
am_s = am.alias('am')
nm_s = nm.alias('nm')
md_s = md.alias('md')
sa_s = sa.alias('sa')
mdd_s = mdd.alias('mdd')
mde_s = mde.alias('mde')
sad_s = sad.alias('sad')
sadd_s = sadd.alias('sadd')
aaa_aa = aa.alias('aaa_aa')
aaa = (select([aaa_aa.c.alarm_definition_id,
models.group_concat([aaa_aa.c.action_id]).label('alarm_actions')])
.select_from(aaa_aa)
.where(aaa_aa.c.alarm_state == text("'ALARM'"))
.group_by(aaa_aa.c.alarm_definition_id)
.alias('aaa'))
aao_aa = aa.alias('aao_aa')
aao = (select([aao_aa.c.alarm_definition_id,
models.group_concat([aao_aa.c.action_id]).label('ok_actions')])
.select_from(aao_aa)
.where(aao_aa.c.alarm_state == text("'OK'"))
.group_by(aao_aa.c.alarm_definition_id)
.alias('aao'))
aau_aa = aa.alias('aau_aa')
aau = (select([aau_aa.c.alarm_definition_id,
models.group_concat([aau_aa.c.action_id]).label('undetermined_actions')])
.select_from(aau_aa)
.where(aau_aa.c.alarm_state == text("'UNDETERMINED'"))
.group_by(aau_aa.c.alarm_definition_id)
.alias('aau'))
self.base_query_from = (ad_s.outerjoin(aaa, aaa.c.alarm_definition_id == ad_s.c.id)
.outerjoin(aao, aao.c.alarm_definition_id == ad_s.c.id)
.outerjoin(aau, aau.c.alarm_definition_id == ad_s.c.id))
self.base_query = (select([ad_s.c.id,
ad_s.c.name,
ad_s.c.description,
ad_s.c.expression,
ad_s.c.match_by,
ad_s.c.severity,
ad_s.c.actions_enabled,
aaa.c.alarm_actions,
aao.c.ok_actions,
aau.c.undetermined_actions]))
self.get_sub_alarms_query = (
select(
[
sa_s.c.id.label('sub_alarm_id'),
sa_s.c.alarm_id,
sa_s.c.expression]) .select_from(
sa_s.join(
a_s,
a_s.c.id == sa_s.c.alarm_id) .join(
ad_s,
ad_s.c.id == a_s.c.alarm_definition_id)) .where(
ad_s.c.tenant_id == bindparam('b_tenant_id')) .where(
ad_s.c.id == bindparam('b_id')) .distinct())
mdg = (select([md_s.c.dimension_set_id,
models.group_concat(
[md_s.c.name + text("'='") + md_s.c.value]).label('dimensions')])
.select_from(md_s)
.group_by(md_s.c.dimension_set_id)
.alias('mdg'))
self.get_alarm_metrics_query = (
select(
[a_s.c.id.label('alarm_id'),
mde_s.c.name,
mdg.c.dimensions]) .select_from(
a_s.join(
ad_s,
ad_s.c.id == a_s.c.alarm_definition_id) .join(
am_s,
am_s.c.alarm_id == a_s.c.id) .join(
mdd_s,
mdd_s.c.id == am_s.c.metric_definition_dimensions_id) .join(
mde_s,
mde_s.c.id == mdd_s.c.metric_definition_id) .outerjoin(
mdg,
mdg.c.dimension_set_id == mdd_s.c.metric_dimension_set_id)) .where(
ad_s.c.tenant_id == bindparam('b_tenant_id')) .where(
ad_s.c.id == bindparam('b_id')) .order_by(
a_s.c.id) .distinct())
self.soft_delete_ad_query = (update(ad)
.where(ad.c.tenant_id == bindparam('b_tenant_id'))
.where(ad.c.id == bindparam('b_id'))
.where(ad.c.deleted_at == null())
.values(deleted_at=datetime.datetime.utcnow()))
self.delete_a_query = (delete(a)
.where(a.c.alarm_definition_id == bindparam('b_id')))
columns_gc = [sadd_s.c.dimension_name + text("'='") + sadd_s.c.value]
saddg = (select([sadd_s.c.sub_alarm_definition_id,
models.group_concat(columns_gc).label('dimensions')])
.select_from(sadd_s)
.group_by(sadd_s.c.sub_alarm_definition_id)
.alias('saddg'))
self.get_sub_alarm_definitions_query = (
select(
[
sad_s,
saddg.c.dimensions]) .select_from(
sad_s.outerjoin(
saddg,
saddg.c.sub_alarm_definition_id == sad_s.c.id)) .where(
sad_s.c.alarm_definition_id == bindparam('b_alarm_definition_id')))
self.create_alarm_definition_insert_ad_query = (
insert(ad) .values(
id=bindparam('b_id'),
tenant_id=bindparam('b_tenant_id'),
name=bindparam('b_name'),
description=bindparam('b_description'),
expression=bindparam('b_expression'),
severity=bindparam('b_severity'),
match_by=bindparam('b_match_by'),
actions_enabled=bindparam('b_actions_enabled'),
created_at=bindparam('b_created_at'),
updated_at=bindparam('b_updated_at')))
self.create_alarm_definition_insert_sad_query = (
insert(sad) .values(
id=bindparam('b_id'),
alarm_definition_id=bindparam('b_alarm_definition_id'),
function=bindparam('b_function'),
metric_name=bindparam('b_metric_name'),
operator=bindparam('b_operator'),
threshold=bindparam('b_threshold'),
period=bindparam('b_period'),
periods=bindparam('b_periods'),
is_deterministic=bindparam('b_is_deterministic'),
created_at=bindparam('b_created_at'),
updated_at=bindparam('b_updated_at')))
b_sad_id = bindparam('b_sub_alarm_definition_id')
self.create_alarm_definition_insert_sadd_query = (
insert(sadd) .values(
sub_alarm_definition_id=b_sad_id,
dimension_name=bindparam('b_dimension_name'),
value=bindparam('b_value')))
self.update_or_patch_alarm_definition_update_ad_query = (
update(ad) .where(
ad.c.tenant_id == bindparam('b_tenant_id')) .where(
ad.c.id == bindparam('b_id')))
self.update_or_patch_alarm_definition_delete_sad_query = (
delete(sad) .where(sad.c.id == bindparam('b_id')))
self.update_or_patch_alarm_definition_update_sad_query = (
update(sad) .where(
sad.c.id == bindparam('b_id')) .values(
operator=bindparam('b_operator'),
threshold=bindparam('b_threshold'),
is_deterministic=bindparam('b_is_deterministic'),
updated_at=bindparam('b_updated_at')))
b_ad_id = bindparam('b_alarm_definition_id'),
self.update_or_patch_alarm_definition_insert_sad_query = (
insert(sad) .values(
id=bindparam('b_id'),
alarm_definition_id=b_ad_id,
function=bindparam('b_function'),
metric_name=bindparam('b_metric_name'),
operator=bindparam('b_operator'),
threshold=bindparam('b_threshold'),
period=bindparam('b_period'),
periods=bindparam('b_periods'),
is_deterministic=bindparam('b_is_deterministic'),
created_at=bindparam('b_created_at'),
updated_at=bindparam('b_updated_at')))
self.update_or_patch_alarm_definition_insert_sadd_query = (
insert(sadd) .values(
sub_alarm_definition_id=b_sad_id,
dimension_name=bindparam('b_dimension_name'),
value=bindparam('b_value')))
self.delete_aa_query = (delete(aa)
.where(aa.c.alarm_definition_id
== bindparam('b_alarm_definition_id')))
self.delete_aa_state_query = (
delete(aa) .where(
aa.c.alarm_definition_id == bindparam('b_alarm_definition_id')) .where(
aa.c.alarm_state == bindparam('b_alarm_state')))
self.select_nm_query = (select([nm_s.c.id])
.select_from(nm_s)
.where(nm_s.c.id == bindparam('b_id')))
self.insert_aa_query = (insert(aa)
.values(
alarm_definition_id=bindparam('b_alarm_definition_id'),
alarm_state=bindparam('b_alarm_state'),
action_id=bindparam('b_action_id')))
@sql_repository.sql_try_catch_block
def get_alarm_definition(self, tenant_id, _id):
with self._db_engine.connect() as conn:
return self._get_alarm_definition(conn, tenant_id, _id)
def _get_alarm_definition(self, conn, tenant_id, _id):
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()))
row = conn.execute(query,
b_tenant_id=tenant_id,
b_id=_id).fetchone()
if row is not None:
return dict(row)
else:
raise exceptions.DoesNotExistException
@sql_repository.sql_try_catch_block
def get_alarm_definitions(self, tenant_id, name=None, dimensions=None, severity=None,
sort_by=None, offset=None, limit=1000):
with self._db_engine.connect() as conn:
ad = self.ad_s
sad = self.sad.alias('sad')
sadd = self.sadd.alias('sadd')
query_from = self.base_query_from
parms = {'b_tenant_id': tenant_id}
if dimensions:
sadi = sad.c.alarm_definition_id
query_from = query_from.join(sad, sadi == ad.c.id)
i = 0
for n, v in dimensions.items():
bind_dimension_name = 'b_sadd_dimension_name_{}'.format(i)
bind_value = 'b_sadd_value_{}'.format(i)
sadd_ = (select([sadd.c.sub_alarm_definition_id])
.select_from(sadd)
.where(sadd.c.dimension_name == bindparam(bind_dimension_name))
.where(sadd.c.value == bindparam(bind_value))
.distinct().alias('saad_{}'.format(i)))
sadd_id = sadd_.c.sub_alarm_definition_id
query_from = query_from.join(sadd_, sadd_id == sad.c.id)
parms[bind_dimension_name] = n.encode('utf8') if six.PY2 else n
parms[bind_value] = v.encode('utf8') if six.PY2 else v
i += 1
query = (self.base_query
.select_from(query_from)
.where(ad.c.tenant_id == bindparam('b_tenant_id'))
.where(ad.c.deleted_at == null()))
if name:
query = query.where(ad.c.name == bindparam('b_name'))
parms['b_name'] = name.encode('utf-8') if six.PY2 else name
if severity:
severities = severity.split('|')
query = query.where(or_(ad.c.severity == bindparam(
'b_severity' + str(i)) for i in range(len(severities))))
for i, s in enumerate(severities):
parms['b_severity' + str(i)] = s.encode('utf-8') if six.PY2 else s
order_columns = []
if sort_by is not None:
order_columns = [literal_column('ad.' + col) for col in sort_by]
if 'id' not in sort_by:
order_columns.append(ad.c.id)
else:
order_columns = [ad.c.id]
if offset:
query = query.offset(bindparam('b_offset'))
parms['b_offset'] = offset
query = query.order_by(*order_columns)
query = query.limit(bindparam('b_limit'))
parms['b_limit'] = limit + 1
return [dict(row) for row in conn.execute(query, parms).fetchall()]
@sql_repository.sql_try_catch_block
def get_sub_alarms(self, tenant_id, alarm_definition_id):
with self._db_engine.connect() as conn:
return [dict(row) for row in conn.execute(self.get_sub_alarms_query,
b_tenant_id=tenant_id,
b_id=alarm_definition_id).fetchall()]
@sql_repository.sql_try_catch_block
def get_alarm_metrics(self, tenant_id, alarm_definition_id):
with self._db_engine.connect() as conn:
return [dict(row) for row in conn.execute(self.get_alarm_metrics_query,
b_tenant_id=tenant_id,
b_id=alarm_definition_id).fetchall()]
@sql_repository.sql_try_catch_block
def delete_alarm_definition(self, tenant_id, alarm_definition_id):
"""Soft delete the alarm definition.
Soft delete the alarm definition and hard delete any associated
alarms.
:param tenant_id:
:param alarm_definition_id:
:returns True: -- if alarm definition exists and was deleted.
:returns False: -- if the alarm definition does not exists.
:raises RepositoryException:
"""
with self._db_engine.begin() as conn:
cursor = conn.execute(self.soft_delete_ad_query,
b_tenant_id=tenant_id,
b_id=alarm_definition_id)
if cursor.rowcount < 1:
return False
conn.execute(self.delete_a_query,
b_tenant_id=tenant_id,
b_id=alarm_definition_id)
return True
@sql_repository.sql_try_catch_block
def get_sub_alarm_definitions(self, alarm_definition_id):
with self._db_engine.connect() as conn:
return self._get_sub_alarm_definitions(conn, alarm_definition_id)
def _get_sub_alarm_definitions(self, conn, alarm_definition_id):
return [
dict(row) for row in conn.execute(
self.get_sub_alarm_definitions_query,
b_alarm_definition_id=alarm_definition_id).fetchall()]
@sql_repository.sql_try_catch_block
def create_alarm_definition(self, tenant_id, name, expression,
sub_expr_list, description, severity, match_by,
alarm_actions, undetermined_actions,
ok_actions):
with self._db_engine.begin() as conn:
now = datetime.datetime.utcnow()
alarm_definition_id = uuidutils.generate_uuid()
conn.execute(self.create_alarm_definition_insert_ad_query,
b_id=alarm_definition_id,
b_tenant_id=tenant_id,
b_name=name.encode('utf8'),
b_description=description.encode('utf8'),
b_expression=expression.encode('utf8'),
b_severity=severity.upper().encode('utf8'),
b_match_by=",".join(match_by).encode('utf8'),
b_actions_enabled=True,
b_created_at=now,
b_updated_at=now)
for sub_expr in sub_expr_list:
sub_alarm_definition_id = uuidutils.generate_uuid()
sub_expr.id = sub_alarm_definition_id
metric_name = sub_expr.metric_name.encode("utf8")
operator = sub_expr.normalized_operator.encode('utf8')
conn.execute(self.create_alarm_definition_insert_sad_query,
b_id=sub_alarm_definition_id,
b_alarm_definition_id=alarm_definition_id,
b_function=sub_expr.normalized_func.encode('utf8'),
b_metric_name=metric_name,
b_operator=operator,
b_threshold=sub_expr.threshold,
b_period=sub_expr.period,
b_periods=sub_expr.periods,
b_is_deterministic=sub_expr.deterministic,
b_created_at=now,
b_updated_at=now)
for dimension in sub_expr.dimensions_as_list:
parsed_dimension = dimension.split('=')
query = self.create_alarm_definition_insert_sadd_query
sadi = sub_alarm_definition_id
dimension_name = parsed_dimension[0].encode('utf8')
conn.execute(query,
b_sub_alarm_definition_id=sadi,
b_dimension_name=dimension_name,
b_value=parsed_dimension[1].encode('utf8'))
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")
return alarm_definition_id
@sql_repository.sql_try_catch_block
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_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.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)
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') if six.PY2 \
else sub_alarm_def.function
metric_name = sub_alarm_def.metric_name.encode('utf8') if six.PY2 \
else sub_alarm_def.metric_name
operator = sub_alarm_def.operator.encode('utf8') if six.PY2 \
else sub_alarm_def.operator
threshold = sub_alarm_def.threshold
period = sub_alarm_def.period
periods = sub_alarm_def.periods
is_deterministic = sub_alarm_def.is_deterministic
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_is_deterministic': is_deterministic,
'b_created_at': now,
'b_updated_at': now})
for name, value in sub_alarm_def.dimensions.items():
sadi = sub_alarm_def.id
b_dimension_name = name .encode('utf8') if six.PY2 else name
b_value = value.encode('utf8') if six.PY2 else value
parms_sadd.append({'b_sub_alarm_definition_id': sadi,
'b_dimension_name': b_dimension_name,
'b_value': b_value})
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
def _determine_sub_expr_changes(self, alarm_definition_id,
old_sub_alarm_defs_by_id,
sub_expr_list):
old_sub_alarm_defs_set = set(
old_sub_alarm_defs_by_id.values())
new_sub_alarm_defs_set = set()
for sub_expr in sub_expr_list:
sad = sub_alarm_definition.SubAlarmDefinition(
sub_expr=sub_expr)
# Inject the alarm definition id.
sad.alarm_definition_id = alarm_definition_id.decode('utf8') if six.PY2 \
else alarm_definition_id
new_sub_alarm_defs_set.add(sad)
# Identify old or changed expressions
old_or_changed_sub_alarm_defs_set = (
old_sub_alarm_defs_set - new_sub_alarm_defs_set)
# Identify new or changed expressions
new_or_changed_sub_alarm_defs_set = (
new_sub_alarm_defs_set - old_sub_alarm_defs_set)
# Find changed expressions. O(n^2) == bad!
# This algo may not work if sub expressions are duplicated.
changed_sub_alarm_defs_by_id = {}
old_or_changed_sub_alarm_defs_set_to_remove = set()
new_or_changed_sub_alarm_defs_set_to_remove = set()
for old_or_changed in old_or_changed_sub_alarm_defs_set:
for new_or_changed in new_or_changed_sub_alarm_defs_set:
if old_or_changed.same_key_fields(new_or_changed):
old_or_changed_sub_alarm_defs_set_to_remove.add(
old_or_changed
)
new_or_changed_sub_alarm_defs_set_to_remove.add(
new_or_changed
)
changed_sub_alarm_defs_by_id[
old_or_changed.id] = (
new_or_changed)
# patch id:
changed_sub_alarm_defs_by_id[
old_or_changed.id].id = old_or_changed.id
old_or_changed_sub_alarm_defs_set = (
old_or_changed_sub_alarm_defs_set -
old_or_changed_sub_alarm_defs_set_to_remove
)
new_or_changed_sub_alarm_defs_set = (
new_or_changed_sub_alarm_defs_set -
new_or_changed_sub_alarm_defs_set_to_remove
)
# Create the list of unchanged expressions
unchanged_sub_alarm_defs_by_id = (
old_sub_alarm_defs_by_id.copy())
for old_sub_alarm_def in old_or_changed_sub_alarm_defs_set:
del unchanged_sub_alarm_defs_by_id[old_sub_alarm_def.id]
for sub_alarm_definition_id in (
changed_sub_alarm_defs_by_id.keys()):
del unchanged_sub_alarm_defs_by_id[
sub_alarm_definition_id]
# Remove old sub expressions
temp = {}
for old_sub_alarm_def in old_or_changed_sub_alarm_defs_set:
temp[old_sub_alarm_def.id] = old_sub_alarm_def
old_sub_alarm_defs_by_id = temp
# Create IDs for new expressions
new_sub_alarm_defs_by_id = {}
for new_sub_alarm_def in new_or_changed_sub_alarm_defs_set:
sub_alarm_definition_id = uuidutils.generate_uuid()
new_sub_alarm_def.id = sub_alarm_definition_id
new_sub_alarm_defs_by_id[sub_alarm_definition_id] = (
new_sub_alarm_def)
return (changed_sub_alarm_defs_by_id,
new_sub_alarm_defs_by_id,
old_sub_alarm_defs_by_id,
unchanged_sub_alarm_defs_by_id)
def _delete_alarm_actions(self, conn, _id, alarm_action_name):
conn.execute(self.delete_aa_state_query,
b_alarm_definition_id=_id,
b_alarm_state=alarm_action_name)
def _insert_into_alarm_action(self, conn, alarm_definition_id, actions,
alarm_state):
if actions is None:
return
for action in actions:
b_id = action.encode('utf8') if six.PY2 else action
row = conn.execute(self.select_nm_query,
b_id=b_id).fetchone()
if row is None:
raise exceptions.InvalidUpdateException(
"Non-existent notification id {} submitted for {} "
"notification action".format(encodeutils.to_utf8(action),
encodeutils.to_utf8(alarm_state)))
conn.execute(self.insert_aa_query,
b_alarm_definition_id=alarm_definition_id,
b_alarm_state=alarm_state.encode('utf8') if six.PY2 else alarm_state,
b_action_id=action.encode('utf8') if six.PY2 else action
)