Files
2019-05-21 12:35:33 -07:00

321 lines
16 KiB
Python
Executable File

# coding=utf-8
#
# Copyright © 2011-2015 Splunk, Inc.
#
# 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.
from __future__ import absolute_import, division, print_function, unicode_literals
from .decorators import ConfigurationSetting
from .search_command import SearchCommand
from itertools import imap, ifilter
# P1 [O] TODO: Discuss generates_timeorder in the class-level documentation for GeneratingCommand
class GeneratingCommand(SearchCommand):
""" Generates events based on command arguments.
Generating commands receive no input and must be the first command on a pipeline. There are three pipelines:
streams, events, and reports. The streams pipeline generates or processes time-ordered event records on an
indexer or search head.
Streaming commands filter, modify, or augment event records and can be applied to subsets of index data in a
parallel manner. An example of a streaming command from Splunk's built-in command set is rex_ which extracts and
adds fields to event records at search time. Records that pass through the streams pipeline move on to the events
pipeline.
The events pipeline generates or processes records on a search head. Eventing commands typically filter, group,
order, or augment event records. Examples of eventing commands from Splunk's built-in command set include sort_,
dedup_, and cluster_. Each execution of an eventing command should produce a set of event records that is
independently usable by downstream processors. Records that pass through the events pipeline move on to the reports
pipeline.
The reports pipeline also runs on a search head, but yields data structures for presentation, not event records.
Examples of streaming from Splunk's built-in command set include chart_, stats_, and contingency_.
GeneratingCommand configuration
===============================
Configure your generating command based on the pipeline that it targets. How you configure your command depends on
the Search Command Protocol (SCP) version.
+----------+-------------------------------------+--------------------------------------------+
| Pipeline | SCP 1 | SCP 2 |
+==========+=====================================+============================================+
| streams | streaming=True[,local=[True|False]] | type='streaming'[,distributed=[true|false] |
+----------+-------------------------------------+--------------------------------------------+
| events | retainsevents=True, streaming=False | type='eventing' |
+----------+-------------------------------------+--------------------------------------------+
| reports | streaming=False | type='reporting' |
+----------+-------------------------------------+--------------------------------------------+
Only streaming commands may be distributed to indexers. By default generating commands are configured to run
locally in the streams pipeline and will run under either SCP 1 or SCP 2.
.. code-block:: python
@Configuration()
class StreamingGeneratingCommand(GeneratingCommand)
...
How you configure your command to run on a different pipeline or in a distributed fashion depends on what SCP
protocol versions you wish to support. You must be sure to configure your command consistently for each protocol,
if you wish to support both protocol versions correctly.
.. _chart: http://docs.splunk.com/Documentation/Splunk/latest/SearchReference/Chart
.. _cluster: http://docs.splunk.com/Documentation/Splunk/latest/SearchReference/Cluster
.. _contingency: http://docs.splunk.com/Documentation/Splunk/latest/SearchReference/Contingency
.. _dedup: http://docs.splunk.com/Documentation/Splunk/latest/SearchReference/Dedup
.. _rex: http://docs.splunk.com/Documentation/Splunk/latest/SearchReference/Rex
.. _sort: http://docs.splunk.com/Documentation/Splunk/latest/SearchReference/Sort
.. _stats: http://docs.splunk.com/Documentation/Splunk/latest/SearchReference/Stats
Distributed Generating command
==============================
Commands configured like this will run as the first command on search heads and/or indexers on the streams pipeline.
+----------+---------------------------------------------------+---------------------------------------------------+
| Pipeline | SCP 1 | SCP 2 |
+==========+===================================================+===================================================+
| streams | 1. Add this line to your command's stanza in | 1. Add this configuration setting to your code: |
| | | |
| | default/commands.conf. | .. code-block:: python |
| | .. code-block:: python | @Configuration(distributed=True) |
| | local = false | class SomeCommand(GeneratingCommand) |
| | | ... |
| | 2. Restart splunk | |
| | | 2. You are good to go; no need to restart Splunk |
+----------+---------------------------------------------------+---------------------------------------------------+
Eventing Generating command
===========================
Generating commands configured like this will run as the first command on a search head on the events pipeline.
+----------+---------------------------------------------------+---------------------------------------------------+
| Pipeline | SCP 1 | SCP 2 |
+==========+===================================================+===================================================+
| events | You have a choice. Add these configuration | Add this configuration setting to your command |
| | settings to your command class: | setting to your command class: |
| | | |
| | .. code-block:: python | .. code-block:: python |
| | @Configuration( | @Configuration(type='eventing') |
| | retainsevents=True, streaming=False) | class SomeCommand(GeneratingCommand) |
| | class SomeCommand(GeneratingCommand) | ... |
| | ... | |
| | | |
| | Or add these lines to default/commands.conf: | |
| | | |
| | .. code-block:: | |
| | retains events = true | |
| | streaming = false | |
+----------+---------------------------------------------------+---------------------------------------------------+
Configure your command class like this, if you wish to support both protocols:
.. code-block:: python
@Configuration(type='eventing', retainsevents=True, streaming=False)
class SomeCommand(GeneratingCommand)
...
You might also consider adding these lines to commands.conf instead of adding them to your command class:
.. code-block:: python
retains events = false
streaming = false
Reporting Generating command
============================
Commands configured like this will run as the first command on a search head on the reports pipeline.
+----------+---------------------------------------------------+---------------------------------------------------+
| Pipeline | SCP 1 | SCP 2 |
+==========+===================================================+===================================================+
| events | You have a choice. Add these configuration | Add this configuration setting to your command |
| | settings to your command class: | setting to your command class: |
| | | |
| | .. code-block:: python | .. code-block:: python |
| | @Configuration(retainsevents=False) | @Configuration(type='reporting') |
| | class SomeCommand(GeneratingCommand) | class SomeCommand(GeneratingCommand) |
| | ... | ... |
| | | |
| | Or add this lines to default/commands.conf: | |
| | | |
| | .. code-block:: | |
| | retains events = false | |
| | streaming = false | |
+----------+---------------------------------------------------+---------------------------------------------------+
Configure your command class like this, if you wish to support both protocols:
.. code-block:: python
@Configuration(type='reporting', streaming=False)
class SomeCommand(GeneratingCommand)
...
You might also consider adding these lines to commands.conf instead of adding them to your command class:
.. code-block:: python
retains events = false
streaming = false
"""
# region Methods
def generate(self):
""" A generator that yields records to the Splunk processing pipeline
You must override this method.
"""
raise NotImplementedError('GeneratingCommand.generate(self)')
def _execute(self, ifile, process):
""" Execution loop
:param ifile: Input file object. Unused.
:type ifile: file
:return: `None`.
"""
self._record_writer.write_records(self.generate())
self.finish()
# endregion
# region Types
class ConfigurationSettings(SearchCommand.ConfigurationSettings):
""" Represents the configuration settings for a :code:`GeneratingCommand` class.
"""
# region SCP v1/v2 Properties
generating = ConfigurationSetting(readonly=True, value=True, doc='''
Tells Splunk that this command generates events, but does not process inputs.
Generating commands must appear at the front of the search pipeline identified by :meth:`type`.
Fixed: :const:`True`
Supported by: SCP 1, SCP 2
''')
# endregion
# region SCP v1 Properties
generates_timeorder = ConfigurationSetting(doc='''
:const:`True`, if the command generates new events.
Default: :const:`False`
Supported by: SCP 1
''')
local = ConfigurationSetting(doc='''
:const:`True`, if the command should run locally on the search head.
Default: :const:`False`
Supported by: SCP 1
''')
retainsevents = ConfigurationSetting(doc='''
:const:`True`, if the command retains events the way the sort, dedup, and cluster commands do, or whether it
transforms them the way the stats command does.
Default: :const:`False`
Supported by: SCP 1
''')
streaming = ConfigurationSetting(doc='''
:const:`True`, if the command is streamable.
Default: :const:`True`
Supported by: SCP 1
''')
# endregion
# region SCP v2 Properties
distributed = ConfigurationSetting(value=False, doc='''
True, if this command should be distributed to indexers.
This value is ignored unless :meth:`type` is equal to :const:`streaming`. It is only this command type that
may be distributed.
Default: :const:`False`
Supported by: SCP 2
''')
type = ConfigurationSetting(value='streaming', doc='''
A command type name.
==================== ======================================================================================
Value Description
-------------------- --------------------------------------------------------------------------------------
:const:`'eventing'` Runs as the first command in the Splunk events pipeline. Cannot be distributed.
:const:`'reporting'` Runs as the first command in the Splunk reports pipeline. Cannot be distributed.
:const:`'streaming'` Runs as the first command in the Splunk streams pipeline. May be distributed.
==================== ======================================================================================
Default: :const:`'streaming'`
Supported by: SCP 2
''')
# endregion
# region Methods
@classmethod
def fix_up(cls, command):
""" Verifies :code:`command` class structure.
"""
if command.generate == GeneratingCommand.generate:
raise AttributeError('No GeneratingCommand.generate override')
def iteritems(self):
iteritems = SearchCommand.ConfigurationSettings.iteritems(self)
version = self.command.protocol_version
if version == 2:
iteritems = ifilter(lambda (name, value): name != 'distributed', iteritems)
if self.distributed and self.type == 'streaming':
iteritems = imap(
lambda (name, value): (name, 'stateful') if name == 'type' else (name, value), iteritems)
return iteritems
pass
# endregion
pass
# endregion