Developing for Splunk Enterprise

How To Run Python On App Install

Splunk Employee
Splunk Employee

I want to run some authenticated Python code when an app installs, to kick off an action.

What's the best way to do that?

Labels (1)
0 Karma
1 Solution

Splunk Employee
Splunk Employee

There are generally two ways of doing this: with a scripted input that runs on Splunk start (will also run on app install) and with triggers.

Scripted inputs are covered elsewhere, but functionally it's an inputs.conf stanza that has an interval set to -1 (run once on Splunk start / app install).

Triggers are defined in app.conf and are less well documented.
Docs: https://docs.splunk.com/Documentation/Splunk/latest/Admin/appconf#.5Btriggers.5D

In order to trigger a custom rest endpoint, you need to define a conf file that matches the configuration.

Here is a working example, tested on Splunk 7.2 (so before Python3 changes -- script might / will likely fail when Splunk switches to python3):

In app.conf:

[triggers]
reload.ssenav = http_get /SSEResetLocalNav

ssenav.conf:

[general]

In web.conf:

[expose:SSEResetLocalNav]
methods = GET
pattern = SSEResetLocalNav

In restmap.conf:

[script:SSEResetLocalNAV]
match                 = /SSEResetLocalNav
script                = resetLocalNAV.py
scripttype            = persist
handler               = resetLocalNAV.ResetLocalNav
requireAuthentication = true
output_modes          = json
passPayload           = true
passHttpHeaders       = true
passHttpCookies       = true

resetLocalNAV.py (this script will overwrite a local default.xml navigation with the default default.xml):

from __future__ import absolute_import

import os
import sys
import time
import csv

import splunk.rest as rest
from splunk.appserver.mrsparkle.lib.util import make_splunkhome_path

if sys.platform == "win32":
    import msvcrt
    # Binary mode is required for persistent mode on Windows.
    msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
    msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
    msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)

from splunk.persistconn.application import PersistentServerConnectionApplication

class ResetLocalNav(PersistentServerConnectionApplication):
    def __init__(self, command_line, command_arg):
        PersistentServerConnectionApplication.__init__(self)

    def handle(self, in_string):
        default_nav = ""
        f = open("/tmp/dvtest.log", "wb")
        from time import gmtime, strftime
        f.write("STARTING - " + strftime("%Y-%m-%d %H:%M:%S", gmtime()) + "\n")
        try: 
            input = json.loads(in_string)
            sessionKey = input['session']['authtoken']
        except Exception as e:
            f.write("Error Early")
            return {'payload': {"status": "error early", "message": str(e)},  
                    'status': 200          # HTTP status code
            }

        try:
            localfilepath = make_splunkhome_path(['etc', 'apps', 'Splunk_Security_Essentials', 'local', 'data', 'ui', 'nav', 'default.xml'])
            if not os.path.exists(localfilepath):
                f.write("No Update Needed\n")
                return {'payload': {"status": "no update needed"},  
                        'status': 200          # HTTP status code
                }
        except Exception as e:
            f.write("Error 1 - " + str(e) + "\n")
            return {'payload': {"status": "error", "message": str(e)},  
                    'status': 200          # HTTP status code
            }

        try:
            filepath = make_splunkhome_path(['etc', 'apps', 'Splunk_Security_Essentials', 'default', 'data', 'ui', 'nav', 'default.xml'])
            with open(filepath, 'rU') as fh:
                default_nav = fh.read()
            url = "/servicesNS/nobody/Splunk_Security_Essentials/data/ui/nav/default"
            postargs = {
                "eai:data": default_nav
            }

            rest.simpleRequest(url, postargs=postargs, sessionKey=sessionKey, raiseAllErrors=True)
            f.write("Update Successful\n")
            return {'payload': {"status": "update successful", "more": default_nav},  
                    'status': 200          # HTTP status code
            }
        except Exception as e:
            f.write("error 2 - " + str(e) + "\n")
            return {'payload': {"status": "error", "message": str(e)},  
                    'status': 200          # HTTP status code
            }

The above was courtesy of @sideview

Below courtesy of @hazekamp :
You can also ship a default.meta entry

[ssenav]

