Splunk Dev

How To Run Python On App Install

David
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

David
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

David
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

Get Updates on the Splunk Community!

.conf24 | Registration Open!

Hello, hello! I come bearing good news: Registration for .conf24 is now open!   conf is Splunk’s rad annual ...

ICYMI - Check out the latest releases of Splunk Edge Processor

Splunk is pleased to announce the latest enhancements to Splunk Edge Processor.  HEC Receiver authorization ...

Introducing the 2024 SplunkTrust!

Hello, Splunk Community! We are beyond thrilled to announce our newest group of SplunkTrust members!  The ...