blob: 3ef9027d9e359e446cc20a4aaa35775c539b96a8 [file] [log] [blame]
Jeremy Mordkoffe29efc32016-09-07 18:59:17 -04001
2/*
Laurence Maultsbyb771a7f2016-10-18 09:59:29 -04003 *
Jeremy Mordkoffe29efc32016-09-07 18:59:17 -04004 * Copyright 2016 RIFT.IO Inc
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
Laurence Maultsbyb771a7f2016-10-18 09:59:29 -040019'use strict';
Jeremy Mordkoffe29efc32016-09-07 18:59:17 -040020var Promise = require('bluebird');
21var utils = require('../../../framework/core/api_utils/utils.js');
22var request = utils.request;
23var constants = require('../../../framework/core/api_utils/constants.js');
24var _ = require('lodash');
Laurence Maultsbyb771a7f2016-10-18 09:59:29 -040025var APIVersion = '/v2';
Jeremy Mordkoffe29efc32016-09-07 18:59:17 -040026var transforms = require('./transforms.js');
27
28var foreverOn = true;
29
30var Config = {};
31var Console = {};
32var Filter = {};
33var Operational = {};
34var Sink = {};
35var SysLogViewer = {};
36var Aggregate = {};
37
38var Test = {};
39
40// Helper functions
41// TODO: Consolidate the build functions, provide method type as arg
42
43function buildGetRequestOptions(req, endpoint) {
44 var headers = _.extend({},
45 constants.HTTP_HEADERS.accept.data, {
46 'Authorization': req.get('Authorization')
47 });
48 var api_server = req.query["api_server"];
49 var requestOptions = {
50 url: utils.confdPort(api_server) + endpoint,
51 method: 'GET',
52 headers: headers,
53 forever: constants.FOREVER_ON,
54 rejectUnauthorized: false
55 };
56 return requestOptions;
57}
58
59function buildPutRequestOptions(req, endpoint, jsonData) {
60 var headers = _.extend({},
61 constants.HTTP_HEADERS.accept.data,
62 constants.HTTP_HEADERS.content_type.data, {
63 'Authorization': req.get('Authorization')
64 });
65 var api_server = req.query["api_server"];
66 var requestOptions = {
67 url: utils.confdPort(api_server) + endpoint,
68 method: 'PUT',
69 headers: headers,
70 forever: constants.FOREVER_ON,
71 rejectUnauthorized: false,
72 json: jsonData
73 };
74 return requestOptions;
75}
76
77
78function buildDeleteRequestOptions(req, endpoint) {
79 var headers = _.extend({},
80 constants.HTTP_HEADERS.accept.data,
81 constants.HTTP_HEADERS.content_type.data, {
82 'Authorization': req.get('Authorization')
83 });
84 var api_server = req.query["api_server"];
85 var requestOptions = {
86 url: utils.confdPort(api_server) + endpoint,
87 method: 'DELETE',
88 headers: headers,
89 forever: constants.FOREVER_ON,
90 rejectUnauthorized: false
91 };
92 return requestOptions;
93}
94
95/**
96* Used for simulating latency
97*/
98function resolve_with_delay(resolve, data, delay) {
99 return setTimeout(function() {
100 resolve(data)
101 }, delay);
102}
103
104/**
105 * This function provides the default callback for requests
106 */
107function requestCallback(resolve, reject, transformFunc) {
108 return function(error, response, body) {
109 if (utils.validateResponse('', error, response, body, resolve, reject)) {
110 if (transformFunc) {
111 var data = transformFunc(response.body);
112 } else {
113 var data = JSON.stringify(response.body);
114 }
Laurence Maultsby660c2a12016-10-20 12:30:41 -0400115 return resolve({
Jeremy Mordkoffe29efc32016-09-07 18:59:17 -0400116 statusCode: response.statusCode,
117 data: data
Laurence Maultsby660c2a12016-10-20 12:30:41 -0400118 });
Jeremy Mordkoffe29efc32016-09-07 18:59:17 -0400119 };
120 };
121}
122
123function handleGetRequest(req, endpoint, responseTransform) {
124 return new Promise(function(resolve, reject) {
125 request(
126 buildGetRequestOptions(req, endpoint),
127 requestCallback(resolve, reject, responseTransform)
128 );
129 });
130}
131
132/**
133 *
134 */
135// TODO: Add arg for transform function to transfrm req.body to json data
136// Right now we'll just pass the request through, until we need to implement
137// a transformer
138function handlePutRequest(req, endpoint, body) {
139 return new Promise(function(resolve, reject) {
140 request(
141 buildPutRequestOptions(req, endpoint, body||req.body),
142 requestCallback(resolve, reject)
143 );
144 });
145}
146
147function handleDeleteRequest(req, endpoint, body) {
148 return new Promise(function(resolve, reject) {
149 request(
150 buildDeleteRequestOptions(req, endpoint),
151 requestCallback(resolve, reject)
152 );
153 });
154}
155
156function handleMockResponse(req, success, statusCode, data, delay) {
157 delay = delay || 0;
158 return new Promise(function(resolve, reject) {
159 if (success) {
160 resolve_with_delay(resolve, { statusCode: statusCode, data: data }, delay)
161 } else { reject({ statusCode: statusCode, data: data }); }
162 });
163}
164
165
166function handleReject(req, statusCode, message) {
167 return new Promise(function(resolve, reject) {
168 reject({ statusCode: statusCode, data: message});
169 })
170}
171
172/**
173* Calllback function to parse the response body into an object and
174* remove the restconf top level key if it is present.
175*/
176function transformLoggingRootResponseCallback(responseBody) {
177 var data = JSON.parse(responseBody);
178 if (data['rwlog-mgmt:logging']) {
179 data = data['rwlog-mgmt:logging'];
180 }
181 return data;
182}
183
184
185/**
186 * Debug function
187 */
188function dumpLoggingConfig(data) {
189 console.log("dumpLoggingconfig");
190 var logConfig = data['lwlog-mgmt:logging'] || data;
191
192 console.log("keys=", Object.keys(logConfig));
193 console.log("stringify=", JSON.stringify(logConfig));
194 if (logConfig['default-severity']) {
195 logConfig['default-severity'].forEach(function(obj) {
196 console.log(obj);
197 })
198 }
199 if (logConfig['sink']) {
200 console.log('sink=', JSON.stringify(logConfig['sink']));
201 }
202 if (logConfig['console']) {
203 console.log('console=', JSON.stringify(logConfig['console']));
204 }
205 if (logConfig['deny']) {
206 console.log('deny=', JSON.stringify(logConfig['deny']));
207 }
208}
209
210// Aggregate calls
211
212/**
213* This method should fill out the full data set
214*/
215Aggregate.get = function(req) {
216 // get config data
217 // get operational data
218 //massage them
219 var configData = Config.get(req);
220 var operationalData = Operational.get(req);
221
222 return new Promise(function(resolve, reject) {
223 Promise.all([configData, operationalData]).then(function(resolves) {
224 //console.log("Resolved all request promises (config, operational logging data)");
225 // TODO: Make sure the statusCodes for each resulves is 200
226 var decoder = new transforms.LoggingConfigDecoder();
227 resolve({
228 statusCode: 200,
229 data: decoder.decode(resolves[0], resolves[1])
230 });
231
232 }).catch(function(error) {
233 console.log("Logging: Aggregate.get error: ", error);
234 reject({
235 statusCode: 404,
236 errorMessage: error
237 })
238 })
239 });
240}
241
242/**
243* This method expects the full data set (keys and values) for the logging
244* config to replace the existing logging config
245*/
246Aggregate.set = function(req) {
247 // NOTE: Left some debugging code remarked out
248
249 //console.log("Logging Aggregate.set called");
250 //console.log("data=", req.body);
251
252 // Do nothing to test delay in response
253 var encoder = new transforms.LoggingConfigEncoder();
254 var data = encoder.encode(req.body);
Laurence Maultsbyb771a7f2016-10-18 09:59:29 -0400255 // console.log("Aggregate.set. encoded data=");
256 // console.log(data);
Jeremy Mordkoffe29efc32016-09-07 18:59:17 -0400257 // dumpLoggingConfig(data);
Laurence Maultsbyb771a7f2016-10-18 09:59:29 -0400258 let setData = {
259 'rwlog-mgmt:logging' : data
260 }
261 return handlePutRequest(req, APIVersion + '/api/config/logging', setData);
Jeremy Mordkoffe29efc32016-09-07 18:59:17 -0400262 // if (this.mockResponse['set']) {
263 // return handleMockResponse(req, true, 201, data, delay=100);
264 // }
265}
266
267
268
269
270
271// Config calls
272
273/**
274 * Get all currently set logging config data
275 */
276Config.get = function(req) {
277 return handleGetRequest(req, APIVersion + '/api/config/logging?deep',
278 transformLoggingRootResponseCallback
279 );
280}
281
282/**
283 * Top level put method. Restconf cannot currently handle a global put on
284 * logging, so this method is currently for testing
285 */
286Config.set = function(req) {
287 return handlePutRequest(req, APIVersion + '/api/config/logging');
288}
289
290
291Config.setConsole = function(req) {
292 return handlePutRequest(req, APIVersion + '/api/config/logging/console');
293}
294
295Config.setFilter = function(req) {
296 return handlePutRequest(req, APIVersion + '/api/config/logging/console/filter');
297}
298
299Config.setDefaultSeverity = function(req) {
300 // TODO: verify there is one key at root of data: 'default-severity'
301 // OR just filter on the request body
302 return handlePutRequest(req, APIVersion + '/api/config/logging/');
303}
304
305Config.deleteDefaultSeverity = function(req) {
306 // TODO: verify there is one key at root of data: 'default-severity'
307 // OR just filter on the request body
308 var Categories = req.body['default-severity'];
309 return new Promise(function(resolve, reject) {
310 var promises = Categories.map(function(c) {
311 return handleDeleteRequest(req, APIVersion + '/api/config/logging/default-severity/' + c.category);
312 });
313 return Promise.all(promises).then(
314 function(data) {
315 resolve(data[0]);
316 },
317 function(data) {
318 reject(data);
319 }
320 )
321 })
322
323}
324
KIRAN KASHALKAR27eea262016-10-19 16:14:50 -0400325// NOTE: In rel_4.3 we are going to affect syslog sink category by default
326
327Config.setDefaultSyslogSeverity = function(req) {
328 // TODO: verify there is one key at root of data: 'default-severity'
329 // OR just filter on the request body
330 return handlePutRequest(req, APIVersion + '/api/config/logging/sink/syslog');
331}
332
333Config.deleteDefaultSyslogSeverity = function(req) {
334 // TODO: verify there is one key at root of data: 'default-severity'
335 // OR just filter on the request body
Laurence Maultsby0aadbca2016-10-20 11:23:09 -0400336 var Categories = req.params.nulledCategories.split(',');
337 var promises = [];
KIRAN KASHALKAR27eea262016-10-19 16:14:50 -0400338 return new Promise(function(resolve, reject) {
Laurence Maultsby0aadbca2016-10-20 11:23:09 -0400339 promises.concat(Categories.map(function(categoryName) {
340 return handleDeleteRequest(req, APIVersion + '/api/config/logging/sink/syslog/filter/category/' + categoryName);
341 }));
342 return Promise.all(promises).then(
343 function(data) {
Laurence Maultsby660c2a12016-10-20 12:30:41 -0400344 resolve({statusCode: data[0].statusCode, data: data[0].data});
Laurence Maultsby0aadbca2016-10-20 11:23:09 -0400345 },
346 function(data) {
Laurence Maultsby660c2a12016-10-20 12:30:41 -0400347 reject({statusCode: data[0].statusCode, data: data[0].data});
Laurence Maultsby0aadbca2016-10-20 11:23:09 -0400348 }
349 )
KIRAN KASHALKAR27eea262016-10-19 16:14:50 -0400350 });
KIRAN KASHALKAR27eea262016-10-19 16:14:50 -0400351}
352
Jeremy Mordkoffe29efc32016-09-07 18:59:17 -0400353/*
354 get body of forms
355
356{
357 "allowDuplicateEvents" : true
358}
359*/
360
361/**
362 * TODO: Repeat delete calls (when 'allowDuplicateEvents' value is false) cause
363 * a 404 error
364 * TODO: the call to handleDeleteRequest returns stringified data, but the PUT
365 * does not (This is the behavior we want)
366 *
367 * Improvement? Allos string representation of true/false
368 */
369Config.setAllowDuplicateEvents = function(req) {
370 // TODO: verify there is one key at root of data: 'default-severity'
371 // OR just filter on the request body
Laurence Maultsbycf5edaf2016-10-20 21:39:20 -0400372console.log(req.body)
373 if (req.body.hasOwnProperty('allowDuplicateEvents')) {
374 if (req.body.allowDuplicateEvents.toUpperCase() == "TRUE") {
375 return handlePutRequest(req, '/api/config/logging/allow', {
Jeremy Mordkoffe29efc32016-09-07 18:59:17 -0400376 "duplicate": "events"
377 });
378 } else { // false, remove entry from logging config
Laurence Maultsbycf5edaf2016-10-20 21:39:20 -0400379 return handleDeleteRequest(req, '/api/config/logging/allow/duplicate');
Jeremy Mordkoffe29efc32016-09-07 18:59:17 -0400380 }
381 } else {
382 return handleReject(statusCode=400,
383 data={
384 "message": 'Expected key, "allowDuplicateEvents" not found',
385 "original-request" : req.body
386 });
387 }
388}
389
390/*
391 "denyEvents": {
392 "eventIDs": [
393 1
394 ]
395 },
396*/
397
398/*
399 "deny": {
400 "event": [
401 {
402 "event-Id": 1
403 }
404 ]
405 },
406*/
407
408Config.setDenyEvents = function(req) {
409 var reqBody = {
410 deny: {
411 events: req.body.denyEvents.eventIDs.map(function(eventID) {
412 return { "event-Id": eventID };
413 })
414 }
415 };
416 return handlePutRequest(req, APIVersion + '/api/config/logging', reqBody);
417}
418
419Config.setSyslogViewer = function(req) {
420 // TODO: Verify structure of req.body
421 var reqBody = {
422 "syslog-viewer" : req.body['syslog-viewer']
423 }
424 return handlePutRequest(req, APIVersion + '/api/config/logging', reqBody);
425}
426
427
428// Operational calls
429
430Operational.get = function(req) {
Laurence Maultsbyb771a7f2016-10-18 09:59:29 -0400431 var APIVersion = '/v1'
Jeremy Mordkoffe29efc32016-09-07 18:59:17 -0400432 return handleGetRequest(req, APIVersion + '/api/operational/logging?deep',
433 transformLoggingRootResponseCallback
434 );
435}
436
437
438/**
439 * Legacy call to get sys log viewer
440 */
441
442SysLogViewer.get = function(req) {
443 console.log("\n***\n SysLogViewer.get called");
444 var api_server = req.query['api_server'];
445 return new Promise(function(resolve, reject) {
446 request({
447 uri: utils.confdPort(api_server) + APIVersion + '/api/config/logging/syslog-viewer',
448 method: 'GET',
449 headers: _.extend({},
450 constants.HTTP_HEADERS.accept.data,
451 {
452 'Authorization': req.get('Authorization')
453 }),
454 forever: foreverOn,
455 rejectUnauthorized: false
456 },
457 function(error, response, body) {
458 if(error) {
459 console.log('Logging.get failed. Error:', error);
460 reject({
461 statusCode: response ? response.statusCode : 404,
462 errorMessage: 'Issue retrieving syslog-viewer url'
463 });
464 } else {
465 var data;
466 try {
467 data = JSON.parse(response.body);
468 } catch (e) {
469 console.log('Logging.get failed while parsing response.body. Error:', e);
470 reject({
471 statusCode: 500,
472 errorMessage: 'Error parsing response.body during Logging.get'
473 });
474 }
475 resolve(data);
476 }
477 });
478 });
479};
480
481/**
482 * Test methods
483 */
484Test.roundtrip = function(req) {
485 return new Promise(function(resolve, reject) {
486 Aggregate.get(req).then(function(result) {
487 var data = (new transforms.LoggingConfigEncoder()).encode(result.data);
488 resolve({
489 statusCode: 200,
490 data: {
491 'rwlog-mgmt:logging': data
492 }
493 });
494 }, function(err) {
495 console.log('Test.get error:', err);
496 reject({
497 statusCode: 500,
498 errorMessage: err
499 });
500 });
501 });
502}
503
504module.exports = {
505 aggregate: Aggregate,
506 config : Config,
507 operational: Operational,
508 sysLogViewer: SysLogViewer,
509 test: Test
510}