config/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/event_log.py

291 lines
10 KiB
Python

#!/usr/bin/env python
# Copyright (c) 2013-2016 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import datetime
from oslo_utils import timeutils
import pecan
from pecan import rest
import wsme
from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan
from sysinv.api.controllers.v1 import alarm_utils
from sysinv.api.controllers.v1 import base
from sysinv.api.controllers.v1 import collection
from sysinv.api.controllers.v1 import link
from sysinv.api.controllers.v1.query import Query
from sysinv.api.controllers.v1 import types
from sysinv.api.controllers.v1 import utils as api_utils
from sysinv.common import exception
from sysinv import objects
from sysinv.openstack.common.gettextutils import _
from sysinv.openstack.common import log
LOG = log.getLogger(__name__)
import json
def prettyDict(dict):
output = json.dumps(dict, sort_keys=True, indent=4)
return output
class EventLogPatchType(types.JsonPatchType):
pass
class EventLog(base.APIBase):
"""API representation of an event log.
This class enforces type checking and value constraints, and converts
between the internal object model and the API representation of
a event_log.
"""
uuid = types.uuid
"The UUID of the event_log"
event_log_id = wsme.wsattr(wtypes.text, mandatory=True)
"structured id for the event log; AREA_ID ID; 300-001"
state = wsme.wsattr(wtypes.text, mandatory=True)
"The state of the event"
entity_type_id = wtypes.text
"The type of the object event log"
entity_instance_id = wsme.wsattr(wtypes.text, mandatory=True)
"The original instance information of the object creating event log"
timestamp = datetime.datetime
"The time in UTC at which the event log is generated"
severity = wsme.wsattr(wtypes.text, mandatory=True)
"The severity of the log"
reason_text = wtypes.text
"The reason why the log is generated"
event_log_type = wsme.wsattr(wtypes.text, mandatory=True)
"The type of the event log"
probable_cause = wsme.wsattr(wtypes.text, mandatory=True)
"The probable cause of the event log"
proposed_repair_action = wtypes.text
"The action to clear the alarm"
service_affecting = wtypes.text
"Whether the log affects the service"
suppression = wtypes.text
"'allowed' or 'not-allowed'"
suppression_status = wtypes.text
"'suppressed' or 'unsuppressed'"
links = [link.Link]
"A list containing a self link and associated community string links"
def __init__(self, **kwargs):
self.fields = objects.event_log.fields.keys()
for k in self.fields:
setattr(self, k, kwargs.get(k))
@classmethod
def convert_with_links(cls, rpc_event_log, expand=True):
if isinstance(rpc_event_log, tuple):
ievent_log = rpc_event_log[0]
suppress_status = rpc_event_log[1]
else:
ievent_log = rpc_event_log
suppress_status = rpc_event_log.suppression_status
if not expand:
ievent_log['service_affecting'] = str(ievent_log['service_affecting'])
ievent_log['suppression'] = str(ievent_log['suppression'])
ilog = EventLog(**ievent_log.as_dict())
if not expand:
ilog.unset_fields_except(['uuid', 'event_log_id', 'entity_instance_id',
'severity', 'timestamp', 'reason_text', 'state'])
ilog.entity_instance_id = \
alarm_utils.make_display_id(ilog.entity_instance_id, replace=False)
ilog.suppression_status = str(suppress_status)
return ilog
def _getEventType(alarms=False, logs=False):
if alarms is False and logs is False:
return "ALL"
if alarms is True and logs is True:
return "ALL"
if logs is True:
return "LOG"
if alarms is True:
return "ALARM"
return "ALL"
class EventLogCollection(collection.Collection):
"""API representation of a collection of event_log."""
event_log = [EventLog]
"A list containing event_log objects"
def __init__(self, **kwargs):
self._type = 'event_log'
@classmethod
def convert_with_links(cls, ilog, limit=None, url=None,
expand=False, **kwargs):
ilogs = []
for a in ilog:
ilogs.append(a)
collection = EventLogCollection()
collection.event_log = [EventLog.convert_with_links(ch, expand)
for ch in ilogs]
collection.next = collection.get_next(limit, url=url, **kwargs)
return collection
def _handle_bad_input_date(f):
"""
A decorator that executes function f and returns
a more human readable error message on a SQL date exception
"""
def date_handler_wrapper(*args, **kwargs):
try:
return f(*args, **kwargs)
except Exception as e:
import re
e_str = "{}".format(e)
for r in [".*date/time field value out of range: \"(.*)\".*LINE",
".*invalid input syntax for type timestamp: \"(.*)\".*",
".*timestamp out of range: \"(.*)\".*"]:
p = re.compile(r, re.DOTALL)
m = p.match(e_str)
if m and len(m.groups()) > 0:
bad_date = m.group(1)
raise wsme.exc.ClientSideError(_("Invalid date '{}' specified".format(bad_date)))
raise
return date_handler_wrapper
class EventLogController(rest.RestController):
"""REST controller for eventlog."""
_custom_actions = {
'detail': ['GET'],
}
@_handle_bad_input_date
def _get_eventlog_collection(self, marker, limit, sort_key, sort_dir,
expand=False, resource_url=None,
q=None, alarms=False, logs=False,
include_suppress=False):
if limit and limit < 0:
raise wsme.exc.ClientSideError(_("Limit must be positive"))
sort_dir = api_utils.validate_sort_dir(sort_dir)
kwargs = {}
if q is not None:
for i in q:
if i.op == 'eq':
if i.field == 'start' or i.field == 'end':
val = timeutils.normalize_time(
timeutils.parse_isotime(i.value)
.replace(tzinfo=None))
i.value = val.isoformat()
kwargs[i.field] = i.value
evtType = _getEventType(alarms, logs)
kwargs["evtType"] = evtType
kwargs["include_suppress"] = include_suppress
if marker:
marker_obj = objects.event_log.get_by_uuid(pecan.request.context,
marker)
ilog = pecan.request.dbapi.event_log_get_list(limit, marker_obj,
sort_key=sort_key,
sort_dir=sort_dir,
evtType=evtType,
include_suppress=include_suppress)
else:
kwargs['limit'] = limit
ilog = pecan.request.dbapi.event_log_get_all(**kwargs)
return EventLogCollection.convert_with_links(ilog, limit,
url=resource_url,
expand=expand,
sort_key=sort_key,
sort_dir=sort_dir)
@wsme_pecan.wsexpose(EventLogCollection, [Query],
types.uuid, int, wtypes.text, wtypes.text, bool, bool, bool)
def get_all(self, q=[], marker=None, limit=None, sort_key='timestamp',
sort_dir='desc', alarms=False, logs=False, include_suppress=False):
"""Retrieve a list of event_log.
:param marker: pagination marker for large data sets.
:param limit: maximum number of resources to return in a single result.
:param sort_key: column to sort results by. Default: id.
:param sort_dir: direction to sort. "asc" or "desc". Default: asc.
:param alarms: filter on alarms. Default: False
:param logs: filter on logs. Default: False
:param include_suppress: filter on suppressed alarms. Default: False
"""
return self._get_eventlog_collection(marker, limit, sort_key,
sort_dir, q=q, alarms=alarms, logs=logs,
include_suppress=include_suppress)
@wsme_pecan.wsexpose(EventLogCollection, types.uuid, int,
wtypes.text, wtypes.text, bool, bool)
def detail(self, marker=None, limit=None, sort_key='id', sort_dir='asc', alarms=False, logs=False):
"""Retrieve a list of event_log with detail.
:param marker: pagination marker for large data sets.
:param limit: maximum number of resources to return in a single result.
:param sort_key: column to sort results by. Default: id.
:param sort_dir: direction to sort. "asc" or "desc". Default: asc.
:param alarms: filter on alarms. Default: False
:param logs: filter on logs. Default: False
"""
# /detail should only work against collections
parent = pecan.request.path.split('/')[:-1][-1]
if parent != "event_log":
raise exception.HTTPNotFound
expand = True
resource_url = '/'.join(['event_log', 'detail'])
return self._get_eventlog_collection(marker, limit, sort_key, sort_dir,
expand, resource_url, None, alarms, logs)
@wsme_pecan.wsexpose(EventLog, wtypes.text)
def get_one(self, id):
"""Retrieve information about the given event_log.
:param id: UUID of an event_log.
"""
rpc_ilog = objects.event_log.get_by_uuid(
pecan.request.context, id)
return EventLog.convert_with_links(rpc_ilog)