UNPKG

splunk-sdk

Version:

SDK for usage with the Splunk REST API

829 lines (758 loc) 37.8 kB
exports.setup = function (svc) { var assert = require('chai').assert; var path = require("path"); var splunkjs = require('../../index'); var tutils = require('../utils'); const { Logger } = require('../../lib/log'); var utils = splunkjs.Utils; var idCounter = 0; var getNextId = function () { return "id" + (idCounter++) + "_" + ((new Date()).valueOf()); }; return ( describe("Job tests", () => { beforeEach(function () { this.service = svc; }); // Disabling the test for now because the apps/appinstall endpoint have been deprecated from Splunk 8.2 // it("Callback#Create+abort job", function (done) { // var service = this.service; // Async.chain([ // function (done) { // var app_name = path.join(process.env.SPLUNK_HOME, ('/etc/apps/sdkappcollection/build/sleep_command.tar')); // // Fix path on Windows if $SPLUNK_HOME contains a space (ex: C:/Program%20Files/Splunk) // app_name = app_name.replace("%20", " "); // // var app_name = "sleep_command"; // service.post("apps/local", { update: 1, name: app_name, filename: true }, done); // }, // function (done) { // var sid = getNextId(); // var options = { id: sid }; // var jobs = service.jobs(); // var req = jobs.oneshotSearch('search index=_internal | head 1 | sleep 10', options, function (err, job) { // assert.ok(err); // assert.ok(!job); // assert.strictEqual(err.error, "abort"); // }); // Async.sleep(1000, function () { // req.abort(); // }); // } // ], // function (err) { // assert.ok(!err); // done(); // }); // done(); // }); it("Job Create Urls validation", function () { let testData = { "v1_1": { "qualifiedPath": "/servicesNS/admin/foo/search/jobs/id5_1649796951725", "relpath": "search/jobs/id5_1649796951725/events", "expected": "/servicesNS/admin/foo/search/jobs/id5_1649796951725/events" }, "v1_2": { "qualifiedPath": "/services/search/jobs/id5_1649796951725", "relpath": "search/jobs/id5_1649796951725/events", "expected": "/services/search/jobs/id5_1649796951725/events" }, "v2_1": { "qualifiedPath": "/servicesNS/admin/foo/search/v2/jobs/id5_1649796951725", "relpath": "search/v2/jobs/id5_1649796951725/events", "expected": "/servicesNS/admin/foo/search/v2/jobs/id5_1649796951725/events" }, "v2_2": { "qualifiedPath": "/services/search/v2/jobs/id5_1649796951725", "relpath": "search/v2/jobs/id5_1649796951725/events", "expected": "/services/search/v2/jobs/id5_1649796951725/events" } } for (const [key, value] of Object.entries(testData)) { createdUrl = this.service.jobs().createUrl(value.qualifiedPath, value.relpath); assert.strictEqual(value.expected, createdUrl); } }); it("Create and cancel job", async function () { let sid = getNextId(); let job = await this.service.jobs().search('search index=_internal | head 1', { id: sid }); assert.ok(job); assert.strictEqual(job.sid, sid); await job.cancel(); }); it("Create job error", async function () { let sid = getNextId(); try { let res = await this.service.jobs().search({ search: 'index=_internal | head 1', id: sid }); assert.ok(!res); } catch (error) { assert.ok(error); } }); it("List jobs", async function () { let jobs = await this.service.jobs().fetch(); assert.ok(jobs); let jobsList = jobs.list(); assert.ok(jobsList.length > 0); for (let i = 0; i < jobsList.length; i++) { assert.ok(jobsList[i]); }; }); it("Contains job", async function () { let sid = getNextId(); let jobs = this.service.jobs(); let job = await jobs.search('search index=_internal | head 1', { id: sid }); assert.ok(job); assert.strictEqual(job.sid, sid); jobs = await jobs.fetch(); job = jobs.item(sid); assert.ok(job); await job.cancel(); }); it("Job results", async function () { let sid = getNextId(); let that = this; let job = await that.service.jobs().search('search index=_internal | head 1 | stats count', { id: sid }); assert.strictEqual(job.sid, sid); await tutils.pollUntil( job, function (j) { return job.properties()["isDone"]; }, 10 ); [results, job] = await job.results({}); assert.strictEqual(results.rows.length, 1); assert.strictEqual(results.fields.length, 1); assert.strictEqual(results.fields[0], "count"); assert.strictEqual(results.rows[0][0], "1"); await job.cancel(); }); it("Job events", async function () { let sid = getNextId(); let that = this; let job = await that.service.jobs().search('search index=_internal | head 1', { id: sid }); assert.strictEqual(job.sid, sid); await tutils.pollUntil( job, function (j) { return job.properties()["isDone"]; }, 10 ); [results, job] = await job.events({}); assert.strictEqual(results.rows.length, 1); assert.strictEqual(results.fields.length, results.rows[0].length); await job.cancel(); }); it("Job events - post processing search params", async function () { let sid = getNextId(); let that = this; let job = await that.service.jobs().search('search index=_internal | head 2', { id: sid }); assert.strictEqual(job.sid, sid); await tutils.pollUntil( job, function (j) { return job.properties()["isDone"]; }, 10 ); [results, job] = await job.events({ search: "| head 1" }); assert.strictEqual(results.post_process_count, 1); assert.strictEqual(results.rows.length, 1); assert.strictEqual(results.fields.length, results.rows[0].length); await job.cancel(); }); it("Job results preview", async function () { let sid = getNextId(); let that = this; let job = await that.service.jobs().search('search index=_internal | head 1 | stats count', { id: sid }); assert.strictEqual(job.sid, sid); await tutils.pollUntil( job, function (j) { return job.properties()["isDone"]; }, 10 ); [results, job] = await job.preview({}); assert.strictEqual(results.rows.length, 1); assert.strictEqual(results.fields.length, 1); assert.strictEqual(results.fields[0], "count"); assert.strictEqual(results.rows[0][0], "1"); await job.cancel(); }); it("Job results iterator", async function () { let that = this; let job = await that.service.jobs().search('search index=_internal | head 10', {}); await tutils.pollUntil( job, function (j) { return job.properties()["isDone"]; }, 10 ); let iterator = job.iterator("results", { pagesize: 4 }); let hasMore = true; let pageSizes = []; await utils.whilst( function () { return hasMore; }, async function () { try { [results, _hasMore] = await iterator.next(); hasMore = _hasMore; if (hasMore) { pageSizes.push(results.rows.length); } } catch (error) { return error; } } ); assert.deepStrictEqual(pageSizes, [4, 4, 2]); }); // Disabling the test for now because the apps/appinstall endpoint have been deprecated from Splunk 8.2 // it("Callback#Enable + disable preview", function (done) { // var that = this; // var sid = getNextId(); // var service = this.service.specialize("nobody", "sdkappcollection"); // Async.chain([ // function (done) { // service.jobs().search('search index=_internal | head 1 | sleep 60', { id: sid }, done); // }, // function (job, done) { // job.enablePreview(done); // }, // function (job, done) { // job.disablePreview(done); // }, // function (job, done) { // job.cancel(done); // } // ], // function (err) { // assert.ok(!err); // done(); // } // ); // }); // Disabling the test for now because the apps/appinstall endpoint have been deprecated from Splunk 8.2 // it("Callback#Pause + unpause + finalize preview", function (done) { // var that = this; // var sid = getNextId(); // var service = this.service.specialize("nobody", "sdkappcollection"); // Async.chain([ // function (done) { // service.jobs().search('search index=_internal | head 1 | sleep 5', { id: sid }, done); // }, // function (job, done) { // job.pause(done); // }, // function (job, done) { // tutils.pollUntil( // job, // function (j) { // return j.properties()["isPaused"]; // }, // 10, // done // ); // }, // function (job, done) { // assert.ok(job.properties()["isPaused"]); // job.unpause(done); // }, // function (job, done) { // tutils.pollUntil( // job, // function (j) { // return !j.properties()["isPaused"]; // }, // 10, // done // ); // }, // function (job, done) { // assert.ok(!job.properties()["isPaused"]); // job.finalize(done); // }, // function (job, done) { // job.cancel(done); // } // ], // function (err) { // assert.ok(!err); // done(); // } // ); // }); it("Set TTL", async function () { let sid = getNextId(); let originalTTL = 0; var that = this; let job = await that.service.jobs().search('search index=_internal | head 1', { id: sid }); job = await job.fetch(); let ttl = job.properties()["ttl"]; originalTTL = ttl; let res = await job.setTTL(ttl * 2); job = await job.fetch(); ttl = job.properties()["ttl"]; assert.ok(ttl > originalTTL); assert.ok(ttl <= (originalTTL * 2)); await job.cancel(); }); // Disabling the test for now because the apps/appinstall endpoint have been deprecated from Splunk 8.2 // it("Callback#Set priority", function (done) { // var sid = getNextId(); // var originalPriority = 0; // var that = this; // var service = this.service.specialize("nobody", "sdkappcollection"); // Async.chain([ // function (done) { // service.jobs().search('search index=_internal | head 1 | sleep 5', { id: sid }, done); // }, // function (job, done) { // job.track({}, { // ready: function (job) { // done(null, job); // } // }); // }, // function (job, done) { // var priority = job.properties()["priority"]; // assert.ok(priority, 5); // job.setPriority(priority + 1, done); // }, // function (job, done) { // job.fetch(done); // }, // function (job, done) { // job.cancel(done); // } // ], // function (err) { // assert.ok(!err); // done(); // } // ); // }); it("Search log", async function () { let sid = getNextId(); var that = this; let job = await that.service.jobs().search('search index=_internal | head 1', { id: sid, exec_mode: "blocking" }); [log, job] = await job.searchlog(); assert.ok(job); assert.ok(log); assert.ok(log.length > 0); assert.ok(log.split("\r\n").length > 0); await job.cancel(); }); it("Search summary", async function () { let sid = getNextId(); var that = this; let job = await that.service.jobs().search( 'search index=_internal | head 1 | eval foo="bar" | fields foo', { id: sid, status_buckets: 300, rf: ["foo"] }); // Let's sleep for 2 second so // we let the server catch up await utils.sleep(2000); [summary, job] = await job.summary({}); assert.ok(job); assert.ok(summary); assert.strictEqual(summary.event_count, 1); assert.strictEqual(summary.fields.foo.count, 1); assert.strictEqual(summary.fields.foo.distinct_count, 1); assert.ok(summary.fields.foo.is_exact, 1); assert.strictEqual(summary.fields.foo.modes.length, 1); assert.strictEqual(summary.fields.foo.modes[0].count, 1); assert.strictEqual(summary.fields.foo.modes[0].value, "bar"); assert.ok(summary.fields.foo.modes[0].is_exact); await job.cancel(); }); it("Search timeline", async function () { let sid = getNextId(); var that = this; let job = await that.service.jobs().search( 'search index=_internal | head 1 | eval foo="bar" | fields foo', { id: sid, status_buckets: 300, rf: ["foo"], exec_mode: "blocking" }); [timeline, job] = await job.timeline({}); assert.ok(job); assert.ok(timeline); assert.strictEqual(timeline.buckets.length, 1); assert.strictEqual(timeline.event_count, 1); assert.strictEqual(timeline.buckets[0].available_count, 1); assert.strictEqual(timeline.buckets[0].duration, 0.001); assert.strictEqual(timeline.buckets[0].earliest_time_offset, timeline.buckets[0].latest_time_offset); assert.strictEqual(timeline.buckets[0].total_count, 1); assert.ok(timeline.buckets[0].is_finalized); await job.cancel(); }); it("Touch", async function () { let sid = getNextId(); var that = this; let originalTime = ""; let job = await that.service.jobs().search('search index=_internal | head 1', { id: sid }); job = await job.fetch(); assert.ok(job); originalTime = job.properties().updated; await utils.sleep(1200); await job.touch(); job = await job.fetch(); assert.ok(originalTime !== job.updated()); await job.cancel(); }); it("Create failure", async function () { let name = "jssdk_savedsearch_" + getNextId(); let originalSearch = "search index=_internal | head 1"; let jobs = this.service.jobs(); let res; try { res = await jobs.create({ search: originalSearch, name: name, exec_mode: "oneshot" }); } catch (error) { assert.ok(error); } assert.ok(!res); }); it("Create fails with no search string", async function () { let jobs = this.service.jobs(); let res; try { res = await jobs.create("", {}); } catch (error) { assert.ok(error); } assert.ok(!res); }); it("Oneshot search", async function () { let sid = getNextId(); var that = this; let results = await that.service.jobs().oneshotSearch('search index=_internal | head 1 | stats count', { id: sid }); assert.ok(results); assert.ok(results.fields); assert.strictEqual(results.fields.length, 1); assert.strictEqual(results.fields[0], "count"); assert.ok(results.rows); assert.strictEqual(results.rows.length, 1); assert.strictEqual(results.rows[0].length, 1); assert.strictEqual(results.rows[0][0], "1"); }); it("Oneshot search with json results", async function () { let sid = getNextId(); var that = this; let results = await that.service.jobs().oneshotSearch('search index=_internal | head 1 | stats count', { id: sid, output_mode: 'json' }); assert.ok(results); assert.ok(results.fields); assert.strictEqual(results.fields.length, 1); }); it("Oneshot search with xml results", async function () { let sid = getNextId(); var that = this; let results = await that.service.jobs().oneshotSearch('search index=_internal | head 2 | stats count', { id: sid, output_mode: 'xml' }); assert.ok(results); assert.ok(results.includes('<field>count</field>')); assert.ok(results.includes('<value><text>2</text></value>')); }); it("Oneshot search with csv results", async function () { let sid = getNextId(); var that = this; let results = await that.service.jobs().oneshotSearch('makeresults count=3 | streamstats count | eval foo="bar" | fields - _time', { id: sid, output_mode: 'csv' }); assert.ok(results); assert.ok(results.includes('count,foo')); assert.ok(results.includes('1,bar')); assert.ok(results.includes('2,bar')); assert.ok(results.includes('3,bar')); }); it("Oneshot search with no results", async function () { let sid = getNextId(); var that = this; let query = 'search index=history MUST_NOT_EXISTABCDEF'; let results = await that.service.jobs().oneshotSearch(query, { id: sid }); assert.ok(results); assert.strictEqual(results.fields.length, 0); assert.strictEqual(results.rows.length, 0); assert.ok(!results.preview); }); // it("Callback#Service oneshot search", function(done) { // var sid = getNextId(); // var that = this; // var namespace = {owner: "admin", app: "search"}; // var splunkVersion = 6.1; // Default to pre-6.2 version // var originalLoggerLevel = "DEBUG"; // Async.chain([ // function(done) { // // If running on Splunk 6.2+, first set the search logger level to DEBUG // Async.chain([ // function(done1) { // that.service.serverInfo(done1); // }, // function(info, done1) { // splunkVersion = parseFloat(info.properties().version); // if (splunkVersion < 6.2) { // done(); // Exit the inner Async.chain // } // else { // done1(); // } // }, // function(done1) { // that.service.configurations({owner: "admin", app: "search"}).fetch(done1); // }, // function(confs, done1) { // try { // confs.item("limits").fetch(done1); // } // catch(e) { // done1(e); // } // }, // function(conf, done1) { // var searchInfo = conf.item("search_info"); // // Save this so it can be restored later // originalLoggerLevel = searchInfo.properties()["infocsv_log_level"]; // searchInfo.update({"infocsv_log_level": "DEBUG"}, done1); // }, // function(conf, done1) { // assert.strictEqual("DEBUG", conf.properties()["infocsv_log_level"]); // done1(); // } // ], // function(err) { // assert.ok(!err); // done(); // } // ); // }, // function(done) { // that.service.oneshotSearch('search index=_internal | head 1 | stats count', {id: sid}, namespace, done); // }, // function(results, done) { // assert.ok(results); // assert.ok(results.fields); // assert.strictEqual(results.fields.length, 1); // assert.strictEqual(results.fields[0], "count"); // assert.ok(results.rows); // assert.strictEqual(results.rows.length, 1); // assert.strictEqual(results.rows[0].length, 1); // assert.strictEqual(results.rows[0][0], "1"); // assert.ok(results.messages[1].text.indexOf('owner="admin"')); // assert.ok(results.messages[1].text.indexOf('app="search"')); // done(); // }, // function(done) { // Async.chain([ // function(done1) { // if (splunkVersion < 6.2) { // done(); // Exit the inner Async.chain // } // else { // done1(); // } // }, // function(done1) { // that.service.configurations({owner: "admin", app: "search"}).fetch(done1); // }, // function(confs, done1) { // try { // confs.item("limits").fetch(done1); // } // catch(e) { // done1(e); // } // }, // function(conf, done1) { // var searchInfo = conf.item("search_info"); // // Restore the logger level from before // searchInfo.update({"infocsv_log_level": originalLoggerLevel}, done1); // }, // function(conf, done1) { // assert.strictEqual(originalLoggerLevel, conf.properties()["infocsv_log_level"]); // done1(); // } // ], // function(err) { // assert.ok(!err); // done(); // } // ); // } // ], // function(err) { // assert.ok(!err); // done(); // } // ); // }); it("Service search", async function () { let sid = getNextId(); let that = this; let namespace = { owner: "admin", app: "search" }; let job = await that.service.search('search index=_internal | head 1 | stats count', { id: sid }, namespace); assert.strictEqual(job.sid, sid); assert.strictEqual(job.namespace, namespace); await tutils.pollUntil( job, function (j) { return job.properties()["isDone"]; }, 10 ); [results, job] = await job.results({}); assert.strictEqual(results.rows.length, 1); assert.strictEqual(results.fields.length, 1); assert.strictEqual(results.fields[0], "count"); assert.strictEqual(results.rows[0][0], "1"); await job.cancel(); }); it("Wait until job done", async function () { let job = await this.service.search('search index=_internal | head 1000', {}); let numReadyEvents = 0; let numProgressEvents = 0; await job.track({ period: 200 }, { ready: function (job) { assert.ok(job); numReadyEvents++; }, progress: function (job) { assert.ok(job); numProgressEvents++; }, done: function (job) { assert.ok(job); assert.ok(numReadyEvents === 1); // all done jobs must have become ready assert.ok(numProgressEvents >= 1); // a job that becomes ready has progress }, failed: function (job) { assert.ok(job); assert.ok(false, "Job failed unexpectedly."); }, error: function (err) { assert.ok(err); assert.ok(false, "Error while tracking job."); } }); }); it("Wait until job failed", async function () { let job = await this.service.search('search index=_internal | head bogusarg', {}); let numReadyEvents = 0; let numProgressEvents = 0; await job.track({ period: 200 }, { ready: function (job) { assert.ok(job); numReadyEvents++; }, progress: function (job) { assert.ok(job); numProgressEvents++; }, done: function (job) { assert.ok(job); assert.ok(false, "Job became done unexpectedly."); }, failed: function (job) { assert.ok(job); assert.ok(numReadyEvents === 1); // even failed jobs become ready assert.ok(numProgressEvents >= 1); // a job that becomes ready has progress }, error: function (err) { assert.ok(err); assert.ok(false, "Error while tracking job."); } }); }); it("track() with default params and one function", async function () { let job = await this.service.search('search index=_internal | head 1', {}); await job.track({}, function (job) { assert.ok(job); }); }); it("track() should stop polling if only the ready callback is specified", async function () { let job = await this.service.search('search index=_internal | head 1', {}); await job.track({}, { ready: function (job) { assert.ok(job); }, _stoppedAfterReady: function (job) { assert.ok(job); } }); }); it("track() a job that is not immediately ready", async function () { /*jshint loopfunc:true */ let numJobs = 20; let numJobsLeft = numJobs; let gotJobNotImmediatelyReady = false; let taskList = [] let service = this.service; for (let i = 0; i < numJobs; i++) { taskList.push(async function(){ let job = await service.search('search index=_internal | head 10000', {}); await job.track({}, { _preready: function (job) { gotJobNotImmediatelyReady = true; }, ready: function (job) { numJobsLeft--; if (numJobsLeft === 0) { if (!gotJobNotImmediatelyReady) { splunkjs.Logger.error("", "WARNING: Couldn't test code path in track() where job wasn't ready immediately."); } assert.ok(true); } } }); }) } let [err, resp] = await utils.parallel(taskList); assert.ok(!err); }); it("Service.getJob() works", async function () { var that = this; let sidsMatch = false; let job = await this.service.search('search index=_internal | head 1', {}); let sid = job.sid; let innerJob = await that.service.getJob(sid); assert.strictEqual(sid, innerJob.sid); sidsMatch = sid === innerJob.sid; assert.ok(sidsMatch); }); }) ) }; if (module.id === __filename && module.parent.id.includes('mocha')) { var splunkjs = require('../../index'); var options = require('../cmdline'); let cmdline = options.create().parse(process.argv); // If there is no command line, we should return if (!cmdline) { throw new Error("Error in parsing command line parameters"); } if (!process.env.SPLUNK_HOME) { throw new Error("$PATH variable SPLUNK_HOME is not set. Please export SPLUNK_HOME to the splunk instance."); } let svc = new splunkjs.Service({ scheme: cmdline.opts.scheme, host: cmdline.opts.host, port: cmdline.opts.port, username: cmdline.opts.username, password: cmdline.opts.password, version: cmdline.opts.version }); // Exports tests on a successful login module.exports = new Promise(async (resolve, reject) => { try { await svc.login(); return resolve(exports.setup(svc)) } catch (error) { throw new Error("Login failed - not running tests", error || ""); } }); }