Splunk Custom Endpoints Part 3: POSTing the Data

In Part 3 of this series we are going to finish setting up our POSTing of data to our custom endpoint.



In Parts 1 and 2 we covered setting up our Python file to handle a POST request with hard-coded data. We also covered setting up our restmap.conf and web.conf files. We then set up our dashboard with a form that will POST to our custom endpoint. Finally, we added some JavaScript to handle the POSTing to our custom endpoint.

As our custom_endpoint.py stands right now it is simply using the hardcoded data in the file and using that to POST to our custom endpoint. Now we want to modify our custom_endpoint.py file to take the data we POST to it and return it so we can see the format the data is sent to our custom endpoint.

Feel free to follow along with the blog post and/or the screencast links that are included below and throughout the post.

Cleaning Our POST Data

You can view the related screencast here.

Part of the request that comes into Splunk when POSTing data to it is the payload. This is the data that we will be sending from our form. We can access this through our handle_POST method’s request like so:

payload = self.request['payload']

Go ahead and open up the custom_endpoint.py script inside of your app’s bin folder. Modify your handle_POST method so it looks like this:

class Send(splunk.rest.BaseRestHandler):

def handle_POST(self):
	sessionKey = self.sessionKey

	try:
		payload = self.request['payload']
		self.response.write(str(payload))

	except Exception, e:
		logger.exception(e)
		self.response.write(e)
	
handle_GET = handle_POST

Here is what we are doing:

  1. Right now all we are interested in seeing that the script can handle the request and then provide a response by simply returning the data we send it.
  2. First define the payload.
  3. Then, write out the payload in a string format back to the browser. We will wait for this response on our dashboard.
  4. Once you make the changes save the file.

Test POSTing

Go back to the dashboard, fill out the form and then click the Submit button. I entered ‘batman’ for my user and ‘admin’ for my role. In the console the response should look something like this:

What are we looking at?

The data is the payload that we are writing out in our Python script. Currently the format is:

0=Username&0=batman&1=Roles&1=admin

I would rather it be in the format of:

Username=batman&Roles=admin

We can do this with a little massaging of our data in our Javascript file.

Modifying the payload data format

In custom_endpoint.js we will add the following inside of our on-click event:

var data_obj = {};
 
//lets massage the data
_.each(data, function(field) {
    var key = field['name'];
    var value = field['value'];

    if(key == 'Roles') {
        data_obj[key] = value.split(',');
    } else {
        data_obj[key] = value;
    }

});

Here is what we are doing:

  1. Above we are pulling out the name of the form field field[‘name’] and the value of the form field field[‘value’].
  2. We then check to see which field we are pulling the data from: Roles or Username
  3. If Roles, we need to split the value apart if multiple roles have been provided e.g. user,admin
  4. If it's not Roles, then it can only be the Username field and we simply assign the Username key to the value.

Next, instead of passing data into our service request, we will pass data_obj:

service.post('/services/send', data_obj, function(err, response) {

Now if you try and submit the form you should get back something like:

Handling POST Data In Python

The next thing we want to do is loop through the payload data, pull out what we need, and pass it to the pre-existing endpoint of /services/admin/users/<user>. Here's the Handling POST Data In Python screencast for you as well. Inside of the custom_endpoint.py file make the following modifications inside the handle_POST method:

def handle_POST(self):
	sessionKey = self.sessionKey
	username = ''
	roles = []

	try:
		payload = self.request['payload']

		for el in payload.split('&'):
			key, value = el.split('=')
			if 'Username' in key:
				username = value
			if 'Roles' in key:
				roles.append(value)
			if username is '':
				self.response.setStatus(400)
				self.response.write('A username must be provided.')
			else:
				post_path = '/services/admin/users/' + username
				new_roles = { "roles" : roles }
				serverContent = splunk.rest.simpleRequest(post_path, 
				sessionKey=sessionKey,postargs=new_roles,method='POST',raiseAllErrors=True)

	except Exception, e:
		self.response.write(e)

handle_GET = handle_POST

Here is what we are doing:

  1. Above we’ve added a variable for a username and roles.
  2. Then inside of the try statement we define our payload, which is passed form on our CRUD dashboard.
  3. We then loop through the payload data first splitting on & and then = characters to pull our our data and assign both the username and roles values.
  4. We also check to see if the username is blank and if it is we throw back a 400 error saying that a username must be provided.
  5. If everything is good, we post to the /services/admin/users/<user> endpoint and pass it our data using the simpleRequest method.
  6. Finally, if an error occurs an exception will be thrown and returned back to us.

At this point if you go back to your dashboard and try to POST, you should receive back User roles updated successfully! If you remember, that "Success!" message comes from our JavaScript file. You can confirm it worked by going to: https://<hostname>:<splunkd_port>/services/admin/users/<user_name>

Now that we have POSTing working, we can move on to going through setting up our GET request. We will do that in the final part of this series.




Close off Canvas Menu