Example #1
0
 def init_generator(self, module, source, node_type, instance_id,
                    collectors, client_context,
                    http_port, sandesh_req_uve_pkg_list=None,
                    discovery_client=None, connect_to_collector=True,
                    logger_class=None, logger_config_file=None,
                    host_ip='127.0.0.1', alarm_ack_callback=None):
     self._role = self.SandeshRole.GENERATOR
     self._module = module
     self._source = source
     self._node_type = node_type
     self._instance_id = instance_id
     self._host_ip = host_ip
     self._client_context = client_context
     self._collectors = collectors
     self._connect_to_collector = connect_to_collector
     self._rcv_queue = WorkQueue(self._process_rx_sandesh)
     self._init_logger(module, logger_class=logger_class,
                       logger_config_file=logger_config_file)
     self._logger.info('SANDESH: CONNECT TO COLLECTOR: %s',
                       connect_to_collector)
     self._stats = SandeshStats()
     self._trace = trace.Trace()
     self._sandesh_request_dict = {}
     self._alarm_ack_callback = alarm_ack_callback
     self._uve_type_maps = SandeshUVETypeMaps(self._logger)
     if sandesh_req_uve_pkg_list is None:
         sandesh_req_uve_pkg_list = []
     # Initialize the request handling
     # Import here to break the cyclic import dependency
     import sandesh_req_impl
     sandesh_req_impl = sandesh_req_impl.SandeshReqImpl(self)
     sandesh_req_uve_pkg_list.append('pysandesh.gen_py')
     for pkg_name in sandesh_req_uve_pkg_list:
         self._create_sandesh_request_and_uve_lists(pkg_name)
     self._gev_httpd = None
     if http_port != -1:
         self._http_server = SandeshHttp(
             self, module, http_port, sandesh_req_uve_pkg_list)
         self._gev_httpd = gevent.spawn(self._http_server.start_http_server)
     primary_collector = None
     secondary_collector = None
     if self._collectors is not None:
         if len(self._collectors) > 0:
             primary_collector = self._collectors[0]
         if len(self._collectors) > 1:
             secondary_collector = self._collectors[1]
     if self._connect_to_collector:
         self._client = SandeshClient(
             self, primary_collector, secondary_collector,
             discovery_client)
         self._client.initiate()
