Skip to content

.conf CRUD functionality added #141

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jan 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,32 @@ Save the file as **.splunkrc** in the current user's home directory.

Click **Yes**, then continue creating the file.

### Create/Update a .conf file
```javascript

Async.chain([
function (done) {
// Fetch configurations
var configs = svc.configurations(namespace);
configs.fetch(done);
},
async function (configs, done) {
// Create a key-value map to store under a stanza
const filename = "app.conf";
const stanzaName = "install";
var keyValueMap = {}
keyValueMap["state"] = "enabled";
keyValueMap["python.version"] = "python3";

// If file/stanza doesn't exist, it will be created
// else it will be updated.
configs.createAsync(filename, stanzaName, keyValueMap, done);
}
],
function (err) {
done();
});
```

### Client-side examples

Expand Down
25 changes: 19 additions & 6 deletions lib/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -356,19 +356,32 @@
*
* @method splunkjs.Context
*/
get: function(path, params, callback) {
get: function(path, params, callback, isAsync) {
var that = this;
var request = function(callback) {

if(isAsync) {
return that.http.get(
that.urlify(path),
that._headers(),
params,
that.timeout,
callback
null,
true
);
};

return this._requestWrapper(request, callback);
}
else {
var request = function(callback) {
return that.http.get(
that.urlify(path),
that._headers(),
params,
that.timeout,
callback
);
};

return this._requestWrapper(request, callback);
}
},

/**
Expand Down
59 changes: 32 additions & 27 deletions lib/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,15 +133,15 @@
*
* @method splunkjs.Http
*/
get: function(url, headers, params, timeout, callback) {
get: function(url, headers, params, timeout, callback, isAsync) {
var message = {
method: "GET",
headers: headers,
timeout: timeout,
query: params
};

return this.request(url, message, callback);
return this.request(url, message, callback, isAsync);
},

/**
Expand Down Expand Up @@ -202,31 +202,8 @@
* @method splunkjs.Http
* @see makeRequest
*/
request: function(url, message, callback) {
request: function(url, message, callback, isAsync) {
var that = this;
var wrappedCallback = function(response) {
callback = callback || function() {};

// Handle cookies if 'set-cookie' header is in the response

var cookieHeaders = response.response.headers['set-cookie'];
if (cookieHeaders) {
utils.forEach(cookieHeaders, function (cookieHeader) {
var cookie = that._parseCookieHeader(cookieHeader);
that._cookieStore[cookie.key] = cookie.value;
});
}

// Handle callback

if (response.status < 400 && response.status !== "abort") {
callback(null, response);
}
else {
callback(response);
}
};

var query = utils.getWithVersion(this.version, queryBuilderMap)(message);
var post = message.post || {};

Expand All @@ -253,7 +230,35 @@

// Now we can invoke the user-provided HTTP class,
// passing in our "wrapped" callback
return this.makeRequest(encodedUrl, options, wrappedCallback);
if(isAsync) {
return this.makeRequestAsync(encodedUrl, options);
}
else {
var wrappedCallback = function(response) {
callback = callback || function() {};

// Handle cookies if 'set-cookie' header is in the response

var cookieHeaders = response.response.headers['set-cookie'];
if (cookieHeaders) {
utils.forEach(cookieHeaders, function (cookieHeader) {
var cookie = that._parseCookieHeader(cookieHeader);
that._cookieStore[cookie.key] = cookie.value;
});
}

// Handle callback

if (response.status < 400 && response.status !== "abort") {
callback(null, response);
}
else {
callback(response);
}
};

return this.makeRequest(encodedUrl, options, wrappedCallback);
}
},

/**
Expand Down
22 changes: 22 additions & 0 deletions lib/platform/node/node_http.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,28 @@
return req;
},

makeRequestAsync: async function(url, message) {
var request_options = {
url: url,
method: message.method,
headers: message.headers || {},
body: message.body || "",
timeout: message.timeout || 0,
jar: false,
followAllRedirects: true,
strictSSL: false,
rejectUnauthorized : false,
};

// Get the byte-length of the content, which adjusts for multi-byte characters
request_options.headers["Content-Length"] = Buffer.byteLength(request_options.body, "utf8");

var that = this;
var response = needle(request_options.method, request_options.url, request_options.body, request_options);

return response;
},

parseJson: function(json) {
return JSON.parse(json);
}
Expand Down
139 changes: 136 additions & 3 deletions lib/service.js
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@
*
* @method splunkjs.Service.Endpoint
*/
get: function(relpath, params, callback) {
get: function(relpath, params, callback, isAsync) {
var url = this.qualifiedPath;

// If we have a relative path, we will append it with a preceding
Expand All @@ -729,7 +729,8 @@
return this.service.get(
url,
params,
callback
callback,
isAsync
);
},

Expand Down Expand Up @@ -1261,6 +1262,7 @@
this._load = utils.bind(this, this._load);
this.fetch = utils.bind(this, this.fetch);
this.create = utils.bind(this, this.create);
this.createAsync = utils.bind(this, this.createAsync);
this.list = utils.bind(this, this.list);
this.item = utils.bind(this, this.item);
this.instantiateEntity = utils.bind(this, this.instantiateEntity);
Expand Down Expand Up @@ -1394,6 +1396,34 @@

return req;
},

/**
* It's an asynchronous version of fetch(options, callback) function.
*
* Refreshes the resource by fetching the object from the server and
* loading it.
*
* @param {Object} options A dictionary of collection filtering and pagination options:
* - `count` (_integer_): The maximum number of items to return.
* - `offset` (_integer_): The offset of the first item to return.
* - `search` (_string_): The search query to filter responses.
* - `sort_dir` (_string_): The direction to sort returned items: “asc” or “desc”.
* - `sort_key` (_string_): The field to use for sorting (optional).
* - `sort_mode` (_string_): The collating sequence for sorting returned items: “auto”, “alpha”, “alpha_case”, or “num”.
*
* @method splunkjs.Service.Collection
*/
fetchAsync: async function(options) {
options = options || {};
if (!options.count) {
options.count = 0;
}

var that = this;
var response = await that.get("", options, null, true);
that._load(response.body);
return that;
},

/**
* Returns a specific entity from the collection.
Expand Down Expand Up @@ -3091,7 +3121,110 @@
});

return req;
}
},

/**
* Fetch a configuration file.
*
* @param {String} file A name for configuration file.
* @return file, if exists or null
*
* @endpoint properties
* @method splunkjs.Service.Configurations
*/
getConfFile: async function(filename) {
var that = this;

// 1. Fetch files list
var response = await this.get("", {__conf: filename}, null, true);

// 2. Filter the files
var files = response
&& response.body
&& response.body.entry
&& response.body.entry.filter(f => f.name === filename);

// 3. Check if the file exists
if(files && files.length == 0) {
return null;
}

// 4. Create a local instance
var configurationFile = new root.ConfigurationFile(that.service, filename);

// 5. Load the file content
var fetchedFile = await configurationFile.fetchAsync();

return fetchedFile;
},

/**
* Fetch a configuration stanza.
*
* @param {String} file A configuration file.
* @param {String} stanza A configuration stanza.
* @return stanza, if exists or null
*
* @endpoint properties
* @method splunkjs.Service.Configurations
*/
getStanza: async function(file, stanza) {
// 1. check if the stanza exists
var fetchedStanza = file.item(stanza);

if(fetchedStanza == undefined) {
return null;
}
else {
return fetchedStanza;
}
},

/**
* Creates/Updates a configuration file and stanza.
*
* @param {String} filename A name for this configuration file to be created/updated.
* @param {String} stanzaName A name for the stanza to be created/updated.
* @param {String} keyValueMap A key-value map of properties to be put under the stanza.
* @param {Function} callback A function to call with the new configuration file.
*
* @endpoint properties
* @method splunkjs.Service.Configurations
*/
createAsync: async function (filename, stanzaName, keyValueMap, callback) {
callback = callback || function() {};
var that = this;

// 1. Check if the file exists
var configFile = await this.getConfFile(filename);

// 2. If the file doesn't exist, create a new file
if(configFile == undefined) {

that.create( { __conf: filename });

configFile = new root.ConfigurationFile( that.service, filename );
configFile = await configFile.fetchAsync();
}

// 3. Check if the stanza exists
var configStanza = await this.getStanza(configFile, stanzaName);

// 4. If the stanza doesn't exist, create a new stanza with given keyValueMap
if(configStanza == undefined) {

configFile.create(stanzaName, keyValueMap, function (err, newStanza) {
callback();
});
}

// 5. If the stanza exists, update it with the keyValueMap
else {
configStanza.update(keyValueMap, (err, updatedStanza) => {
callback();
});
}
},
});

/**
Expand Down
Loading