If you don't want to ship a dummy conf

View solution in original post

Splunk Employee
Splunk Employee

There are generally two ways of doing this: with a scripted input that runs on Splunk start (will also run on app install) and with triggers.

Scripted inputs are covered elsewhere, but functionally it's an inputs.conf stanza that has an interval set to -1 (run once on Splunk start / app install).

Triggers are defined in app.conf and are less well documented.
Docs: https://docs.splunk.com/Documentation/Splunk/latest/Admin/appconf#.5Btriggers.5D

In order to trigger a custom rest endpoint, you need to define a conf file that matches the configuration.

Here is a working example, tested on Splunk 7.2 (so before Python3 changes -- script might / will likely fail when Splunk switches to python3):

In app.conf:

[triggers]
reload.ssenav = http_get /SSEResetLocalNav

ssenav.conf:

[general]

In web.conf:

[expose:SSEResetLocalNav]
methods = GET
pattern = SSEResetLocalNav

In restmap.conf:

[script:SSEResetLocalNAV]
match                 = /SSEResetLocalNav
script                = resetLocalNAV.py
scripttype            = persist
handler               = resetLocalNAV.ResetLocalNav
requireAuthentication = true
output_modes          = json
passPayload           = true
passHttpHeaders       = true
passHttpCookies       = true

resetLocalNAV.py (this script will overwrite a local default.xml navigation with the default default.xml):

from __future__ import absolute_import

import os
import sys
import time
import csv

import splunk.rest as rest
from splunk.appserver.mrsparkle.lib.util import make_splunkhome_path

if sys.platform == "win32":
    import msvcrt
    # Binary mode is required for persistent mode on Windows.
    msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
    msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
    msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)

from splunk.persistconn.application import PersistentServerConnectionApplication

class ResetLocalNav(PersistentServerConnectionApplication):
    def __init__(self, command_line, command_arg):
        PersistentServerConnectionApplication.__init__(self)

    def handle(self, in_string):
        default_nav = ""
        f = open("/tmp/dvtest.log", "wb")
        from time import gmtime, strftime
        f.write("STARTING - " + strftime("%Y-%m-%d %H:%M:%S", gmtime()) + "\n")
        try: 
            input = json.loads(in_string)
            sessionKey = input['session']['authtoken']
        except Exception as e:
            f.write("Error Early")
            return {'payload': {"status": "error early", "message": str(e)},  
                    'status': 200          # HTTP status code
            }

        try:
            localfilepath = make_splunkhome_path(['etc', 'apps', 'Splunk_Security_Essentials', 'local', 'data', 'ui', 'nav', 'default.xml'])
            if not os.path.exists(localfilepath):
                f.write("No Update Needed\n")
                return {'payload': {"status": "no update needed"},  
                        'status': 200          # HTTP status code
                }
        except Exception as e:
            f.write("Error 1 - " + str(e) + "\n")
            return {'payload': {"status": "error", "message": str(e)},  
                    'status': 200          # HTTP status code
            }

        try:
            filepath = make_splunkhome_path(['etc', 'apps', 'Splunk_Security_Essentials', 'default', 'data', 'ui', 'nav', 'default.xml'])
            with open(filepath, 'rU') as fh:
                default_nav = fh.read()
            url = "/servicesNS/nobody/Splunk_Security_Essentials/data/ui/nav/default"
            postargs = {
                "eai:data": default_nav
            }

            rest.simpleRequest(url, postargs=postargs, sessionKey=sessionKey, raiseAllErrors=True)
            f.write("Update Successful\n")
            return {'payload': {"status": "update successful", "more": default_nav},  
                    'status': 200          # HTTP status code
            }
        except Exception as e:
            f.write("error 2 - " + str(e) + "\n")
            return {'payload': {"status": "error", "message": str(e)},  
                    'status': 200          # HTTP status code
            }

The above was courtesy of @sideview

Below courtesy of @hazekamp :
You can also ship a default.meta entry

[ssenav]

If you don't want to ship a dummy conf

View solution in original post

Don’t Miss Global Splunk
User Groups Week!

Free LIVE events worldwide 2/8-2/12
Connect, learn, and collect rad prizes
and swag!