Example #1
0
    def parse_input(self, data):
        """Parse the lines of a livestatus request.

        This function looks for keywords in input lines and
        sets the attributes of the request object

        """
        for line in data.splitlines():
            line = line.strip()
            # Tools like NagVis send KEYWORK:option, and we prefer to have
            # a space following the:
            if ':' in line and not ' ' in line:
                line = line.replace(':', ': ')
            keyword = line.split(' ')[0].rstrip(':')
            if keyword == 'GET':  # Get the name of the base table
                _, self.table = self.split_command(line)
                if self.table not in table_class_map.keys():
                    raise LiveStatusQueryError(404, self.table)
            elif keyword == 'Columns':  # Get the names of the desired columns
                _, self.columns = self.split_option_with_columns(line)
                self.response.columnheaders = 'off'
            elif keyword == 'ResponseHeader':
                _, responseheader = self.split_option(line)
                self.response.responseheader = responseheader
            elif keyword == 'OutputFormat':
                _, outputformat = self.split_option(line)
                self.response.outputformat = outputformat
            elif keyword == 'KeepAlive':
                _, keepalive = self.split_option(line)
                self.response.keepalive = keepalive
            elif keyword == 'ColumnHeaders':
                _, columnheaders = self.split_option(line)
                self.response.columnheaders = columnheaders
            elif keyword == 'Limit':
                _, self.limit = self.split_option(line)
            elif keyword == 'AuthUser':
                if self.table in [
                        'hosts', 'hostgroups', 'services', 'servicegroups',
                        'hostsbygroup', 'servicesbygroup',
                        'servicesbyhostgroup'
                ]:
                    _, self.authuser = self.split_option(line)
                # else self.authuser stays None and will be ignored
            elif keyword == 'Filter':
                try:
                    _, attribute, operator, reference = self.split_option(
                        line, 3)
                except:
                    _, attribute, operator, reference = self.split_option(
                        line, 2) + ['']
                if operator in [
                        '=', '>', '>=', '<', '<=', '=~', '~', '~~', '!=', '!>',
                        '!>=', '!<', '!<='
                ]:
                    # Cut off the table name
                    attribute = self.strip_table_from_column(attribute)
                    # Some operators can simply be negated
                    if operator in ['!>', '!>=', '!<', '!<=']:
                        operator = {
                            '!>': '<=',
                            '!>=': '<',
                            '!<': '>=',
                            '!<=': '>'
                        }[operator]
                    # Put a function on top of the filter_stack which implements
                    # the desired operation
                    self.filtercolumns.append(attribute)
                    self.prefiltercolumns.append(attribute)
                    self.filter_stack.put_stack(
                        self.make_filter(operator, attribute, reference))
                    if self.table == 'log':
                        self.db.add_filter(operator, attribute, reference)
                else:
                    print "illegal operation", operator
                    pass  # illegal operation
            elif keyword == 'And':
                _, andnum = self.split_option(line)
                # Take the last andnum functions from the stack
                # Construct a new function which makes a logical and
                # Put the function back onto the stack
                self.filter_stack.and_elements(andnum)
                if self.table == 'log':
                    self.db.add_filter_and(andnum)
            elif keyword == 'Or':
                _, ornum = self.split_option(line)
                # Take the last ornum functions from the stack
                # Construct a new function which makes a logical or
                # Put the function back onto the stack
                self.filter_stack.or_elements(ornum)
                if self.table == 'log':
                    self.db.add_filter_or(ornum)
            elif keyword == 'Negate':
                self.filter_stack.not_elements()
                if self.table == 'log':
                    self.db.add_filter_not()
            elif keyword == 'StatsGroupBy':
                _, stats_group_by = self.split_option_with_columns(line)
                self.filtercolumns.extend(stats_group_by)
                self.stats_group_by.extend(stats_group_by)
                # Deprecated. If your query contains at least one Stats:-header
                # then Columns: has the meaning of the old StatsGroupBy: header
            elif keyword == 'Stats':
                self.stats_query = True
                try:
                    _, attribute, operator, reference = self.split_option(
                        line, 3)
                    if attribute in ['sum', 'min', 'max', 'avg', 'std'
                                     ] and reference.startswith('as '):
                        attribute, operator = operator, attribute
                        _, alias = reference.split(' ')
                        self.aliases.append(alias)
                    elif attribute in ['sum', 'min', 'max', 'avg', 'std'
                                       ] and reference == '=':
                        # Workaround for thruk-cmds like: Stats: sum latency =
                        attribute, operator = operator, attribute
                        reference = ''
                except:
                    _, attribute, operator = self.split_option(line, 3)
                    if attribute in ['sum', 'min', 'max', 'avg', 'std']:
                        attribute, operator = operator, attribute
                    reference = ''
                attribute = self.strip_table_from_column(attribute)
                if operator in [
                        '=', '>', '>=', '<', '<=', '=~', '~', '~~', '!=', '!>',
                        '!>=', '!<', '!<='
                ]:
                    if operator in ['!>', '!>=', '!<', '!<=']:
                        operator = {
                            '!>': '<=',
                            '!>=': '<',
                            '!<': '>=',
                            '!<=': '>'
                        }[operator]
                    self.filtercolumns.append(attribute)
                    self.stats_columns.append(attribute)
                    self.stats_filter_stack.put_stack(
                        self.make_filter(operator, attribute, reference))
                    self.stats_postprocess_stack.put_stack(
                        self.make_filter('count', attribute, None))
                elif operator in ['sum', 'min', 'max', 'avg', 'std']:
                    self.stats_columns.append(attribute)
                    self.stats_filter_stack.put_stack(
                        self.make_filter('dummy', attribute, None))
                    self.stats_postprocess_stack.put_stack(
                        self.make_filter(operator, attribute, None))
                else:
                    print "illegal operation", operator
                    pass  # illegal operation
            elif keyword == 'StatsAnd':
                _, andnum = self.split_option(line)
                self.stats_filter_stack.and_elements(andnum)
            elif keyword == 'StatsOr':
                _, ornum = self.split_option(line)
                self.stats_filter_stack.or_elements(ornum)
            elif keyword == 'Separators':
                _, sep1, sep2, sep3, sep4 = line.split(' ', 5)
                self.response.separators = map(lambda x: chr(int(x)),
                                               [sep1, sep2, sep3, sep4])
            elif keyword == 'Localtime':
                _, self.client_localtime = self.split_option(line)
            elif keyword == 'COMMAND':
                _, self.extcmd = line.split(' ', 1)
            else:
                # This line is not valid or not implemented
                print "Received a line of input which i can't handle: '%s'" % line
                pass
        self.metainfo = LiveStatusQueryMetainfo(data)
    def parse_input(self, data):
        """Parse the lines of a livestatus request.

        This function looks for keywords in input lines and
        sets the attributes of the request object.
        WaitCondition statements are written into the metafilter string as if they
        were ordinary Filter:-statements. (metafilter is then used for a MetaData object)

        """
        metafilter = ""
        for line in data.splitlines():
            line = line.strip()
            # Tools like NagVis send KEYWORK:option, and we prefer to have
            # a space following the:
            if ':' in line and not ' ' in line:
                line = line.replace(':', ': ')
            keyword = line.split(' ')[0].rstrip(':')
            if keyword == 'GET':  # Get the name of the base table
                _, self.table = self.split_command(line)
                metafilter += "GET %s\n" % self.table
            elif keyword == 'WaitObject':  # Pick a specific object by name
                _, item = self.split_option(line)
                # It's like Filter: name = %s
                # Only for services it's host<blank>servicedesc
                if self.table == 'services':
                    if ';' in item:
                        host_name, service_description = item.split(';', 1)
                    else:
                        host_name, service_description = item.split(' ', 1)
                    self.filtercolumns.append('host_name')
                    self.prefiltercolumns.append('host_name')
                    self.filter_stack.put(self.make_filter('=', 'host_name', host_name))
                    self.filtercolumns.append('description')
                    self.prefiltercolumns.append('description')
                    self.filter_stack.put(self.make_filter('=', 'description', service_description))
                    # A WaitQuery works like an ordinary Query. But if
                    # we already know which object we're watching for
                    # changes, instead of scanning the entire list and
                    # applying a Filter:, we simply reduce the list
                    # so it has just one element.
                    metafilter += "Filter: host_name = %s\n" % host_name
                    metafilter += "Filter: service_description = %s\n" % service_description
                elif self.table == 'hosts':
                    attribute = self.strip_table_from_column('name')
                    self.filtercolumns.append('name')
                    self.prefiltercolumns.append('name')
                    self.filter_stack.put(self.make_filter('=', 'name', item))
                    metafilter += "Filter: host_name = %s\n" % (item,)
                else:
                    attribute = self.strip_table_from_column('name')
                    self.filtercolumns.append('name')
                    self.prefiltercolumns.append('name')
                    self.filter_stack.put(self.make_filter('=', 'name', item))
                    # For the other tables this works like an ordinary query.
                    # In the future there might be more lookup-tables
            elif keyword == 'WaitTrigger':
                _, self.wait_trigger = self.split_option(line)
                if self.wait_trigger not in ['check', 'state', 'log', 'downtime', 'comment', 'command']:
                    self.wait_trigger = 'all'
            elif keyword == 'WaitCondition':
                try:
                    _, attribute, operator, reference = self.split_option(line, 3)
                except:
                    _, attribute, operator, reference = self.split_option(line, 2) + ['']
                if operator in ['=', '>', '>=', '<', '<=', '=~', '~', '~~', '!=', '!>', '!>=', '!<', '!<=']:
                    # We need to set columns, if not columnheaders will be set to "on"
                    self.columns.append(attribute)
                    # Cut off the table name
                    attribute = self.strip_table_from_column(attribute)
                    # Some operators can simply be negated
                    if operator in ['!>', '!>=', '!<', '!<=']:
                        operator = {'!>': '<=', '!>=': '<', '!<': '>=', '!<=': '>'}[operator]
                    # Put a function on top of the filter_stack which implements
                    # the desired operation
                    self.filtercolumns.append(attribute)
                    self.prefiltercolumns.append(attribute)
                    self.filter_stack.put(self.make_filter(operator, attribute, reference))
                    if self.table == 'log':
                        self.db.add_filter(operator, attribute, reference)
                else:
                    logger.warning("[Livestatus Wait Query] Illegal operation: %s" % str(operator))
                    pass  # illegal operation
            elif keyword == 'WaitConditionAnd':
                _, andnum = self.split_option(line)
                # Take the last andnum functions from the stack
                # Construct a new function which makes a logical and
                # Put the function back onto the stack
                self.filter_stack.and_elements(andnum)
                if self.table == 'log':
                    self.db.add_filter_and(andnum)
            elif keyword == 'WaitConditionOr':
                _, ornum = self.split_option(line)
                # Take the last ornum functions from the stack
                # Construct a new function which makes a logical or
                # Put the function back onto the stack
                self.filter_stack.or_elements(ornum)
                if self.table == 'log':
                    self.db.add_filter_or(ornum)
            elif keyword == 'WaitTimeout':
                _, self.wait_timeout = self.split_option(line)
                self.wait_timeout = int(self.wait_timeout) / 1000
            else:
                # This line is not valid or not implemented
                logger.warning("[Livestatus Wait Query] Received a line of input which i can't handle: '%s'" % line)
                pass
        # Make columns unique
        self.filtercolumns = list(set(self.filtercolumns))
        self.prefiltercolumns = list(set(self.prefiltercolumns))

        # Make one big filter where the single filters are anded
        self.filter_stack.and_elements(self.filter_stack.qsize())

        #if self.table == 'log':
        #    self.sql_filter_stack.and_elements(self.sql_filter_stack.qsize())

        self.metainfo = LiveStatusQueryMetainfo(metafilter)