Example #2
0
class Sandesh(object):
    _DEFAULT_LOG_FILE = sand_logger.SandeshLogger._DEFAULT_LOG_FILE
    _DEFAULT_SYSLOG_FACILITY = (
        sand_logger.SandeshLogger._DEFAULT_SYSLOG_FACILITY)

    class SandeshRole:
        INVALID = 0
        GENERATOR = 1
        COLLECTOR = 2
    # end class SandeshRole

    def __init__(self):
        self._context = ''
        self._scope = ''
        self._module = ''
        self._source = ''
        self._node_type = ''
        self._instance_id = ''
        self._timestamp = 0
        self._versionsig = 0
        self._type = 0
        self._hints = 0
        self._client_context = ''
        self._client = None
        self._role = self.SandeshRole.INVALID
        self._logger = None
        self._level = SandeshLevel.INVALID
        self._category = ''
        self._send_queue_enabled = True
        self._http_server = None
        self._connect_to_collector = True
    # end __init__

    # Public functions

    def init_generator(self, module, source, node_type, instance_id,
                       collectors, client_context,
                       http_port, sandesh_req_uve_pkg_list=None,
                       discovery_client=None, connect_to_collector=True,
                       logger_class=None, logger_config_file=None,
                       host_ip='127.0.0.1', alarm_ack_callback=None):
        self._role = self.SandeshRole.GENERATOR
        self._module = module
        self._source = source
        self._node_type = node_type
        self._instance_id = instance_id
        self._host_ip = host_ip
        self._client_context = client_context
        self._collectors = collectors
        self._connect_to_collector = connect_to_collector
        self._rcv_queue = WorkQueue(self._process_rx_sandesh)
        self._init_logger(module, logger_class=logger_class,
                          logger_config_file=logger_config_file)
        self._logger.info('SANDESH: CONNECT TO COLLECTOR: %s',
                          connect_to_collector)
        self._stats = SandeshStats()
        self._trace = trace.Trace()
        self._sandesh_request_dict = {}
        self._alarm_ack_callback = alarm_ack_callback
        self._uve_type_maps = SandeshUVETypeMaps(self._logger)
        if sandesh_req_uve_pkg_list is None:
            sandesh_req_uve_pkg_list = []
        # Initialize the request handling
        # Import here to break the cyclic import dependency
        import sandesh_req_impl
        sandesh_req_impl = sandesh_req_impl.SandeshReqImpl(self)
        sandesh_req_uve_pkg_list.append('pysandesh.gen_py')
        for pkg_name in sandesh_req_uve_pkg_list:
            self._create_sandesh_request_and_uve_lists(pkg_name)
        self._gev_httpd = None
        if http_port != -1:
            self._http_server = SandeshHttp(
                self, module, http_port, sandesh_req_uve_pkg_list)
            self._gev_httpd = gevent.spawn(self._http_server.start_http_server)
        primary_collector = None
        secondary_collector = None
        if self._collectors is not None:
            if len(self._collectors) > 0:
                primary_collector = self._collectors[0]
            if len(self._collectors) > 1:
                secondary_collector = self._collectors[1]
        if self._connect_to_collector:
            self._client = SandeshClient(
                self, primary_collector, secondary_collector,
                discovery_client)
            self._client.initiate()
    # end init_generator

    def uninit(self):
        self.kill_httpd()

    def kill_httpd(self):
        if self._gev_httpd:
            try:
                self._gev_httpd.kill()
            except Exception as e:
                self._logger.debug(str(e))

    def record_port(self, name, port):
        pipe_name = '/tmp/%s.%d.%s_port' % (self._module, os.getppid(), name)
        try:
            pipeout = os.open(pipe_name, os.O_WRONLY)
        except Exception:
            self._logger.error('Cannot write %s_port %d to %s'
                               % (name, port, pipe_name))
        else:
            self._logger.error('Writing %s_port %d to %s'
                               % (name, port, pipe_name))
            os.write(pipeout, '%d\n' % port)
            os.close(pipeout)

    def logger(self):
        return self._logger
    # end logger

    def sandesh_logger(self):
        return self._sandesh_logger
    # end sandesh_logger

    def set_logging_params(self, enable_local_log=False, category='',
                           level=SandeshLevel.SYS_INFO,
                           file=sand_logger.SandeshLogger._DEFAULT_LOG_FILE,
                           enable_syslog=False,
                           syslog_facility=_DEFAULT_SYSLOG_FACILITY,
                           enable_trace_print=False,
                           enable_flow_log=False):
        self._sandesh_logger.set_logging_params(
            enable_local_log=enable_local_log, category=category,
            level=level, file=file, enable_syslog=enable_syslog,
            syslog_facility=syslog_facility,
            enable_trace_print=enable_trace_print,
            enable_flow_log=enable_flow_log)
    # end set_logging_params

    def set_trace_print(self, enable_trace_print):
        self._sandesh_logger.set_trace_print(enable_trace_print)
    # end set_trace_print

    def set_flow_logging(self, enable_flow_log):
        self._sandesh_logger.set_flow_logging(enable_flow_log)
    # end set_flow_logging

    def set_local_logging(self, enable_local_log):
        self._sandesh_logger.set_local_logging(enable_local_log)
    # end set_local_logging

    def set_logging_level(self, level):
        self._sandesh_logger.set_logging_level(level)
    # end set_logging_level

    def set_logging_category(self, category):
        self._sandesh_logger.set_logging_category(category)
    # end set_logging_category

    def set_logging_file(self, file):
        self._sandesh_logger.set_logging_file(file)
    # end set_logging_file

    def is_logging_dropped_allowed(self, sandesh):
        if sandesh.type() == SandeshType.FLOW:
            return self.is_flow_logging_enabled()
        else:
            return True
    # end is_logging_dropped_allowed

    def is_send_queue_enabled(self):
        return self._send_queue_enabled
    # end is_send_queue_enabled

    def is_connect_to_collector_enabled(self):
        return self._connect_to_collector
    # end is_connect_to_collector_enabled

    def set_send_queue(self, enable):
        if self._send_queue_enabled != enable:
            self._logger.info("SANDESH: CLIENT: SEND QUEUE: %s -> %s",
                              self._send_queue_enabled, enable)
            self._send_queue_enabled = enable
            if enable:
                connection = self._client.connection()
                if connection and connection.session():
                    connection.session().send_queue().may_be_start_runner()
    # end set_send_queue

    def init_collector(self):
        pass
    # end init_collector

    def stats(self):
        return self._stats
    # end stats

    @classmethod
    def next_seqnum(cls):
        if not hasattr(cls, '_lseqnum'):
            cls._lseqnum = 1
        else:
            cls._lseqnum += 1
        return cls._lseqnum
    # end next_seqnum

    @classmethod
    def lseqnum(cls):
        if not hasattr(cls, '_lseqnum'):
            cls._lseqnum = 0
        return cls._lseqnum
    # end lseqnum

    def module(self):
        return self._module
    # end module

    def source_id(self):
        return self._source
    # end source_id

    def node_type(self):
        return self._node_type
    # end node_type

    def instance_id(self):
        return self._instance_id
    # end instance_id

    def host_ip(self):
        return self._host_ip
    # end host_ip

    def scope(self):
        return self._scope
    # end scope

    def context(self):
        return self._context
    # end context

    def seqnum(self):
        return self._seqnum
    # end seqnum

    def timestamp(self):
        return self._timestamp
    # end timestamp

    def versionsig(self):
        return self._versionsig
    # end versionsig

    def type(self):
        return self._type
    # end type

    def hints(self):
        return self._hints
    # end hints

    def client(self):
        return self._client
    # end client

    def level(self):
        return self._level
    # end level

    def category(self):
        return self._category
    # end category

    def validate(self):
        return
    # end validate

    def alarm_ack_callback(self):
        return self._alarm_ack_callback
    # end alarm_ack_callback

    def is_flow_logging_enabled(self):
        return self._sandesh_logger.is_flow_logging_enabled()
    # end is_flow_logging_enabled

    def is_trace_print_enabled(self):
        return self._sandesh_logger.is_trace_print_enabled()
    # end is_trace_print_enabled

    def is_local_logging_enabled(self):
        return self._sandesh_logger.is_local_logging_enabled()
    # end is_local_logging_enabled

    def logging_level(self):
        return self._sandesh_logger.logging_level()
    # end logging_level

    def logging_category(self):
        return self._sandesh_logger.logging_category()
    # end logging_category

    def is_syslog_logging_enabled(self):
        return self._sandesh_logger.is_syslog_logging_enabled()
    # end is_syslog_logging_enabled

    def logging_syslog_facility(self):
        return self._sandesh_logger.logging_syslog_facility()
    # end logging_syslog_facility

    def is_unit_test(self):
        return self._role == self.SandeshRole.INVALID
    # end is_unit_test

    def handle_test(self, sandesh_init):
        if sandesh_init.is_unit_test() or self._is_level_ut():
            if self._is_logging_allowed(sandesh_init):
                sandesh_init._logger.debug(self.log())
                return True
        return False

    def is_logging_allowed(self, sandesh_init):
        if self._type == SandeshType.FLOW:
            return sandesh_init.is_flow_logging_enabled()

        if not sandesh_init.is_local_logging_enabled():
            return False

        logging_level = sandesh_init.logging_level()
        level_allowed = logging_level >= self._level

        logging_category = sandesh_init.logging_category()
        if logging_category is None or len(logging_category) == 0:
            category_allowed = True
        else:
            category_allowed = logging_category == self._category

        return level_allowed and category_allowed
    # end is_logging_allowed

    def enqueue_sandesh_request(self, sandesh):
        self._rcv_queue.enqueue(sandesh)
    # end enqueue_sandesh_request

    def send_sandesh(self, tx_sandesh):
        if self._client:
            self._client.send_sandesh(tx_sandesh)
        else:
            if self._connect_to_collector:
                if self.is_logging_dropped_allowed(tx_sandesh):
                    self._logger.error('SANDESH: No Client: %s',
                                       tx_sandesh.log())
            else:
                self._logger.log(
                    sand_logger.SandeshLogger.get_py_logger_level(
                        tx_sandesh.level()), tx_sandesh.log())
    # end send_sandesh

    def send_generator_info(self):
        from gen_py.sandesh_uve.ttypes import SandeshClientInfo, \
            ModuleClientState, SandeshModuleClientTrace
        client_info = SandeshClientInfo()
        try:
            client_start_time = self._start_time
        except Exception:
            self._start_time = util.UTCTimestampUsec()
        finally:
            client_info.start_time = self._start_time
            client_info.pid = os.getpid()
            if self._http_server is not None:
                client_info.http_port = self._http_server.get_port()
            client_info.collector_name = self._client.connection().collector()
            client_info.status = self._client.connection().state()
            client_info.successful_connections = (
                self._client.connection().statemachine().connect_count())
            client_info.primary = self._client.connection().primary_collector()
            if client_info.primary is None:
                client_info.primary = ''
            client_info.secondary = (
                self._client.connection().secondary_collector())
            if client_info.secondary is None:
                client_info.secondary = ''
            module_state = ModuleClientState(name=self._source + ':' +
                                             self._node_type + ':' +
                                             self._module + ':' +
                                             self._instance_id,
                                             client_info=client_info)
            generator_info = SandeshModuleClientTrace(
                data=module_state, sandesh=self)
            generator_info.send(sandesh=self)
    # end send_generator_info

    def get_sandesh_request_object(self, request):
        try:
            req_module = self._sandesh_request_dict[request]
        except KeyError:
            self._logger.error('Invalid Sandesh Request "%s"' % (request))
            return None
        else:
            if req_module:
                try:
                    imp_module = importlib.import_module(req_module)
                except ImportError:
                    self._logger.error(
                        'Failed to import Module "%s"' % (req_module))
                else:
                    try:
                        sandesh_request = getattr(imp_module, request)()
                        return sandesh_request
                    except AttributeError:
                        self._logger.error(
                            'Failed to create Sandesh Request "%s"' %
                            (request))
                        return None
            else:
                self._logger.error(
                    'Sandesh Request "%s" not implemented' % (request))
                return None
    # end get_sandesh_request_object

    def trace_enable(self):
        self._trace.TraceOn()
    # end trace_enable

    def trace_disable(self):
        self._trace.TraceOff()
    # end trace_disable

    def is_trace_enabled(self):
        return self._trace.IsTraceOn()
    # end is_trace_enabled

    def trace_buffer_create(self, name, size, enable=True):
        self._trace.TraceBufAdd(name, size, enable)
    # end trace_buffer_create

    def trace_buffer_delete(self, name):
        self._trace.TraceBufDelete(name)
    # end trace_buffer_delete

    def trace_buffer_enable(self, name):
        self._trace.TraceBufOn(name)
    # end trace_buffer_enable

    def trace_buffer_disable(self, name):
        self._trace.TraceBufOff(name)
    # end trace_buffer_disable

    def is_trace_buffer_enabled(self, name):
        return self._trace.IsTraceBufOn(name)
    # end is_trace_buffer_enabled

    def trace_buffer_list_get(self):
        return self._trace.TraceBufListGet()
    # end trace_buffer_list_get

    def trace_buffer_size_get(self, name):
        return self._trace.TraceBufSizeGet(name)
    # end trace_buffer_size_get

    def trace_buffer_read(self, name, read_context, count, read_cb):
        self._trace.TraceRead(name, read_context, count, read_cb)
    # end trace_buffer_read

    def trace_buffer_read_done(self, name, context):
        self._trace.TraceReadDone(name, context)
    # end trace_buffer_read_done

    # API to send the trace buffer to the Collector.
    # If trace count is not specified/or zero, then the entire trace buffer
    # is sent to the Collector.
    # [Note] No duplicate trace message sent to the Collector. i.e., If there
    # is no trace message added between two consequent calls to this API, then
    # no trace message is sent to the Collector.
    def send_sandesh_trace_buffer(self, trace_buf, count=0):
        trace_req_runner = SandeshTraceRequestRunner(
            sandesh=self, request_buffer_name=trace_buf, request_context='',
            read_context='Collector', request_count=count)
        trace_req_runner.Run()
    # end send_sandesh_trace_buffer

    # Private functions

    def _is_level_ut(self):
        return (self._level >= SandeshLevel.UT_START and
                self._level <= SandeshLevel.UT_END)
    # end _is_level_ut

    def _create_task(self):
        return gevent.spawn(self._runner.run_for_ever)
    # end _create_task

    def _process_rx_sandesh(self, rx_sandesh):
        handle_request_fn = getattr(rx_sandesh, "handle_request", None)
        if callable(handle_request_fn):
            handle_request_fn(rx_sandesh)
        else:
            self._logger.error('Sandesh Request "%s" not implemented' %
                               (rx_sandesh.__class__.__name__))
    # end _process_rx_sandesh

    def _create_sandesh_request_and_uve_lists(self, package):
        try:
            imp_pkg = __import__(package)
        except ImportError:
            self._logger.error('Failed to import package "%s"' % (package))
        else:
            try:
                pkg_path = imp_pkg.__path__
            except AttributeError:
                self._logger.error(
                    'Failed to get package [%s] path' % (package))
                return
            for importer, mod, ispkg in (
                pkgutil.walk_packages(path=pkg_path,
                                      prefix=imp_pkg.__name__ + '.')):
                if not ispkg:
                    module = mod.rsplit('.', 1)[-1]
                    if 'ttypes' == module:
                        self._logger.debug(
                            'Add Sandesh requests in module "%s"' % (mod))
                        self._add_sandesh_request(mod)
                        self._logger.debug(
                            'Add Sandesh UVEs in module "%s"' % (mod))
                        self._add_sandesh_uve(mod)
                        self._logger.debug(
                            'Add Sandesh Alarms in module "%s"' % (mod))
                        self._add_sandesh_alarm(mod)
    # end _create_sandesh_request_and_uve_lists

    def _add_sandesh_request(self, mod):
        try:
            imp_module = importlib.import_module(mod)
        except ImportError:
            self._logger.error('Failed to import Module "%s"' % (mod))
        else:
            try:
                sandesh_req_list = getattr(imp_module, '_SANDESH_REQUEST_LIST')
            except AttributeError:
                self._logger.error(
                    '"%s" module does not have sandesh request list' % (mod))
            else:
                # Add sandesh requests to the dictionary.
                for req in sandesh_req_list:
                    self._sandesh_request_dict[req] = mod
    # end _add_sandesh_request

    def _get_sandesh_uve_list(self, imp_module):
        try:
            sandesh_uve_list = getattr(imp_module, '_SANDESH_UVE_LIST')
        except AttributeError:
            self._logger.error(
                '"%s" module does not have sandesh UVE list' %
                (imp_module.__name__))
            return None
        else:
            return sandesh_uve_list
    # end _get_sandesh_uve_list

    def _get_sandesh_uve_data_list(self, imp_module):
        try:
            sandesh_uve_data_list = getattr(imp_module,
                                            '_SANDESH_UVE_DATA_LIST')
        except AttributeError:
            self._logger.error(
                '"%s" module does not have sandesh UVE data list' %
                (imp_module.__name__))
            return None
        else:
            return sandesh_uve_data_list
    # end _get_sandesh_uve_data_list

    def _add_sandesh_uve(self, mod):
        try:
            imp_module = importlib.import_module(mod)
        except ImportError:
            self._logger.error('Failed to import Module "%s"' % (mod))
        else:
            sandesh_uve_list = self._get_sandesh_uve_list(imp_module)
            sandesh_uve_data_list = self._get_sandesh_uve_data_list(imp_module)
            if sandesh_uve_list is None or sandesh_uve_data_list is None:
                return
            if len(sandesh_uve_list) != len(sandesh_uve_data_list):
                self._logger.error(
                    '"%s" module sandesh UVE and UVE data list do not match'
                    % (mod))
                return
            sandesh_uve_info_list = zip(sandesh_uve_list,
                                        sandesh_uve_data_list)
            # Register sandesh UVEs
            for uve_type_name, uve_data_type_name in sandesh_uve_info_list:
                SandeshUVEPerTypeMap(self, SandeshType.UVE,
                                     uve_type_name, uve_data_type_name, mod)
    # end _add_sandesh_uve

    def _get_sandesh_alarm_list(self, imp_module):
        try:
            sandesh_alarm_list = getattr(imp_module, '_SANDESH_ALARM_LIST')
        except AttributeError:
            self._logger.error(
                '"%s" module does not have sandesh Alarm list' %
                (imp_module.__name__))
            return None
        else:
            return sandesh_alarm_list
    # end _get_sandesh_alarm_list

    def _get_sandesh_alarm_data_list(self, imp_module):
        try:
            sandesh_alarm_data_list = getattr(imp_module,
                                              '_SANDESH_ALARM_DATA_LIST')
        except AttributeError:
            self._logger.error(
                '"%s" module does not have sandesh Alarm data list' %
                (imp_module.__name__))
            return None
        else:
            return sandesh_alarm_data_list
    # end _get_sandesh_alarm_data_list

    def _add_sandesh_alarm(self, mod):
        try:
            imp_module = importlib.import_module(mod)
        except ImportError:
            self._logger.error('Failed to import Module "%s"' % (mod))
        else:
            sandesh_alarm_list = self._get_sandesh_alarm_list(imp_module)
            sandesh_alarm_data_list = self._get_sandesh_alarm_data_list(
                imp_module)
            if sandesh_alarm_list is None or sandesh_alarm_data_list is None:
                return
            if len(sandesh_alarm_list) != len(sandesh_alarm_data_list):
                self._logger.error(
                    '"%s" module sandesh Alarm and Alarm data list do not '
                    'match' % (mod))
                return
            sandesh_alarm_info_list = zip(sandesh_alarm_list,
                                          sandesh_alarm_data_list)
            # Register sandesh Alarms
            for (alarm_type_name, alarm_data_type_name) in (
                    sandesh_alarm_info_list):
                SandeshUVEPerTypeMap(self, SandeshType.ALARM, alarm_type_name,
                                     alarm_data_type_name, mod)
    # end _add_sandesh_alarm

    def _init_logger(self, module, logger_class=None,
                     logger_config_file=None):
        if not module:
            module = 'sandesh'

        if logger_class:
            self._sandesh_logger = (sand_logger.create_logger(
                module, logger_class,
                logger_config_file=logger_config_file))
        else:
            generator = '%s:%s:%s:%s' % (self._source, module, self._node_type,
                                         self._instance_id)
            self._sandesh_logger = sand_logger.SandeshLogger(
                generator, logger_config_file=logger_config_file)
        self._logger = self._sandesh_logger.logger()