Note: The getting started example is the same example used for Cookbook Example4.
app.conf
default.xml
Example.xml
CustomResultsTable.conf
CustomResultsTable.js
CustomResultsTable.py
[ui] is_visible = true label = App Framework Tutorial [package] id = dev_tutorial [launcher] author = Splunk, Inc. description = App Framework Tutorial App version = 1.0
<nav>
<collection label="Examples">
<view name="Example" />
</collection>
</nav>
<view template="dashboard.html">
<label>Example: Using a Custom Module</label>
<module name="AccountBar" layoutPanel="appHeader"/>
<module name="AppBar" layoutPanel="navigationHeader"/>
<module name="Message" layoutPanel="messaging">
<param name="filter">*</param>
<param name="clearOnJobDispatch">False</param>
<param name="maxSize">1</param>
</module>
<module name="StaticContentSample" layoutPanel="panel_row1_col1">
<param name="text"><![CDATA[
<h1>Example: Using a Custom Module</h1>
<p>
This simple application searches the metrics log and lists the CPU utilization of each indexer stage, for the last seven days.
</p>
<p>
Search string: <tt>index=_internal source=*metrics.log group=pipeline | stats sum(cpu_seconds) as totalCPU by name</tt>
</p>
<p>
Results are displayed using a custom module, <tt>CustomResultsTable</tt>.
</p>
]]>
</param>
</module>
<module name="HiddenSearch" layoutPanel="panel_row2_col1" group="CPU Utilization" autoRun="True">
<param name="search">index=_internal source=*metrics.log group=pipeline | stats sum(cpu_seconds) as totalCPU by name</param>
<param name="earliest">-7d</param>
<module name="CustomResultsTable">
</module>
</module>
</view>
[module] className = Splunk.Module.CustomResultsTable superClass = Splunk.Module.DispatchingModule description = Custom module for App Framework example.
Splunk.Module.CustomResultsTable = $.klass(Splunk.Module.DispatchingModule, {
initialize: function($super, container) {
$super(container);
this.myParam = this.getParam("myParam");
this.resultsContainer = this.container;
},
onJobDone: function(event) {
this.getResults();
},
getResultParams: function($super) {
var params = $super();
var context = this.getContext();
var search = context.get("search");
var sid = search.job.getSearchId();
if (!sid) this.logger.error(this.moduleType, "Search ID is missing.");
params.sid = sid;
return params;
},
renderResults: function($super, htmlFragment) {
if (!htmlFragment) {
this.resultsContainer.html('No content available.');
return;
}
this.resultsContainer.html(htmlFragment);
}
})
import controllers.module as module
import splunk, splunk.search, splunk.util, splunk.entity
import lib.util as util
import lib.i18n as i18n
import logging
logger = logging.getLogger('splunk.module.CustomResultsTable')
import math
import cgi
MAX_MULTI_VALUE_COUNT = 50
class CustomResultsTable(module.ModuleHandler):
def generateResults(self, host_app, client_app, sid, count=1000,
offset=0, entity_name='results'):
count = max(int(count), 0)
offset = max(int(offset), 0)
if not sid:
raise Exception('CustomResultsTable.generateResults - sid not passed!')
try:
job = splunk.search.getJob(sid)
except splunk.ResourceNotFound, e:
logger.error('CustomResultsTable could not find the job %s. Exception: %s' % (sid, e))
return _('<p class="resultStatusMessage">The job appears to have expired or has been canceled.</p>')
output = []
output.append('<div class="CustomResultsTableWrapper">')
output.append('<table class="CustomResultsTable splTable">')
fieldNames = [x for x in getattr(job, entity_name).fieldOrder if (not x.startswith('_'))]
offset_start = offset
if offset < 0 and count < abs(offset):
offset_start = -count
dataset = getattr(job, entity_name)[offset_start: offset+count]
for i, result in enumerate(dataset):
output.append('<tr>')
for field in fieldNames:
output.append('<td')
fieldValues = result.get(field, None)
if fieldValues:
renderedValues = [cgi.escape(x.value) for x in fieldValues[:MAX_MULTI_VALUE_COUNT]]
output.append('>%s</td>' % "".join(renderedValues))
else:
output.append('></td>')
output.append('</tr>')
output.append('</table></div>')
if (entity_name == 'results' and job.resultCount == 0):
if job.isDone:
output = self.generateStatusMessage(entity_name, 'nodata', job.id)
else:
output = self.generateStatusMessage(entity_name, 'waiting', job.id)
else:
output = ''.join(output)
return output
Example5.xml
CustomJSONResults.conf
CustomJSONResults.js
CustomJSONResults.py
Example6.xml
TreeMap.conf
TreeMap.html
TreeMap.js
TreeMap.py
Example7.xml
ParameterizedTreeMap.conf
ParameterizedTreeMap.html
ParameterizedTreeMap.js
ParameterizedTreeMap.py
Example8.xml
web.conf
TutorialSetup.py
setup.html
success.html
failure.html
<view template="dashboard.html">
<label>Example 1: A Basic Application</label>
<module name="AccountBar" layoutPanel="appHeader"/>
<module name="AppBar" layoutPanel="navigationHeader"/>
<module name="Message" layoutPanel="messaging">
<param name="filter">*</param>
<param name="clearOnJobDispatch">False</param>
<param name="maxSize">1</param>
</module>
<module name="StaticContentSample" layoutPanel="panel_row1_col1">
<param name="text"><![CDATA[
<h1>Example 1: A Basic Application</h1>
<p>
This simple application searches the metrics log and lists the CPU utilization of each indexer stage, for the last seven days.
</p>
<p>
Search string: <tt>index=_internal source=*metrics.log group=pipeline | stats sum(cpu_seconds) as totalCPU by name</tt>
</p>
<p>
Results are displayed using the <tt>SimpleResultsTable</tt> module.
</p>
]]></param>
</module>
<module name="HiddenSearch" layoutPanel="panel_row2_col1" group="CPU Utilization" autoRun="True">
<param name="search">index=_internal source=*metrics.log group=pipeline | stats sum(cpu_seconds) as totalCPU by name</param>
<param name="earliest">-7d</param>
<module name="SimpleResultsTable"></module>
</module>
</view>
<nav>
<collection label="Examples">
<view name="Example1" />
<view name="Example2" />
<view name="Example3" />
<view name="Example4" />
<view name="Example5" />
<view name="Example6" />
<view name="Example7" />
<view name="Example8" />
</collection>
</nav>
<view template="dashboard.html" stylesheet="example2Styles.css">
<label>Example 2: Changing the Look of an Application</label>
<module name="AccountBar" layoutPanel="appHeader"/>
<module name="AppBar" layoutPanel="navigationHeader"/>
<module name="Message" layoutPanel="messaging">
<param name="filter">*</param>
<param name="clearOnJobDispatch">False</param>
<param name="maxSize">1</param>
</module>
<module name="StaticContentSample" layoutPanel="panel_row1_col1">
<param name="text"><![CDATA[
<h1>Example 2: Changing the Look of an Application</h1>
<p>
This example applies a custom CSS to the results table.
</p>
]]></param>
</module>
<module name="HiddenSearch" layoutPanel="panel_row2_col1" group="CPU Utilization, another view" autoRun="True">
<param name="search">index=_internal source=*metrics.log group=pipeline | stats sum(cpu_seconds) as totalCPU by name</param>
<param name="earliest">-7d</param>
<module name="SimpleResultsTable"></module>
</module>
</view>
table.simpleResultsTable tbody
{
background: #ebf2e6;
}
table.simpleResultsTable td
{
color: #669;
border-top: 1px dashed #fff;
}
table.simpleResultsTable tbody tr:hover td
{
color: #339;
background: #b3d09f;
}
<view template="dashboard.html" stylesheet="example2Styles.css">
<label>Example 3: Adding Dynamic Behavior to an Application</label>
<module name="AccountBar" layoutPanel="appHeader"/>
<module name="AppBar" layoutPanel="navigationHeader"/>
<module name="Message" layoutPanel="messaging">
<param name="filter">*</param>
<param name="clearOnJobDispatch">False</param>
<param name="maxSize">1</param>
</module>
<module name="StaticContentSample" layoutPanel="panel_row1_col1">
<param name="text"><![CDATA[
<h1>Example 3: Adding Dynamic Behavior to an Application</h1>
<p>
This builds on Example2 by using custom JavaScript to handle clicking on a table row. On click, the indexer stage name associated with the row is displayed.
</p>
]]></param>
</module>
<module name="HiddenSearch" layoutPanel="panel_row2_col1" group="CPU Utilization, other behavior" autoRun="True">
<param name="search">index=_internal source=*metrics.log group=pipeline | stats sum(cpu_seconds) as totalCPU by name</param>
<param name="earliest">-7d</param>
<module name="SimpleResultsTable">
<param name="drilldown">row</param>
<param name="displayMenu">true</param>
<module name="NullModule"></module>
</module>
</module>
</view>
switch (Splunk.util.getCurrentView()) {
case "Example3":
if (Splunk.Module.NullModule) {
Splunk.Module.NullModule = $.klass(Splunk.Module.NullModule, {
getModifiedContext: function() {
var context = this.getContext(),
click = context.getAll('click');
alert (click.value);
return context;
}
});
}
break;
}
<view template="dashboard.html">
<label>Example 5: Client-side Rendering, with JSON</label>
<module name="AccountBar" layoutPanel="appHeader"/>
<module name="AppBar" layoutPanel="navigationHeader"/>
<module name="Message" layoutPanel="messaging">
<param name="filter">*</param>
<param name="clearOnJobDispatch">False</param>
<param name="maxSize">1</param>
</module>
<module name="StaticContentSample" layoutPanel="panel_row1_col1">
<param name="text"><![CDATA[
<h1>Example 5: Formatting results on the client, with JSON</h1>
<p>
This simple application searches the metrics log and lists the CPU utilization of each indexer stage, for the last seven days.
</p>
<p>
Search string: <tt>index=_internal source=*metrics.log group=pipeline | stats sum(cpu_seconds) as totalCPU by name</tt>
</p>
<p>
JSON-formatted results are returned and displayed in tabular form using th custom <tt>CustomJSONResults</tt> module.
</p>
]]></param>
</module>
<module name="HiddenSearch" layoutPanel="panel_row2_col1" group="CPU Utilization" autoRun="True">
<param name="search">index=_internal source=*metrics.log group=pipeline | stats sum(cpu_seconds) as totalCPU by name</param>
<param name="earliest">-7d</param>
<module name="CustomJSONResults"></module>
</module>
</view>
[module] # The JavaScript name of the module className = Splunk.Module.CustomJSONResults # The module class to subclass from superClass = Splunk.Module.DispatchingModule description = this module waits for the search to complete, formats JSON data, and renders results in a tabular format. [param:myParam] required = False default = none label = This is an example parameter (not currently used).
Splunk.Module.CustomJSONResults = $.klass(Splunk.Module.DispatchingModule, {
initialize: function($super, container) {
$super(container);
this.myParam = this.getParam("myParam");
this.resultsContainer = this.container;
},
onJobDone: function(event) {
this.getResults();
},
getResultParams: function($super) {
var params = $super();
var context = this.getContext();
var search = context.get("search");
var sid = search.job.getSearchId();
if (!sid) this.logger.error(this.moduleType, "Assertion Failed.");
params.sid = sid;
return params;
},
renderResults: function($super, results) {
if(!results) {
this.resultsContainer.html('No content available.');
return;
}
for (var key in results) {
console.debug("key = %s, val = %s", key, results[key]);
}
htmlFragment = '<div class="CustomResultsTableWrapper">';
htmlFragment += '<table class="CustomResultsTable splTable">';
for (var key in results) {
htmlFragment += '<tr>';
htmlFragment += '<td>' + key + '</td><td>' + results[key] + '</td>';
htmlFragment += '</tr>';
}
htmlFragment += '</table></div>';
this.resultsContainer.html(htmlFragment);
}
})
import cherrypy
import controllers.module as module
import splunk, splunk.search, splunk.util, splunk.entity
import json
from splunk.appserver.mrsparkle.lib import jsonresponse
import lib.util as util
import lib.i18n as i18n
import logging
logger = logging.getLogger('splunk.module.CustomJSONResults')
import math
import cgi
class CustomJSONResults(module.ModuleHandler):
def generateResults(self, host_app, client_app, sid, count=1000,
offset=0, entity_name='results'):
count = max(int(count), 0)
offset = max(int(offset), 0)
if not sid:
raise Exception('CustomJSONResults.generateResults - sid not passed!')
try:
job = splunk.search.getJob(sid)
except splunk.ResourceNotFound, e:
logger.error('CustomJSONResults could not find the job %s. Exception: %s' % (sid, e))
return _('<p class="resultStatusMessage">Could not retrieve search data.</p>')
fieldNames = [x for x in getattr(job, entity_name).fieldOrder if (not x.startswith('_'))]
dataset = getattr(job, entity_name)[offset: offset+count]
outputJSON = {}
for i, result in enumerate(dataset):
outputJSON[str(result.get('name', None))] = str(result.get('totalCPU', None))
cherrypy.response.headers['Content-Type'] = 'text/json'
return json.dumps(outputJSON, sort_keys=True)
def render_json(self, response_data, set_mime='text/json'):
cherrypy.response.headers['Content-Type'] = set_mime
if isinstance(response_data, jsonresponse.JsonResponse):
response = response_data.toJson().replace("</", "<\\/")
else:
response = json.dumps(response_data).replace("</", "<\\/")
return ' ' * 256 + '\n' + response
<view template="dashboard.html">
<label>Example 6: Rendering a Treemap Visualization</label>
<module name="AccountBar" layoutPanel="appHeader"/>
<module name="AppBar" layoutPanel="navigationHeader"/>
<module name="Message" layoutPanel="messaging">
<param name="filter">*</param>
<param name="clearOnJobDispatch">False</param>
<param name="maxSize">1</param>
</module>
<module name="StaticContentSample" layoutPanel="panel_row1_col1">
<param name="text"><![CDATA[
<h1>Example 6: Rendering a Treemap Visualization</h1>
<p>
This simple application searches the metrics log and lists the CPU utilization of each processor of each indexer stage.
</p>
<p>
Search string: <tt>index=_internal source=*metrics.log group=pipeline | stats sum(cpu_seconds) as totalCPU by name, processor</tt>
</p>
<p>
JSON-formatted results are returned and rendered as a treemap using the custom <tt>TreeMap</tt> module. Treemap rectangles are sized by CPU utilization, with processors grouped by indexer type.
</p>
]]></param>
</module>
<module name="HiddenSearch" layoutPanel="panel_row2_col1" group="CPU utilization thresholds" autoRun="True">
<param name="search">index=_internal source=*metrics.log group=pipeline | stats sum(cpu_seconds) as totalCPU by name, processor</param>
<param name="earliest">-7d</param>
<module name="TreeMap"></module>
</module>
</view>
[module] # The JavaScript name of the module className = Splunk.Module.TreeMap # The module class to subclass from superClass = Splunk.Module.DispatchingModule description = this module waits for the search to complete, formats JSON data, and renders results in a tabular format. [param:myParam] required = False default = none label = This is an example parameter (not currently used).
<%page args="module" expression_filter="h"/>
<%namespace name="lib" file="//lib.html" import="*"/>
<%lib:script_tags files="${['/static/app/%s/protovis.js' % APP['id']]}" />
<div id="TreeMapID" class="TreeMapResults"></div>
// A treemap renderer
Splunk.Module.TreeMap = $.klass(Splunk.Module.DispatchingModule, {
initialize: function($super, container) {
$super(container);
this.myParam = this.getParam("myParam");
this.resultsContainer = this.container;
},
onJobDone: function(event) {
this.getResults();
},
getResultParams: function($super) {
var params = $super();
var context = this.getContext();
var search = context.get("search");
var sid = search.job.getSearchId();
if (!sid) this.logger.error(this.moduleType, "Assertion Failed.");
params.sid = sid;
return params;
},
renderResults: function($super, results) {
if(!results) {
this.resultsContainer.html('No content available.');
return;
}
var re = "";
var color = pv.Colors.category19().by(function(d){return d.parentNode.nodeName});
var nodes = pv.dom(results).root("flare").nodes();
var vis = new pv.Panel().width(920).height(420).canvas(document.getElementById('TreeMapID'));
var treemap = vis.add(pv.Layout.Treemap).nodes(nodes).round(true);
treemap.leaf.add(pv.Panel).fillStyle(function(d){return color(d).alpha(1)}).strokeStyle("#fff").lineWidth(1).antialias(false);
treemap.label.add(pv.Label).textStyle(function(d){return pv.rgb(0, 0, 0, 1)});
vis.render();
}
})
import cherrypy
import controllers.module as module
import splunk, splunk.search, splunk.util, splunk.entity
import json
from splunk.appserver.mrsparkle.lib import jsonresponse
import lib.util as util
import lib.i18n as i18n
import logging
logger = logging.getLogger('splunk.module.TreeMap')
import math
import cgi
class TreeMap(module.ModuleHandler):
def generateResults(self, host_app, client_app, sid, count=1000,
offset=0, entity_name='results'):
count = max(int(count), 0)
offset = max(int(offset), 0)
if not sid:
raise Exception('TreeMap.generateResults - sid not passed!')
try:
job = splunk.search.getJob(sid)
except splunk.ResourceNotFound, e:
logger.error('TreeMap could not find job %s. Exception: %s' % (sid, e))
return _('<p class="resultStatusMessage">Could not get search data.</p>')
dataset = getattr(job, entity_name)[offset: offset+count]
outputJSON = {}
for i, result in enumerate(dataset):
tdict = {}
tdict[str(result.get('processor', None))] = str(result.get('totalCPU', None))
name = str(result.get('name', None))
if name not in outputJSON:
outputJSON[name] = dict()
outputJSON[name].update(tdict)
cherrypy.response.headers['Content-Type'] = 'text/json'
return json.dumps(outputJSON, sort_keys=True)
def render_json(self, response_data, set_mime='text/json'):
cherrypy.response.headers['Content-Type'] = set_mime
if isinstance(response_data, jsonresponse.JsonResponse):
response = response_data.toJson().replace("</", "<\\/")
else:
response = json.dumps(response_data).replace("</", "<\\/")
return ' ' * 256 + '\n' + response
<view template="dashboard.html">
<label>Example 7: Parameterizing a Module</label>
<module name="AccountBar" layoutPanel="appHeader"/>
<module name="AppBar" layoutPanel="navigationHeader"/>
<module name="Message" layoutPanel="messaging">
<param name="filter">*</param>
<param name="clearOnJobDispatch">False</param>
<param name="maxSize">1</param>
</module>
<module name="StaticContentSample" layoutPanel="panel_row1_col1">
<param name="text"><![CDATA[
<h1>Example 7: Parameterizing a Module</h1>
<p>
This example shows you how to statically parameterize your module when the app starts by specifying properties in the module configuration file.
</p>
<p>
Search string: <tt>index=_internal source=*metrics.log group=pipeline | stats sum(cpu_seconds) as totalCPU by name, processor</tt>
</p>
<p>
Example6 used hardcoded values for the treemap height and width. This example lets you specify those values in the <tt>ParameterizedTreeMap.conf</tt> configuration file.
</p>
]]></param>
</module>
<module name="HiddenSearch" layoutPanel="panel_row2_col1" group="Threshold events" autoRun="True">
<param name="search">index=_internal source=*metrics.log group=pipeline | stats sum(cpu_seconds) as totalCPU by name, processor</param>
<param name="earliest">-7d</param>
<module name="ParameterizedTreeMap"></module>
</module>
</view>
[module] # The JavaScript name of the module className = Splunk.Module.ParameterizedTreeMap # The module class to subclass from superClass = Splunk.Module.DispatchingModule [param:tmapWidth] required = False default = 640 label = This parameter defines the treemap width. description = this module waits for the search to complete, formats JSON data, and renders a treemap. [param:tmapHeight] required = False default = 320 label = This parameter defines the treemap height.
<%page args="module" expression_filter="h"/>
<%namespace name="lib" file="//lib.html" import="*"/>
<%lib:script_tags files="${['/static/app/%s/protovis.js' % APP['id']]}" />
<div id="ParameterizedTreeMapID" class="ParameterizedTreeMapResults"></div>
// A treemap renderer
Splunk.Module.ParameterizedTreeMap = $.klass(Splunk.Module.DispatchingModule, {
initialize: function($super, container) {
$super(container);
this.resultsContainer = this.container;
this.tmapHeight = this.getParam('tmapHeight', 920);
this.tmapWidth = this.getParam('tmapWidth', 420);
},
onJobDone: function(event) {
this.getResults();
},
getResultParams: function($super) {
var params = $super();
var context = this.getContext();
var search = context.get("search");
var sid = search.job.getSearchId();
if (!sid) this.logger.error(this.moduleType, "Assertion Failed.");
params.sid = sid;
return params;
},
renderResults: function($super, results) {
if(!results) {
this.resultsContainer.html('No content available.');
return;
}
var re = "";
var color = pv.Colors.category19().by(function(d){return d.parentNode.nodeName});
var nodes = pv.dom(results).root("flare").nodes();
var vis = new pv.Panel().width(this.tmapWidth).height(this.tmapHeight).canvas(document.getElementById('ParameterizedTreeMapID'));
var treemap = vis.add(pv.Layout.Treemap).nodes(nodes).round(true);
treemap.leaf.add(pv.Panel).fillStyle(function(d){return color(d).alpha(1)}).strokeStyle("#fff").lineWidth(1).antialias(false);
treemap.label.add(pv.Label).textStyle(function(d){return pv.rgb(0, 0, 0, 1)});
vis.render();
}
})
#
# Splunk UI module python renderer
# This module is imported by the module loader (lib.module.ModuleMapper) into
# the splunk.appserver.mrsparkle.controllers.module.* namespace.
#
import cherrypy
import controllers.module as module
import splunk, splunk.search, splunk.util, splunk.entity
import json
from splunk.appserver.mrsparkle.lib import jsonresponse
import lib.util as util
import lib.i18n as i18n
import logging
logger = logging.getLogger('splunk.module.ParameterizedTreeMap')
import math
import cgi
class ParameterizedTreeMap(module.ModuleHandler):
def generateResults(self, host_app, client_app, sid, count=1000,
offset=0, entity_name='results'):
count = max(int(count), 0)
offset = max(int(offset), 0)
if not sid:
raise Exception('ParameterizedTreeMap.generateResults - sid not passed!')
try:
job = splunk.search.getJob(sid)
except splunk.ResourceNotFound, e:
logger.error('ParameterizedTreeMap could not find job %s. Exception: %s' % (sid, e))
return _('Could not get search data.
')
dataset = getattr(job, entity_name)[offset: offset+count]
outputJSON = {}
for i, result in enumerate(dataset):
tdict = {}
tdict[str(result.get('processor', None))] = str(result.get('totalCPU', None))
name = str(result.get('name', None))
if name not in outputJSON:
outputJSON[name] = dict()
outputJSON[name].update(tdict)
cherrypy.response.headers['Content-Type'] = 'text/json'
return json.dumps(outputJSON, sort_keys=True)
# return self.render_json(outputJSON)
def render_json(self, response_data, set_mime='text/json'):
cherrypy.response.headers['Content-Type'] = set_mime
if isinstance(response_data, jsonresponse.JsonResponse):
response = response_data.toJson().replace("</", "<\\/")
else:
response = json.dumps(response_data).replace("</", "<\\/")
# Pad with 256 bytes of whitespace for IE security issue. See SPL-34355
return ' ' * 256 + '\n' + response
<view template="dashboard.html">
<label>Example 8: Setting up an App (MVC)</label>
<module name="AccountBar" layoutPanel="appHeader"/>
<module name="AppBar" layoutPanel="navigationHeader"/>
<module name="Message" layoutPanel="messaging">
<param name="filter">*</param>
<param name="clearOnJobDispatch">False</param>
<param name="maxSize">1</param>
</module>
<module name="StaticContentSample" layoutPanel="panel_row1_col1">
<param name="text"><![CDATA[
<h1>Example 8: Setting up an App (MVC)</h1>
<p>
App setup involves configuring configuration objects using HTML forms. This differs from Module Controllers, which facilitate asynchronous context, search, and job processing. (Setup demonstrates how to use the MVC architectural pattern implemented by the App Framework.)
</p>
]]></param>
</module>
<module name="IFrameInclude" layoutPanel="panel_row2_col1">
<param name="src">/custom/dev_tutorial/TutorialSetup/show</param>
</module>
</view>
[endpoint:TutorialSetup]
import logging
import os
import sys
import cherrypy
import splunk
import splunk.bundle as bundle
import splunk.appserver.mrsparkle.controllers as controllers
import splunk.appserver.mrsparkle.lib.util as util
from splunk.appserver.mrsparkle.lib.decorators import expose_page
from splunk.models.event_type import EventType
logger = logging.getLogger('splunk.appserver.mrsparkle.controllers.TutorialSetup')
class TutorialSetup(controllers.BaseController):
'''App Framework Tutorial Setup Controller'''
@expose_page(must_login=True, methods=['GET'])
def show(self, **kwargs):
return self.render_template('/dev_tutorial:/templates/setup.html')
@expose_page(must_login=True, trim_spaces=True, methods=['POST'])
def save(self, **params):
form_content = {}
user = cherrypy.session['user']['name']
for key, val in params.iteritems():
try:
if (key != 'splunk_form_key'):
form_content[key] = EventType.get(EventType.build_id(key, 'dev_tutorial', user))
form_content[key].search = val
except Exception, ex:
form_content[key] = EventType('dev_tutorial', user, key)
for key in form_content.keys():
try:
form_content[key].passive_save()
except splunk.AuthorizationFailed:
logger.info('User %s is unauthorized to perform setup on %s' % (user, 'dev_tutorial'))
except Exception, ex:
logger.info(ex)
logger.info('Failed to save eventtype %s' % key)
return self.render_template('/dev_tutorial:/templates/success.html')
<%page expression_filter="h"/>
<%inherit file="//layout/base.html" />
<%namespace name="lib" file="//lib.html" import="*"/>
<%namespace name="helpers" file="//view/_helpers.html" import="*"/>
<%!
import logging
logger = logging.getLogger('splunk.module.setup')
%>
<%def name="gen_form(method='POST', action=None)">
<form method="${method}" action="${action if action else ''}">
</%def>
<div id="setup">
<p class="pageDesc">Select the indexer stages you want to display:</p>
${gen_form(method="POST", action=make_url(['custom', 'dev_tutorial', 'TutorialSetup', 'save']))}
${csrf_hidden_input()}
<input type="checkbox" name="dev-null" value="Yes" /> dev-null<br />
<input type="checkbox" name="archivepipe" value="Yes" /> archivepipe<br />
<input type="checkbox" name="fschangemanager" value="Yes" /> fschangemanager<br />
<input type="checkbox" name="indexerpipe" value="Yes" checked/> indexerpipe<br />
<input type="checkbox" name="merging" value="Yes" checked/> merging<br />
<input type="checkbox" name="parsing" value="Yes" checked/> parsing<br />
<input type="checkbox" name="scheduler" value="Yes" /> scheduler<br />
<input type="checkbox" name="typing" value="Yes" checked/> typing<br />
<input type="checkbox" name="tcp" value="Yes" /> tcp<br />
<input type="checkbox" name="udp" value="Yes" /> udp<br />
<p>Click the button to save your configuration:</p>
<input class="splButton-primary" type="submit" value="Save"></input>
</form>
</div>
<%inherit file="//layout/base.html" />
<%namespace name="lib" file="//lib.html" import="*"/>
<div id="success">
<h2>Great Success!</h2>
<p>Your App Framework tutorial settings have been saved.</p>
<p>Click "OK" to go to the App Framework Tutorial home page.</p>
<a target="_parent" href="${make_url('/app/dev_tutorial')}" class="splButton-primary"><span class="cancel">OK</span></a>
</div>
<%inherit file="//layout/base.html" />
<%namespace name="lib" file="//lib.html" import="*"/>
<div id="failure">
<h2>Failure</h2>
<p>App Framework Tutorial settings could not be loaded successfully. Click "OK" to return to setup.</p>
<a target="_parent" href="${make_url('/app/dev_tutorial/Example8')}"><span class="splButton-primary cancel">OK</span></a>
</div>