monasca-analytics/monasca_analytics/util/common_util.py

291 lines
9.4 KiB
Python

#!/usr/bin/env python
# Copyright (c) 2016 Hewlett Packard Enterprise Development Company, L.P.
#
# 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.
"""Common util functions."""
import importlib
import inspect
import json
import logging
from logging import config as log_conf
import os
import pkgutil
from monasca_analytics.config import const
from monasca_analytics.exception import monanas as err
from monasca_analytics import ingestor
from monasca_analytics import ldp
from monasca_analytics import sink
from monasca_analytics import sml
from monasca_analytics import source
from monasca_analytics import voter
logger = logging.getLogger(__name__)
def parse_json_file(filename):
"""Parses json and return a dict.
:type filename: str
:param filename: Filename to be parsed to a dictionary.
:rtype: dict
:returns: Parsed data.
:raises: IOError --If the file does not exist.
:raises: ValueError -- If the file is an invalid json file.
"""
try:
with open(filename, "rt") as f:
return json.load(f)
except (IOError, ValueError) as e:
logger.error("Exception parsing json file : " + str(e))
raise
def setup_logging(filename):
"""Setup logging based on a json string.
:type filename: str
:param filename: Log configuration file.
:raises: IOError -- If the file does not exist.
:raises: ValueError -- If the file is an invalid json file.
"""
try:
config = parse_json_file(filename)
log_conf.dictConfig(config)
logpy4j = logging.getLogger("py4j")
logpy4j.setLevel(logging.ERROR)
logkafka = logging.getLogger("kafka")
logkafka.setLevel(logging.ERROR)
except (IOError, ValueError):
raise
def get_available_inherited_classes(pkg, base_class):
"""Gets all inherited classes in modules for a given package
This does not include subpackages.
:type pkg: str
:param pkg: a package name.
:type base_class: object
:param base_class: a base class.
:rtype: list
:returns: a list of inherited classes.
"""
available_classes = []
pkg_path = os.path.dirname(pkg.__file__)
for _, mod_name, _ in pkgutil.iter_modules([pkg_path]):
if not mod_name.startswith("_"):
try:
module = importlib.import_module("{0}.{1}".format(pkg.__name__,
mod_name))
for clazz in inspect.getmembers(module, inspect.isclass):
if clazz is not base_class:
if issubclass(clazz[1], base_class) and\
not inspect.isabstract(clazz[1]) and\
clazz[1] != base_class:
available_classes.append(clazz[1])
except Exception as e:
logger.warn(e.__str__())
return set(available_classes)
def get_available_classes(class_type=None):
"""Creates a dictionary containing pipeline available classes of each type
:type class_type: str | None
:param class_type: if provided, only this type of classes
will be returned
:rtype: dict
:returns: all subclasses keyed by type
"""
_classes = {}
if not class_type or class_type == const.SOURCES:
from monasca_analytics.source.base import BaseSource
_classes[const.SOURCES] = get_available_inherited_classes(source,
BaseSource)
if not class_type or class_type == const.INGESTORS:
from monasca_analytics.ingestor.base import BaseIngestor
_classes[const.INGESTORS] = \
get_available_inherited_classes(ingestor, BaseIngestor)
if not class_type or class_type == const.SMLS:
from monasca_analytics.sml.base import BaseSML
_classes[const.SMLS] = get_available_inherited_classes(sml, BaseSML)
if not class_type or class_type == const.VOTERS:
from monasca_analytics.voter.base import BaseVoter
_classes[const.VOTERS] = get_available_inherited_classes(voter,
BaseVoter)
if not class_type or class_type == const.SINKS:
from monasca_analytics.sink.base import BaseSink
_classes[const.SINKS] = get_available_inherited_classes(sink, BaseSink)
if not class_type or class_type == const.LDPS:
from monasca_analytics.ldp.base import BaseLDP
_classes[const.LDPS] = \
get_available_inherited_classes(ldp, BaseLDP)
return _classes
def get_component_type(class_name):
for cls_type in const.components_types:
names = get_available_class_names(cls_type)
if class_name in names:
return cls_type
def get_class_by_name(class_name, class_type=None):
"""Gets the class by class name.
:type class_name: str
:param class_name: a class name to look for
:type class_type: str
:param class_type: the type of the class to look for
(e.g. data_sources, ingestors, etc.).
:returns: class -- the source class requested.
:raises: MonanasNoSuchSourceError -- If no source class found.
:raises: MonanasDuplicateSourceError -- If the system has multiple sources
of the same class name.
"""
classes = get_available_classes(class_type)
if class_type:
clazz = list(filter(lambda t_class: t_class.__name__ == class_name,
classes[class_type]))
else:
for c_type in classes.keys():
clazz = list(filter(lambda t_class: t_class.__name__ == class_name,
classes[c_type]))
if clazz:
break
if not clazz:
raise err.MonanasNoSuchClassError(class_name)
elif len(clazz) > 1:
raise err.MonanasDuplicateClassError(class_name)
else:
return clazz[0]
def get_available_class_names(class_type):
"""Gets available class names of type class_type.
:type class_type: str
:param class_type: type of classes to look for
:rtype: list
:returns: a list of available source class names.
"""
classes = get_available_classes(class_type)
return [Clazz.__name__ for Clazz in classes[class_type]]
def get_source_class_by_name(class_name):
"""Gets the source class by class name.
:type class_name: str
:param class_name: name of the source class requested.
:raises: MonanasNoSuchIngestorError -- if no source class found.
:raises: MonanasDuplicateIngestorError -- if the system has multiple
source of the same class name.
"""
return get_class_by_name(class_name, const.SOURCES)
def get_available_source_class_names():
"""Gets available source class names.
:rtype: list
:returns: a list of available source class names.
"""
return get_available_class_names(const.SOURCES)
def get_ingestor_class_by_name(class_name):
"""Gets the ingestor class by class name.
:type class_name: str
:param class_name: name of the ingestor class requested.
:raises: MonanasNoSuchIngestorError -- if no ingestor class found.
:raises: MonanasDuplicateIngestorError -- if the system has multiple
ingestors of the same class name.
"""
return get_class_by_name(class_name, const.INGESTORS)
def get_available_ingestor_class_names():
"""Gets available ingestor class names.
:rtype: list
:returns: a list of available ingestor class names.
"""
return get_available_class_names(const.INGESTORS)
def get_sml_class_by_name(class_name):
"""Gets the sml class by class name.
:type class_name: str
:param class_name: name of the sml class requested.
:raises: MonanasNoSuchIngestorError -- if no sml class found.
:raises: MonanasDuplicateIngestorError -- if the system has multiple sml
algorithms of the same class
name.
"""
return get_class_by_name(class_name, const.SMLS)
def get_available_sml_class_names():
"""Gets available sml class names.
:rtype: list
:returns: a list of available sml class names.
"""
return get_available_class_names(const.SMLS)
def get_voter_class_by_name(class_name):
"""Gets the voter class by class name.
:type class_name: str
:param class_name: name of the voter class requested.
:raises: MonanasNoSuchIngestorError -- If no voter class found.
:raises: MonanasDuplicateIngestorError: If the system has multiple
voter of the same class name.
"""
return get_class_by_name(class_name, const.VOTERS)
def get_available_voter_class_names():
"""Gets available voter class names.
:rtype: list
:returns: a list of available voter class names.
"""
return get_available_class_names(const.VOTERS)
def get_available_ldp_class_names():
"""Gets available ldp class names.
:rtype: list
:returns: a list of available ldp class names.
"""
return get_available_class_names(const.LDPS)