Skip to content

Commit 5014298

Browse files
Merge pull request #141 from splunk/DVPL-7124
.conf CRUD functionality added
2 parents f6647ad + 381f8aa commit 5014298

File tree

6 files changed

+289
-36
lines changed

6 files changed

+289
-36
lines changed

README.md

+26
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,32 @@ Save the file as **.splunkrc** in the current user's home directory.
219219

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

222+
### Create/Update a .conf file
223+
```javascript
224+
225+
Async.chain([
226+
function (done) {
227+
// Fetch configurations
228+
var configs = svc.configurations(namespace);
229+
configs.fetch(done);
230+
},
231+
async function (configs, done) {
232+
// Create a key-value map to store under a stanza
233+
const filename = "app.conf";
234+
const stanzaName = "install";
235+
var keyValueMap = {}
236+
keyValueMap["state"] = "enabled";
237+
keyValueMap["python.version"] = "python3";
238+
239+
// If file/stanza doesn't exist, it will be created
240+
// else it will be updated.
241+
configs.createAsync(filename, stanzaName, keyValueMap, done);
242+
}
243+
],
244+
function (err) {
245+
done();
246+
});
247+
```
222248

223249
### Client-side examples
224250

lib/context.js

+19-6
Original file line numberDiff line numberDiff line change
@@ -356,19 +356,32 @@
356356
*
357357
* @method splunkjs.Context
358358
*/
359-
get: function(path, params, callback) {
359+
get: function(path, params, callback, isAsync) {
360360
var that = this;
361-
var request = function(callback) {
361+
362+
if(isAsync) {
362363
return that.http.get(
363364
that.urlify(path),
364365
that._headers(),
365366
params,
366367
that.timeout,
367-
callback
368+
null,
369+
true
368370
);
369-
};
370-
371-
return this._requestWrapper(request, callback);
371+
}
372+
else {
373+
var request = function(callback) {
374+
return that.http.get(
375+
that.urlify(path),
376+
that._headers(),
377+
params,
378+
that.timeout,
379+
callback
380+
);
381+
};
382+
383+
return this._requestWrapper(request, callback);
384+
}
372385
},
373386

374387
/**

lib/http.js

+32-27
Original file line numberDiff line numberDiff line change
@@ -133,15 +133,15 @@
133133
*
134134
* @method splunkjs.Http
135135
*/
136-
get: function(url, headers, params, timeout, callback) {
136+
get: function(url, headers, params, timeout, callback, isAsync) {
137137
var message = {
138138
method: "GET",
139139
headers: headers,
140140
timeout: timeout,
141141
query: params
142142
};
143143

144-
return this.request(url, message, callback);
144+
return this.request(url, message, callback, isAsync);
145145
},
146146

147147
/**
@@ -202,31 +202,8 @@
202202
* @method splunkjs.Http
203203
* @see makeRequest
204204
*/
205-
request: function(url, message, callback) {
205+
request: function(url, message, callback, isAsync) {
206206
var that = this;
207-
var wrappedCallback = function(response) {
208-
callback = callback || function() {};
209-
210-
// Handle cookies if 'set-cookie' header is in the response
211-
212-
var cookieHeaders = response.response.headers['set-cookie'];
213-
if (cookieHeaders) {
214-
utils.forEach(cookieHeaders, function (cookieHeader) {
215-
var cookie = that._parseCookieHeader(cookieHeader);
216-
that._cookieStore[cookie.key] = cookie.value;
217-
});
218-
}
219-
220-
// Handle callback
221-
222-
if (response.status < 400 && response.status !== "abort") {
223-
callback(null, response);
224-
}
225-
else {
226-
callback(response);
227-
}
228-
};
229-
230207
var query = utils.getWithVersion(this.version, queryBuilderMap)(message);
231208
var post = message.post || {};
232209

@@ -253,7 +230,35 @@
253230

254231
// Now we can invoke the user-provided HTTP class,
255232
// passing in our "wrapped" callback
256-
return this.makeRequest(encodedUrl, options, wrappedCallback);
233+
if(isAsync) {
234+
return this.makeRequestAsync(encodedUrl, options);
235+
}
236+
else {
237+
var wrappedCallback = function(response) {
238+
callback = callback || function() {};
239+
240+
// Handle cookies if 'set-cookie' header is in the response
241+
242+
var cookieHeaders = response.response.headers['set-cookie'];
243+
if (cookieHeaders) {
244+
utils.forEach(cookieHeaders, function (cookieHeader) {
245+
var cookie = that._parseCookieHeader(cookieHeader);
246+
that._cookieStore[cookie.key] = cookie.value;
247+
});
248+
}
249+
250+
// Handle callback
251+
252+
if (response.status < 400 && response.status !== "abort") {
253+
callback(null, response);
254+
}
255+
else {
256+
callback(response);
257+
}
258+
};
259+
260+
return this.makeRequest(encodedUrl, options, wrappedCallback);
261+
}
257262
},
258263

259264
/**

lib/platform/node/node_http.js

+22
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,28 @@
8585
return req;
8686
},
8787

88+
makeRequestAsync: async function(url, message) {
89+
var request_options = {
90+
url: url,
91+
method: message.method,
92+
headers: message.headers || {},
93+
body: message.body || "",
94+
timeout: message.timeout || 0,
95+
jar: false,
96+
followAllRedirects: true,
97+
strictSSL: false,
98+
rejectUnauthorized : false,
99+
};
100+
101+
// Get the byte-length of the content, which adjusts for multi-byte characters
102+
request_options.headers["Content-Length"] = Buffer.byteLength(request_options.body, "utf8");
103+
104+
var that = this;
105+
var response = needle(request_options.method, request_options.url, request_options.body, request_options);
106+
107+
return response;
108+
},
109+
88110
parseJson: function(json) {
89111
return JSON.parse(json);
90112
}

lib/service.js

+136-3
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@
717717
*
718718
* @method splunkjs.Service.Endpoint
719719
*/
720-
get: function(relpath, params, callback) {
720+
get: function(relpath, params, callback, isAsync) {
721721
var url = this.qualifiedPath;
722722

723723
// If we have a relative path, we will append it with a preceding
@@ -729,7 +729,8 @@
729729
return this.service.get(
730730
url,
731731
params,
732-
callback
732+
callback,
733+
isAsync
733734
);
734735
},
735736

@@ -1261,6 +1262,7 @@
12611262
this._load = utils.bind(this, this._load);
12621263
this.fetch = utils.bind(this, this.fetch);
12631264
this.create = utils.bind(this, this.create);
1265+
this.createAsync = utils.bind(this, this.createAsync);
12641266
this.list = utils.bind(this, this.list);
12651267
this.item = utils.bind(this, this.item);
12661268
this.instantiateEntity = utils.bind(this, this.instantiateEntity);
@@ -1394,6 +1396,34 @@
13941396

13951397
return req;
13961398
},
1399+
1400+
/**
1401+
* It's an asynchronous version of fetch(options, callback) function.
1402+
*
1403+
* Refreshes the resource by fetching the object from the server and
1404+
* loading it.
1405+
*
1406+
* @param {Object} options A dictionary of collection filtering and pagination options:
1407+
* - `count` (_integer_): The maximum number of items to return.
1408+
* - `offset` (_integer_): The offset of the first item to return.
1409+
* - `search` (_string_): The search query to filter responses.
1410+
* - `sort_dir` (_string_): The direction to sort returned items: “asc” or “desc”.
1411+
* - `sort_key` (_string_): The field to use for sorting (optional).
1412+
* - `sort_mode` (_string_): The collating sequence for sorting returned items: “auto”, “alpha”, “alpha_case”, or “num”.
1413+
*
1414+
* @method splunkjs.Service.Collection
1415+
*/
1416+
fetchAsync: async function(options) {
1417+
options = options || {};
1418+
if (!options.count) {
1419+
options.count = 0;
1420+
}
1421+
1422+
var that = this;
1423+
var response = await that.get("", options, null, true);
1424+
that._load(response.body);
1425+
return that;
1426+
},
13971427

13981428
/**
13991429
* Returns a specific entity from the collection.
@@ -3091,7 +3121,110 @@
30913121
});
30923122

30933123
return req;
3094-
}
3124+
},
3125+
3126+
/**
3127+
* Fetch a configuration file.
3128+
*
3129+
* @param {String} file A name for configuration file.
3130+
* @return file, if exists or null
3131+
*
3132+
* @endpoint properties
3133+
* @method splunkjs.Service.Configurations
3134+
*/
3135+
getConfFile: async function(filename) {
3136+
var that = this;
3137+
3138+
// 1. Fetch files list
3139+
var response = await this.get("", {__conf: filename}, null, true);
3140+
3141+
// 2. Filter the files
3142+
var files = response
3143+
&& response.body
3144+
&& response.body.entry
3145+
&& response.body.entry.filter(f => f.name === filename);
3146+
3147+
// 3. Check if the file exists
3148+
if(files && files.length == 0) {
3149+
return null;
3150+
}
3151+
3152+
// 4. Create a local instance
3153+
var configurationFile = new root.ConfigurationFile(that.service, filename);
3154+
3155+
// 5. Load the file content
3156+
var fetchedFile = await configurationFile.fetchAsync();
3157+
3158+
return fetchedFile;
3159+
},
3160+
3161+
/**
3162+
* Fetch a configuration stanza.
3163+
*
3164+
* @param {String} file A configuration file.
3165+
* @param {String} stanza A configuration stanza.
3166+
* @return stanza, if exists or null
3167+
*
3168+
* @endpoint properties
3169+
* @method splunkjs.Service.Configurations
3170+
*/
3171+
getStanza: async function(file, stanza) {
3172+
// 1. check if the stanza exists
3173+
var fetchedStanza = file.item(stanza);
3174+
3175+
if(fetchedStanza == undefined) {
3176+
return null;
3177+
}
3178+
else {
3179+
return fetchedStanza;
3180+
}
3181+
},
3182+
3183+
/**
3184+
* Creates/Updates a configuration file and stanza.
3185+
*
3186+
* @param {String} filename A name for this configuration file to be created/updated.
3187+
* @param {String} stanzaName A name for the stanza to be created/updated.
3188+
* @param {String} keyValueMap A key-value map of properties to be put under the stanza.
3189+
* @param {Function} callback A function to call with the new configuration file.
3190+
*
3191+
* @endpoint properties
3192+
* @method splunkjs.Service.Configurations
3193+
*/
3194+
createAsync: async function (filename, stanzaName, keyValueMap, callback) {
3195+
callback = callback || function() {};
3196+
var that = this;
3197+
3198+
// 1. Check if the file exists
3199+
var configFile = await this.getConfFile(filename);
3200+
3201+
// 2. If the file doesn't exist, create a new file
3202+
if(configFile == undefined) {
3203+
3204+
that.create( { __conf: filename });
3205+
3206+
configFile = new root.ConfigurationFile( that.service, filename );
3207+
configFile = await configFile.fetchAsync();
3208+
}
3209+
3210+
// 3. Check if the stanza exists
3211+
var configStanza = await this.getStanza(configFile, stanzaName);
3212+
3213+
// 4. If the stanza doesn't exist, create a new stanza with given keyValueMap
3214+
if(configStanza == undefined) {
3215+
3216+
configFile.create(stanzaName, keyValueMap, function (err, newStanza) {
3217+
callback();
3218+
});
3219+
}
3220+
3221+
// 5. If the stanza exists, update it with the keyValueMap
3222+
else {
3223+
configStanza.update(keyValueMap, (err, updatedStanza) => {
3224+
callback();
3225+
});
3226+
}
3227+
},
30953228
});
30963229

30973230
/**

0 commit comments

Comments
 (0)