e9ba02ab5c
This commit complements the previous commit with same topic: https://review.opendev.org/c/starlingx/fault/+/815381 This particular commit improves the log inside the python script, considering others possible fails. Also, some verifications are added in fmDbUtils class wich calls the script. Test Plan: Log in (/var/log/platform.log): PASS: Log arguments error calling script. PASS: Log new database connection problems. PASS: Log Session commit problems. PASS: Log problems opening "/etc/fm/events.yaml" file. Log (in /var/log/fm-manager.log): PASS: Log Problems opening fm_db_sync_event_suppression.py file. PASS: Log problems running fm_db_sync_event_suppression.py. PASS: build and install package. Closes-bug: 1932324 Signed-off-by: fperez <fabrizio.perez@windriver.com> Change-Id: I913d6d1282bea346f87f73179f0738c0c17d7446
216 lines
7.1 KiB
Python
Executable File
216 lines
7.1 KiB
Python
Executable File
#!/usr/bin/python3
|
|
# Copyright (c) 2016-2021 Wind River Systems, Inc.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
|
|
import sys
|
|
import os
|
|
import json
|
|
import datetime
|
|
import errno
|
|
import uuid as uuid_gen
|
|
|
|
import yaml
|
|
import collections
|
|
|
|
import sqlalchemy
|
|
from sqlalchemy.orm import sessionmaker
|
|
from sqlalchemy.ext.declarative import declarative_base
|
|
from sqlalchemy import Column
|
|
from sqlalchemy import Boolean
|
|
from sqlalchemy import Integer
|
|
from sqlalchemy import String
|
|
from sqlalchemy import DateTime
|
|
from sqlalchemy import exc
|
|
|
|
import fm_log as log
|
|
|
|
LOG = log.get_logger(__name__)
|
|
|
|
Base = declarative_base()
|
|
|
|
|
|
class EventSuppression(Base):
|
|
__tablename__ = 'event_suppression'
|
|
created_at = Column('created_at', DateTime)
|
|
id = Column('id', Integer, primary_key=True, nullable=False)
|
|
uuid = Column('uuid', String(36), unique=True)
|
|
alarm_id = Column('alarm_id', String(255), unique=True)
|
|
description = Column('description', String(255))
|
|
suppression_status = Column('suppression_status', String(255))
|
|
set_for_deletion = Column('set_for_deletion', Boolean)
|
|
mgmt_affecting = Column('mgmt_affecting', String(255))
|
|
degrade_affecting = Column('degrade_affecting', String(255))
|
|
|
|
|
|
class ialarm(Base):
|
|
__tablename__ = 'alarm'
|
|
id = Column(Integer, primary_key=True, nullable=False)
|
|
alarm_id = Column('alarm_id', String(255), index=True)
|
|
|
|
|
|
class event_log(Base):
|
|
__tablename__ = 'event_log'
|
|
id = Column(Integer, primary_key=True, nullable=False)
|
|
event_log_id = Column('event_log_id', String(255), index=True)
|
|
state = Column(String(255))
|
|
|
|
|
|
def prettyDict(dict):
|
|
output = json.dumps(dict, sort_keys=True, indent=4)
|
|
return output
|
|
|
|
|
|
def get_events_yaml_filename():
|
|
events_yaml_name = os.environ.get("EVENTS_YAML")
|
|
if events_yaml_name is not None and os.path.isfile(events_yaml_name):
|
|
return events_yaml_name
|
|
return "/etc/fm/events.yaml"
|
|
|
|
|
|
#
|
|
# Main
|
|
#
|
|
|
|
if len(sys.argv) < 2:
|
|
msg = 'Postgres credentials required as argument.'
|
|
LOG.error(msg)
|
|
raise ValueError(msg)
|
|
|
|
postgresql_credentials = str(sys.argv[1])
|
|
|
|
# Set up logging:
|
|
current_file_name = __file__
|
|
current_file_name = current_file_name[2:] # remove leading characters "./"
|
|
|
|
# Set up sqlalchemy:
|
|
try:
|
|
meta = sqlalchemy.MetaData()
|
|
engine = sqlalchemy.create_engine(postgresql_credentials)
|
|
meta.bind = engine
|
|
Session = sessionmaker(bind=engine)
|
|
session = Session()
|
|
except exc.SQLAlchemyError as exp:
|
|
LOG.error(exp)
|
|
raise RuntimeError(exp)
|
|
|
|
# Convert events.yaml to dict:
|
|
LOG.info("Converting events.yaml to dict: ")
|
|
EVENT_TYPES_FILE = get_events_yaml_filename()
|
|
|
|
if not os.path.isfile(EVENT_TYPES_FILE):
|
|
LOG.error("file %s doesn't exist. Ending execution" % (EVENT_TYPES_FILE))
|
|
raise OSError(
|
|
errno.ENOENT, os.strerror(errno.ENOENT), EVENT_TYPES_FILE
|
|
)
|
|
|
|
try:
|
|
with open(EVENT_TYPES_FILE, 'r') as stream:
|
|
event_types = yaml.load(stream)
|
|
except Exception as exp:
|
|
LOG.error(exp)
|
|
raise RuntimeError(exp)
|
|
|
|
for alarm_id in list(event_types.keys()):
|
|
if isinstance(alarm_id, float):
|
|
# force 3 digits after the decimal point,
|
|
# to include trailing zero's (ex.: 200.010)
|
|
formatted_alarm_id = "{:.3f}".format(alarm_id)
|
|
event_types[formatted_alarm_id] = event_types.pop(alarm_id)
|
|
|
|
event_types = collections.OrderedDict(sorted(event_types.items()))
|
|
|
|
yaml_event_list = []
|
|
uneditable_descriptions = {'100.114', '200.007', '200.02', '200.021', '200.022', '800.002'}
|
|
|
|
# Parse events.yaml dict, and add any new alarm to event_suppression table:
|
|
LOG.info("Parsing events.yaml and adding any new alarm to event_suppression table: ")
|
|
for event_type in event_types:
|
|
|
|
if event_types.get(event_type).get('Type') == "Alarm":
|
|
event_created_at = datetime.datetime.now()
|
|
event_uuid = str(uuid_gen.uuid4())
|
|
|
|
string_event_type = str(event_type)
|
|
|
|
yaml_event_list.append(string_event_type)
|
|
|
|
if str(event_type) not in uneditable_descriptions:
|
|
event_description = (event_types.get(event_type)
|
|
.get('Description'))
|
|
else:
|
|
event_description = event_types.get(event_type).get('Description')
|
|
|
|
event_description = str(event_description)
|
|
event_description = (event_description[:250] + ' ...') \
|
|
if len(event_description) > 250 else event_description
|
|
|
|
try:
|
|
event_supp = session.query(EventSuppression) \
|
|
.filter_by(alarm_id=string_event_type).first()
|
|
except exc.SQLAlchemyError as exp:
|
|
LOG.error(exp)
|
|
|
|
event_mgmt_affecting = str(event_types.get(event_type).get(
|
|
'Management_Affecting_Severity', 'warning'))
|
|
|
|
event_degrade_affecting = str(event_types.get(event_type).get(
|
|
'Degrade_Affecting_Severity', 'none'))
|
|
|
|
if event_supp:
|
|
event_supp.description = event_description
|
|
event_supp.mgmt_affecting = event_mgmt_affecting
|
|
event_supp.degrade_affecting = event_degrade_affecting
|
|
else:
|
|
event_supp = EventSuppression(created_at=event_created_at,
|
|
uuid=event_uuid,
|
|
alarm_id=string_event_type,
|
|
description=event_description,
|
|
suppression_status='unsuppressed',
|
|
set_for_deletion=False,
|
|
mgmt_affecting=event_mgmt_affecting,
|
|
degrade_affecting=event_degrade_affecting)
|
|
session.add(event_supp)
|
|
LOG.info("Created Event Type: %s in event_suppression table." % (string_event_type))
|
|
|
|
try:
|
|
session.commit()
|
|
except exc.SQLAlchemyError as exp:
|
|
LOG.error(exp)
|
|
raise RuntimeError(exp)
|
|
|
|
event_supp = session.query(EventSuppression)
|
|
alarms = session.query(ialarm)
|
|
events = session.query(event_log).filter(event_log.state != 'log')
|
|
|
|
alarm_ids_in_use = set()
|
|
for alarm in alarms:
|
|
alarm_ids_in_use.add(alarm.alarm_id)
|
|
|
|
for event in events:
|
|
alarm_ids_in_use.add(event.event_log_id)
|
|
|
|
for event_type in event_supp:
|
|
if event_type.alarm_id not in yaml_event_list:
|
|
if event_type.alarm_id not in alarm_ids_in_use:
|
|
event_supp = session.query(EventSuppression) \
|
|
.filter_by(alarm_id=event_type.alarm_id).first()
|
|
session.delete(event_supp)
|
|
LOG.info("Deleted Event Type: %s from event_suppression table." % (event_type.alarm_id))
|
|
else:
|
|
event_supp.suppression_status = 'unsuppressed'
|
|
event_supp.set_for_deletion = True
|
|
LOG.info("Event Type: %s no longer in events.yaml, but still used by alarm in database." % (event_type.alarm_id))
|
|
LOG.info("Event Type: %s marked as set for deletion in event_suppression table." % (event_type.alarm_id))
|
|
|
|
try:
|
|
session.commit()
|
|
except exc.SQLAlchemyError as exp:
|
|
LOG.error(exp)
|
|
raise RuntimeError(exp)
|
|
|
|
session.close()
|
|
|
|
LOG.debug("Normally exiting from: %s" % (__file__))
|