mirror of
https://github.com/splunk/security_content
synced 2026-06-08 17:32:49 +00:00
321 lines
16 KiB
Python
Executable File
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
|