Dashboards & Visualizations
Highlighted

Logging into Splunk SDK gives 404 error

Explorer

I'm trying the basic examples using the Javascript Splunk SDK using Node 0.8.0.

Trying to login to Splunk through the API gives me a 404 error.

My Javascript code -

username = "admin";
password = "changeme";
scheme   = "https";
host     = "localhost";
port     = "8089";
version  = "5.0";

Async = splunkjs.Async;
utils = splunkjs.Utils;

var tag = null;

done = callback = function() {
    $(tag).remove();
};

var http = new splunkjs.ProxyHttp("/proxy");
var service = new splunkjs.Service(http, {
    username: username,
    password: password,
    scheme: scheme,
    host: host,
    port: port,
    version: version
});

Async.chain([
        // First, we log in
        function(done) {
            service.login(done);
        },
        // Retrieve the apps
        function(success, done) {
            if (!success) {
                done("Error logging in");
            }

            service.apps().fetch(done);
        },
        // Print them out
        function(apps, done) {     
            var appsList = apps.list();       
            console.log("Applications:");
            for(var i = 0; i < appsList.length; i++) {
                var app = appsList[i];
                console.log("  App " + i + ": " + app.name);
            } 
            done();
        }
    ],
    function(err) {
        callback(err);        
    }
);

This is in my own code. The same script works when run from the SDK examples. What am I doing wrong?

EDIT - My backend is running in Node.JS so I'm confused as to whether I have to change some config files or not.

Highlighted

Re: Logging into Splunk SDK gives 404 error

Splunk Employee
Splunk Employee

There doesn't seem to be anything wrong with the code. I tried it (on apache) and it worked just fine.

Due to Same Origin Policy issues, you do need to set up a proxy for node to handle the requests to Splunk's REST APIs, i.e. on port 8089. For example, on apache, I have modified its httpd.conf file as follows:

SSLProxyEngine On
ProxyPass /proxy/ https://localhost:8089/

This works in the SDK examples for you because the examples are shipped with special handling for the "/proxy" requests.

0 Karma
Highlighted

Re: Logging into Splunk SDK gives 404 error

Explorer

I'm not using Apache though, I'm using Node.JS (along with Express) for my backend. (I just checked on my dev machine and I don't have Apache installed). Is there something I can do in Node/Express to do the same?

0 Karma
Highlighted

Re: Logging into Splunk SDK gives 404 error

Splunk Employee
Splunk Employee

If I understand your question correctly, it is because you need to add a /proxy
endpoint on your Express server. Let me try and explain first what we do in the
SDK examples, and then this should make a bit more sense.

In the SDK, when you run sdkdo examples or sdkdo runserver, it will start
up a small webserver. You can see the code for this server here:

https://github.com/splunk/splunk-sdk-javascript/blob/master/bin/cli.js#L137

As you can see, this server is super simple. It has two rules:

  1. If the URI starts with "/proxy", we will do some special handling, which
    you can see here:
    https://github.com/splunk/splunk-sdk-javascript/blob/master/bin/cli.js#L80

  2. If it is anything else, we assume we need to serve a static file from the
    filesystem.

The interesting case is (1), which you can see from the code. All it does is
look at the request that came in, and then "re-make" that request to the Splunk
server. This is because of the Single Origin Policy, since we can't talk
cross-domain.

For Express, you can do something very similar. You can use the app.all function,
something like this:

app.all('/proxy/*', function(req, res) {
    var error = {d: { __messages: [{ type: "ERROR", text: "Proxy Error", code: "PROXY"}] }};

    var writeError = function() {
        res.writeHead(500, {});
        res.write(JSON.stringify(error));
        res.end();
    };

    try {      
        var body = "";
        req.on('data', function(data) {
            body += data.toString("utf-8");
        });

        req.on('end', function() {
            var destination = req.headers["X-ProxyDestination".toLowerCase()];

            var options = {
                url: destination,
                method: req.method,
                headers: {
                    "Content-Length": req.headers["content-length"],
                    "Content-Type": req.headers["content-type"],
                    "Authorization": req.headers["authorization"]
                },
                followAllRedirects: true,
                body: body,
                jar: false
            };

            try {
                request(options, function(err, response, data) {
                    try {
                        var statusCode = (response ? response.statusCode : 500) || 500;
                        var headers = (response ? response.headers : {}) || {};

                        res.writeHead(statusCode, headers);
                        res.write(data || JSON.stringify(err));
                        res.end();
                    }
                    catch (ex) {
                        writeError();
                    }
                });
            }
            catch (ex) {
                writeError();
            }

        });
    }
    catch (ex) {
        writeError();
    }
});

I basically just copied the code from the example server. It probably needs a bit
of tweaking to confirm to the Express API, but should be pretty straightforward.

Hopefully this makes sense - let me know if I should clarify anything!

View solution in original post

0 Karma
Highlighted

Re: Logging into Splunk SDK gives 404 error

Path Finder

If this code is running from server-side, the HttpProxy is not required. you can use a pure splunkjs.Http object as the first parameter to Service creation.

Highlighted

Re: Logging into Splunk SDK gives 404 error

Splunk Employee
Splunk Employee

This is absolutely correct, I did not consider that they may want to just do a server-side connection 🙂

Also, if you just want a default server-side connection, you don't need to pass anything to Service, it will do the correct thing by default.

0 Karma