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!

Introducing the 2024 SplunkTrust!

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

Introducing the 2024 Splunk MVPs!

We are excited to announce the 2024 cohort of the Splunk MVP program. Splunk MVPs are passionate members of ...

Splunk Custom Visualizations App End of Life

The Splunk Custom Visualizations apps End of Life for SimpleXML will reach end of support on Dec 21, 2024, ...