Dashboards & Visualizations

Logging into Splunk SDK gives 404 error

narabhut
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.

1 Solution

ineeman
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

yitzarad
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.

ineeman
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

ineeman
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!

0 Karma

Neeraj_Luthra
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

narabhut
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
Get Updates on the Splunk Community!

Cloud Platform & Enterprise: Classic Dashboard Export Feature Deprecation

As of Splunk Cloud Platform 9.3.2408 and Splunk Enterprise 9.4, classic dashboard export features are now ...

Explore the Latest Educational Offerings from Splunk (November Releases)

At Splunk Education, we are committed to providing a robust learning experience for all users, regardless of ...

New This Month in Splunk Observability Cloud - Metrics Usage Analytics, Enhanced K8s ...

The latest enhancements across the Splunk Observability portfolio deliver greater flexibility, better data and ...