@itentialopensource/adapter-aruba_airwave 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/.eslintignore +6 -0
  2. package/.eslintrc.js +18 -0
  3. package/.gitlab/.gitkeep +0 -0
  4. package/.gitlab/issue_templates/.gitkeep +0 -0
  5. package/.gitlab/issue_templates/Default.md +17 -0
  6. package/.gitlab/issue_templates/bugReportTemplate.md +76 -0
  7. package/.gitlab/issue_templates/featureRequestTemplate.md +14 -0
  8. package/.jshintrc +0 -0
  9. package/CHANGELOG.md +9 -0
  10. package/CODE_OF_CONDUCT.md +48 -0
  11. package/CONTRIBUTING.md +158 -0
  12. package/LICENSE +201 -0
  13. package/README.md +544 -0
  14. package/adapter.js +2860 -0
  15. package/adapterBase.js +906 -0
  16. package/entities/.system/action.json +50 -0
  17. package/entities/.system/mockdatafiles/getToken-default.json +3 -0
  18. package/entities/.system/mockdatafiles/healthcheck-default.json +3 -0
  19. package/entities/.system/schema.json +19 -0
  20. package/entities/.system/schemaTokenReq.json +77 -0
  21. package/entities/.system/schemaTokenResp.json +65 -0
  22. package/entities/BatchExecuteAPCommandsAPIS/action.json +45 -0
  23. package/entities/BatchExecuteAPCommandsAPIS/schema.json +20 -0
  24. package/entities/ConfigurationAPIS/action.json +126 -0
  25. package/entities/ConfigurationAPIS/schema.json +90 -0
  26. package/entities/DeviceAPIS/action.json +46 -0
  27. package/entities/DeviceAPIS/schema.json +20 -0
  28. package/entities/LOGIN/action.json +24 -0
  29. package/entities/LOGIN/schema.json +41 -0
  30. package/entities/QueryAPIS/action.json +298 -0
  31. package/entities/QueryAPIS/schema.json +32 -0
  32. package/entities/ReportAPIS/action.json +25 -0
  33. package/entities/ReportAPIS/schema.json +30 -0
  34. package/entities/SearchAPIS/action.json +67 -0
  35. package/entities/SearchAPIS/schema.json +21 -0
  36. package/error.json +184 -0
  37. package/package.json +86 -0
  38. package/pronghorn.json +1589 -0
  39. package/propertiesSchema.json +801 -0
  40. package/refs?service=git-upload-pack +0 -0
  41. package/report/ArubaAirwavePostman.json-OpenApi3Json.json +1583 -0
  42. package/report/creationReport.json +381 -0
  43. package/sampleProperties.json +97 -0
  44. package/test/integration/adapterTestBasicGet.js +85 -0
  45. package/test/integration/adapterTestConnectivity.js +93 -0
  46. package/test/integration/adapterTestIntegration.js +1125 -0
  47. package/test/unit/adapterBaseTestUnit.js +929 -0
  48. package/test/unit/adapterTestUnit.js +1413 -0
  49. package/utils/artifactize.js +146 -0
  50. package/utils/basicGet.js +63 -0
  51. package/utils/packModificationScript.js +35 -0
  52. package/utils/pre-commit.sh +27 -0
  53. package/utils/setup.js +33 -0
  54. package/utils/tbScript.js +163 -0
  55. package/utils/tbUtils.js +372 -0
  56. package/utils/testRunner.js +298 -0
  57. package/utils/troubleshootingAdapter.js +219 -0
  58. package/workflows/README.md +3 -0
package/adapterBase.js ADDED
@@ -0,0 +1,906 @@
1
+ /* @copyright Itential, LLC 2018-9 */
2
+
3
+ // Set globals
4
+ /* global log */
5
+ /* eslint class-methods-use-this:warn */
6
+ /* eslint import/no-dynamic-require: warn */
7
+ /* eslint no-loop-func: warn */
8
+ /* eslint no-cond-assign: warn */
9
+ /* eslint global-require: warn */
10
+ /* eslint no-unused-vars: warn */
11
+
12
+ /* Required libraries. */
13
+ const fs = require('fs-extra');
14
+ const path = require('path');
15
+ const EventEmitterCl = require('events').EventEmitter;
16
+ const { execSync } = require('child_process');
17
+
18
+ /* The schema validator */
19
+ const AjvCl = require('ajv');
20
+
21
+ /* Fetch in the other needed components for the this Adaptor */
22
+ const PropUtilCl = require('@itentialopensource/adapter-utils').PropertyUtility;
23
+ const RequestHandlerCl = require('@itentialopensource/adapter-utils').RequestHandler;
24
+ const troubleshootingAdapter = require('./utils/troubleshootingAdapter');
25
+ const tbUtils = require('./utils/tbUtils');
26
+
27
+ let propUtil = null;
28
+
29
+ /*
30
+ * INTERNAL FUNCTION: force fail the adapter - generally done to cause restart
31
+ */
32
+ function forceFail(packChg) {
33
+ if (packChg !== undefined && packChg !== null && packChg === true) {
34
+ execSync(`rm -rf ${__dirname}/node modules`, { encoding: 'utf-8' });
35
+ execSync(`rm -rf ${__dirname}/package-lock.json`, { encoding: 'utf-8' });
36
+ execSync('npm install', { encoding: 'utf-8' });
37
+ }
38
+ log.error('NEED TO RESTART ADAPTER - FORCE FAIL');
39
+ const errorObj = {
40
+ origin: 'adapter-forceFail',
41
+ type: 'Force Fail so adapter will restart',
42
+ vars: []
43
+ };
44
+ setTimeout(() => {
45
+ throw new Error(JSON.stringify(errorObj));
46
+ }, 1000);
47
+ }
48
+
49
+ /*
50
+ * INTERNAL FUNCTION: update the action.json
51
+ */
52
+ function updateAction(entityPath, action, changes) {
53
+ // if the action file does not exist - error
54
+ const actionFile = path.join(entityPath, '/action.json');
55
+ if (!fs.existsSync(actionFile)) {
56
+ return 'Missing Action File';
57
+ }
58
+
59
+ // read in the file as a json object
60
+ const ajson = require(path.resolve(entityPath, 'action.json'));
61
+ let chgAct = {};
62
+
63
+ // get the action we need to change
64
+ for (let a = 0; a < ajson.actions.length; a += 1) {
65
+ if (ajson.actions[a].name === action) {
66
+ chgAct = ajson.actions[a];
67
+ break;
68
+ }
69
+ }
70
+ // merge the changes into the desired action
71
+ chgAct = propUtil.mergeProperties(changes, chgAct);
72
+
73
+ fs.writeFileSync(actionFile, JSON.stringify(ajson, null, 2));
74
+ return null;
75
+ }
76
+
77
+ /*
78
+ * INTERNAL FUNCTION: update the schema file
79
+ */
80
+ function updateSchema(entityPath, configFile, changes) {
81
+ // if the schema file does not exist - error
82
+ const schemaFile = path.join(entityPath, `/${configFile}`);
83
+ if (!fs.existsSync(schemaFile)) {
84
+ return 'Missing Schema File';
85
+ }
86
+
87
+ // read in the file as a json object
88
+ let schema = require(path.resolve(entityPath, configFile));
89
+
90
+ // merge the changes into the schema file
91
+ schema = propUtil.mergeProperties(changes, schema);
92
+
93
+ fs.writeFileSync(schemaFile, JSON.stringify(schema, null, 2));
94
+ return null;
95
+ }
96
+
97
+ /*
98
+ * INTERNAL FUNCTION: update the mock data file
99
+ */
100
+ function updateMock(mockPath, configFile, changes) {
101
+ // if the mock file does not exist - create it
102
+ const mockFile = path.join(mockPath, `/${configFile}`);
103
+ if (!fs.existsSync(mockFile)) {
104
+ const newMock = {};
105
+ fs.writeFileSync(mockFile, JSON.stringify(newMock, null, 2));
106
+ }
107
+
108
+ // read in the file as a json object
109
+ let mock = require(path.resolve(mockPath, configFile));
110
+
111
+ // merge the changes into the mock file
112
+ mock = propUtil.mergeProperties(changes, mock);
113
+
114
+ fs.writeFileSync(mockFile, JSON.stringify(mock, null, 2));
115
+ return null;
116
+ }
117
+
118
+ /*
119
+ * INTERNAL FUNCTION: update the package dependencies
120
+ */
121
+ function updatePackage(changes) {
122
+ // if the schema file does not exist - error
123
+ const packFile = path.join(__dirname, '/package.json');
124
+ if (!fs.existsSync(packFile)) {
125
+ return 'Missing Pacakge File';
126
+ }
127
+
128
+ // read in the file as a json object
129
+ const pack = require(path.resolve(__dirname, 'package.json'));
130
+
131
+ // only certain changes are allowed
132
+ if (changes.dependencies) {
133
+ const keys = Object.keys(changes.dependencies);
134
+
135
+ for (let k = 0; k < keys.length; k += 1) {
136
+ pack.dependencies[keys[k]] = changes.dependencies[keys[k]];
137
+ }
138
+ }
139
+
140
+ fs.writeFileSync(packFile, JSON.stringify(pack, null, 2));
141
+ return null;
142
+ }
143
+
144
+ /* GENERAL ADAPTER FUNCTIONS THESE SHOULD NOT BE DIRECTLY MODIFIED */
145
+ /* IF YOU NEED MODIFICATIONS, REDEFINE THEM IN adapter.js!!! */
146
+ class AdapterBase extends EventEmitterCl {
147
+ /**
148
+ * [System] Adapter
149
+ * @constructor
150
+ */
151
+ constructor(prongid, properties) {
152
+ // Instantiate the EventEmitter super class
153
+ super();
154
+
155
+ try {
156
+ // Capture the adapter id
157
+ this.id = prongid;
158
+ this.propUtilInst = new PropUtilCl(prongid, __dirname);
159
+ propUtil = this.propUtilInst;
160
+ this.initProps = properties;
161
+ this.alive = false;
162
+ this.healthy = false;
163
+ this.suspended = false;
164
+ this.suspendMode = 'pause';
165
+ this.caching = false;
166
+ this.repeatCacheCount = 0;
167
+ this.allowFailover = 'AD.300';
168
+ this.noFailover = 'AD.500';
169
+
170
+ // set up the properties I care about
171
+ this.refreshProperties(properties);
172
+
173
+ // Instantiate the other components for this Adapter
174
+ this.requestHandlerInst = new RequestHandlerCl(this.id, this.allProps, __dirname);
175
+ } catch (e) {
176
+ // handle any exception
177
+ const origin = `${this.id}-adapterBase-constructor`;
178
+ log.error(`${origin}: Adapter may not have started properly. ${e}`);
179
+ }
180
+ }
181
+
182
+ /**
183
+ * @callback healthCallback
184
+ * @param {Object} result - the result of the get request (contains an id and a status)
185
+ */
186
+ /**
187
+ * @callback getCallback
188
+ * @param {Object} result - the result of the get request (entity/ies)
189
+ * @param {String} error - any error that occured
190
+ */
191
+ /**
192
+ * @callback createCallback
193
+ * @param {Object} item - the newly created entity
194
+ * @param {String} error - any error that occured
195
+ */
196
+ /**
197
+ * @callback updateCallback
198
+ * @param {String} status - the status of the update action
199
+ * @param {String} error - any error that occured
200
+ */
201
+ /**
202
+ * @callback deleteCallback
203
+ * @param {String} status - the status of the delete action
204
+ * @param {String} error - any error that occured
205
+ */
206
+
207
+ /**
208
+ * refreshProperties is used to set up all of the properties for the connector.
209
+ * It allows properties to be changed later by simply calling refreshProperties rather
210
+ * than having to restart the connector.
211
+ *
212
+ * @function refreshProperties
213
+ * @param {Object} properties - an object containing all of the properties
214
+ * @param {boolean} init - are we initializing -- is so no need to refresh throtte engine
215
+ */
216
+ refreshProperties(properties) {
217
+ const meth = 'adapterBase-refreshProperties';
218
+ const origin = `${this.id}-${meth}`;
219
+ log.trace(origin);
220
+
221
+ try {
222
+ // Read the properties schema from the file system
223
+ const propertiesSchema = JSON.parse(fs.readFileSync(path.join(__dirname, 'propertiesSchema.json'), 'utf-8'));
224
+
225
+ // add any defaults to the data
226
+ const defProps = this.propUtilInst.setDefaults(propertiesSchema);
227
+ this.allProps = this.propUtilInst.mergeProperties(properties, defProps);
228
+
229
+ // validate the entity against the schema
230
+ const ajvInst = new AjvCl();
231
+ const validate = ajvInst.compile(propertiesSchema);
232
+ const result = validate(this.allProps);
233
+
234
+ // if invalid properties throw an error
235
+ if (!result) {
236
+ if (this.requestHandlerInst) {
237
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Invalid Properties', [JSON.stringify(validate.errors)], null, null, null);
238
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
239
+ throw new Error(JSON.stringify(errorObj));
240
+ } else {
241
+ log.error(`${origin}: ${JSON.stringify(validate.errors)}`);
242
+ throw new Error(`${origin}: ${JSON.stringify(validate.errors)}`);
243
+ }
244
+ }
245
+
246
+ // properties that this code cares about
247
+ this.healthcheckType = this.allProps.healthcheck.type;
248
+ this.healthcheckInterval = this.allProps.healthcheck.frequency;
249
+
250
+ // set the failover codes from properties
251
+ if (this.allProps.request.failover_codes) {
252
+ if (Array.isArray(this.allProps.request.failover_codes)) {
253
+ this.failoverCodes = this.allProps.request.failover_codes;
254
+ } else {
255
+ this.failoverCodes = [this.allProps.request.failover_codes];
256
+ }
257
+ } else {
258
+ this.failoverCodes = [];
259
+ }
260
+
261
+ // set the caching flag from properties
262
+ if (this.allProps.cache_location) {
263
+ if (this.allProps.cache_location === 'redis' || this.allProps.cache_location === 'local') {
264
+ this.caching = true;
265
+ }
266
+ }
267
+
268
+ // if this is truly a refresh and we have a request handler, refresh it
269
+ if (this.requestHandlerInst) {
270
+ this.requestHandlerInst.refreshProperties(properties);
271
+ }
272
+ } catch (e) {
273
+ log.error(`${origin}: Properties may not have been set properly. ${e}`);
274
+ }
275
+ }
276
+
277
+ /**
278
+ * updateAdapterConfiguration is used to update any of the adapter configuration files. This
279
+ * allows customers to make changes to adapter configuration without having to be on the
280
+ * file system.
281
+ *
282
+ * @function updateAdapterConfiguration
283
+ * @param {string} configFile - the name of the file being updated (required)
284
+ * @param {Object} changes - an object containing all of the changes = formatted like the configuration file (required)
285
+ * @param {string} entity - the entity to be changed, if an action, schema or mock data file (optional)
286
+ * @param {string} type - the type of entity file to change, (action, schema, mock) (optional)
287
+ * @param {string} action - the action to be changed, if an action, schema or mock data file (optional)
288
+ * @param {Callback} callback - The results of the call
289
+ */
290
+ updateAdapterConfiguration(configFile, changes, entity, type, action, callback) {
291
+ const meth = 'adapterBase-updateAdapterConfiguration';
292
+ const origin = `${this.id}-${meth}`;
293
+ log.trace(origin);
294
+
295
+ // verify the parameters are valid
296
+ if (changes === undefined || changes === null || typeof changes !== 'object'
297
+ || Object.keys(changes).length === 0) {
298
+ const result = {
299
+ response: 'No configuration updates to make'
300
+ };
301
+ log.info(result.response);
302
+ return callback(result, null);
303
+ }
304
+ if (configFile === undefined || configFile === null || configFile === '') {
305
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['configFile'], null, null, null);
306
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
307
+ return callback(null, errorObj);
308
+ }
309
+
310
+ // take action based on configFile being changed
311
+ if (configFile === 'package.json') {
312
+ const pres = updatePackage(changes);
313
+ if (pres) {
314
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: ${pres}`, [], null, null, null);
315
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
316
+ return callback(null, errorObj);
317
+ }
318
+ const result = {
319
+ response: 'Package updates completed - restarting adapter'
320
+ };
321
+ log.info(result.response);
322
+ forceFail(true);
323
+ return callback(result, null);
324
+ }
325
+ if (entity === undefined || entity === null || entity === '') {
326
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Unsupported Configuration Change or Missing Entity', [], null, null, null);
327
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
328
+ return callback(null, errorObj);
329
+ }
330
+
331
+ // this means we are changing an entity file so type is required
332
+ if (type === undefined || type === null || type === '') {
333
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['type'], null, null, null);
334
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
335
+ return callback(null, errorObj);
336
+ }
337
+
338
+ // if the entity does not exist - error
339
+ const epath = `${__dirname}/entities/${entity}`;
340
+ if (!fs.existsSync(epath)) {
341
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: Invalid Entity - ${entity}`, [], null, null, null);
342
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
343
+ return callback(null, errorObj);
344
+ }
345
+
346
+ // take action based on type of file being changed
347
+ if (type === 'action') {
348
+ // BACKUP???
349
+ const ares = updateAction(epath, action, changes);
350
+ if (ares) {
351
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: ${ares}`, [], null, null, null);
352
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
353
+ return callback(null, errorObj);
354
+ }
355
+ // AJV CHECK???
356
+ // RESTORE IF NEEDED???
357
+ const result = {
358
+ response: `Action updates completed to entity: ${entity} - ${action}`
359
+ };
360
+ log.info(result.response);
361
+ return callback(result, null);
362
+ }
363
+ if (type === 'schema') {
364
+ const sres = updateSchema(epath, configFile, changes);
365
+ if (sres) {
366
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: ${sres}`, [], null, null, null);
367
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
368
+ return callback(null, errorObj);
369
+ }
370
+ const result = {
371
+ response: `Schema updates completed to entity: ${entity} - ${configFile}`
372
+ };
373
+ log.info(result.response);
374
+ return callback(result, null);
375
+ }
376
+ if (type === 'mock') {
377
+ // if the mock directory does not exist - error
378
+ const mpath = `${__dirname}/entities/${entity}/mockdatafiles`;
379
+ if (!fs.existsSync(mpath)) {
380
+ fs.mkdirSync(mpath);
381
+ }
382
+
383
+ const mres = updateMock(mpath, configFile, changes);
384
+ if (mres) {
385
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: ${mres}`, [], null, null, null);
386
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
387
+ return callback(null, errorObj);
388
+ }
389
+ const result = {
390
+ response: `Mock data updates completed to entity: ${entity} - ${configFile}`
391
+ };
392
+ log.info(result.response);
393
+ return callback(result, null);
394
+ }
395
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: Unsupported Type - ${type}`, [], null, null, null);
396
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
397
+ return callback(null, errorObj);
398
+ }
399
+
400
+ /**
401
+ * @summary Connect function is used during Pronghorn startup to provide instantiation feedback.
402
+ *
403
+ * @function connect
404
+ */
405
+ connect() {
406
+ const origin = `${this.id}-adapterBase-connect`;
407
+ log.trace(origin);
408
+
409
+ // initially set as off
410
+ this.emit('OFFLINE', { id: this.id });
411
+ this.alive = true;
412
+
413
+ // if there is no healthcheck just change the emit to ONLINE
414
+ // We do not recommend no healthcheck!!!
415
+ if (this.healthcheckType === 'none') {
416
+ log.error(`${origin}: Waiting 1 Seconds to emit Online`);
417
+ setTimeout(() => {
418
+ this.emit('ONLINE', { id: this.id });
419
+ this.healthy = true;
420
+ }, 1000);
421
+ }
422
+
423
+ // is the healthcheck only suppose to run on startup
424
+ // (intermittent runs on startup and after that)
425
+ if (this.healthcheckType === 'startup' || this.healthcheckType === 'intermittent') {
426
+ // run an initial healthcheck
427
+ this.healthCheck(null, (status) => {
428
+ log.spam(`${origin}: ${status}`);
429
+ });
430
+ }
431
+
432
+ // is the healthcheck suppose to run intermittently
433
+ if (this.healthcheckType === 'intermittent') {
434
+ // run the healthcheck in an interval
435
+ setInterval(() => {
436
+ // try to see if mongo is available
437
+ this.healthCheck(null, (status) => {
438
+ log.spam(`${origin}: ${status}`);
439
+ });
440
+ }, this.healthcheckInterval);
441
+ }
442
+ }
443
+
444
+ /**
445
+ * @summary Suspends the adapter
446
+ * @param {Callback} callback - The adapater suspension status
447
+ * @function suspend
448
+ */
449
+ suspend(mode, callback) {
450
+ const origin = `${this.id}-adapterBase-suspend`;
451
+ if (this.suspended) {
452
+ throw new Error(`${origin}: Adapter is already suspended`);
453
+ }
454
+ try {
455
+ this.suspended = true;
456
+ this.suspendMode = mode;
457
+ if (this.suspendMode === 'pause') {
458
+ const props = JSON.parse(JSON.stringify(this.initProps));
459
+ // To suspend adapter, enable throttling and set concurrent max to 0
460
+ props.throttle.throttle_enabled = true;
461
+ props.throttle.concurrent_max = 0;
462
+ this.refreshProperties(props);
463
+ }
464
+ return callback({ suspended: true });
465
+ } catch (error) {
466
+ return callback(null, error);
467
+ }
468
+ }
469
+
470
+ /**
471
+ * @summary Unsuspends the adapter
472
+ * @param {Callback} callback - The adapater suspension status
473
+ *
474
+ * @function unsuspend
475
+ */
476
+ unsuspend(callback) {
477
+ const origin = `${this.id}-adapterBase-unsuspend`;
478
+ if (!this.suspended) {
479
+ throw new Error(`${origin}: Adapter is not suspended`);
480
+ }
481
+ if (this.suspendMode === 'pause') {
482
+ const props = JSON.parse(JSON.stringify(this.initProps));
483
+ // To unsuspend adapter, keep throttling enabled and begin processing queued requests in order
484
+ props.throttle.throttle_enabled = true;
485
+ props.throttle.concurrent_max = 1;
486
+ this.refreshProperties(props);
487
+ setTimeout(() => {
488
+ this.getQueue((q, error) => {
489
+ // console.log("Items in queue: " + String(q.length))
490
+ if (q.length === 0) {
491
+ // if queue is empty, return to initial properties state
492
+ this.refreshProperties(this.initProps);
493
+ this.suspended = false;
494
+ return callback({ suspended: false });
495
+ }
496
+ // recursive call to check queue again every second
497
+ return this.unsuspend(callback);
498
+ });
499
+ }, 1000);
500
+ } else {
501
+ this.suspended = false;
502
+ }
503
+ }
504
+
505
+ /**
506
+ * @summary HealthCheck function is used to provide Pronghorn the status of this adapter.
507
+ *
508
+ * @function healthCheck
509
+ */
510
+ healthCheck(reqObj, callback) {
511
+ const origin = `${this.id}-adapterBase-healthCheck`;
512
+ log.trace(origin);
513
+
514
+ // call to the healthcheck in connector
515
+ return this.requestHandlerInst.identifyHealthcheck(reqObj, (res, error) => {
516
+ // unhealthy
517
+ if (error) {
518
+ // if we were healthy, toggle health
519
+ if (this.healthy) {
520
+ this.emit('OFFLINE', { id: this.id });
521
+ this.emit('DEGRADED', { id: this.id });
522
+ this.healthy = false;
523
+ log.error(`${origin}: HEALTH CHECK - Error ${error}`);
524
+ } else {
525
+ // still log but set the level to trace
526
+ log.trace(`${origin}: HEALTH CHECK - Still Errors ${error}`);
527
+ }
528
+
529
+ return callback(false);
530
+ }
531
+
532
+ // if we were unhealthy, toggle health
533
+ if (!this.healthy) {
534
+ this.emit('FIXED', { id: this.id });
535
+ this.emit('ONLINE', { id: this.id });
536
+ this.healthy = true;
537
+ log.info(`${origin}: HEALTH CHECK SUCCESSFUL`);
538
+ } else {
539
+ // still log but set the level to trace
540
+ log.trace(`${origin}: HEALTH CHECK STILL SUCCESSFUL`);
541
+ }
542
+
543
+ return callback(true);
544
+ });
545
+ }
546
+
547
+ /**
548
+ * getAllFunctions is used to get all of the exposed function in the adapter
549
+ *
550
+ * @function getAllFunctions
551
+ */
552
+ getAllFunctions() {
553
+ let myfunctions = [];
554
+ let obj = this;
555
+
556
+ // find the functions in this class
557
+ do {
558
+ const l = Object.getOwnPropertyNames(obj)
559
+ .concat(Object.getOwnPropertySymbols(obj).map((s) => s.toString()))
560
+ .sort()
561
+ .filter((p, i, arr) => typeof obj[p] === 'function' && p !== 'constructor' && (i === 0 || p !== arr[i - 1]) && myfunctions.indexOf(p) === -1);
562
+ myfunctions = myfunctions.concat(l);
563
+ }
564
+ while (
565
+ (obj = Object.getPrototypeOf(obj)) && Object.getPrototypeOf(obj)
566
+ );
567
+
568
+ return myfunctions;
569
+ }
570
+
571
+ /**
572
+ * getWorkflowFunctions is used to get all of the workflow function in the adapter
573
+ * @param {array} ignoreThese - additional methods to ignore (optional)
574
+ *
575
+ * @function getWorkflowFunctions
576
+ */
577
+ getWorkflowFunctions(ignoreThese) {
578
+ const myfunctions = this.getAllFunctions();
579
+ const wffunctions = [];
580
+
581
+ // remove the functions that should not be in a Workflow
582
+ for (let m = 0; m < myfunctions.length; m += 1) {
583
+ if (myfunctions[m] === 'addEntityCache') {
584
+ // got to the second tier (adapterBase)
585
+ break;
586
+ }
587
+ if (myfunctions[m] !== 'hasEntity' && myfunctions[m] !== 'verifyCapability' && myfunctions[m] !== 'updateEntityCache'
588
+ && myfunctions[m] !== 'healthCheck' && myfunctions[m] !== 'getWorkflowFunctions'
589
+ && !(myfunctions[m].endsWith('Emit') || myfunctions[m].match(/Emit__v[0-9]+/))) {
590
+ let found = false;
591
+ if (ignoreThese && Array.isArray(ignoreThese)) {
592
+ for (let i = 0; i < ignoreThese.length; i += 1) {
593
+ if (myfunctions[m].toUpperCase() === ignoreThese[i].toUpperCase()) {
594
+ found = true;
595
+ }
596
+ }
597
+ }
598
+ if (!found) {
599
+ wffunctions.push(myfunctions[m]);
600
+ }
601
+ }
602
+ }
603
+
604
+ return wffunctions;
605
+ }
606
+
607
+ /**
608
+ * checkActionFiles is used to update the validation of the action files.
609
+ *
610
+ * @function checkActionFiles
611
+ */
612
+ checkActionFiles() {
613
+ const origin = `${this.id}-adapterBase-checkActionFiles`;
614
+ log.trace(origin);
615
+
616
+ // validate the action files for the adapter
617
+ try {
618
+ return this.requestHandlerInst.checkActionFiles();
619
+ } catch (e) {
620
+ return ['Exception increase log level'];
621
+ }
622
+ }
623
+
624
+ /**
625
+ * checkProperties is used to validate the adapter properties.
626
+ *
627
+ * @function checkProperties
628
+ * @param {Object} properties - an object containing all of the properties
629
+ */
630
+ checkProperties(properties) {
631
+ const origin = `${this.myid}-adapterBase-checkProperties`;
632
+ log.trace(origin);
633
+
634
+ // validate the properties for the adapter
635
+ try {
636
+ return this.requestHandlerInst.checkProperties(properties);
637
+ } catch (e) {
638
+ return { exception: 'Exception increase log level' };
639
+ }
640
+ }
641
+
642
+ /**
643
+ * getQueue is used to get information for all of the requests currently in the queue.
644
+ *
645
+ * @function getQueue
646
+ * @param {Callback} callback - a callback function to return the result (Queue) or the error
647
+ */
648
+ getQueue(callback) {
649
+ const origin = `${this.id}-adapterBase-getQueue`;
650
+ log.trace(origin);
651
+
652
+ return this.requestHandlerInst.getQueue(callback);
653
+ }
654
+
655
+ /**
656
+ * @summary Takes in property text and an encoding/encryption and returns the resulting
657
+ * encoded/encrypted string
658
+ *
659
+ * @function encryptProperty
660
+ * @param {String} property - the property to encrypt
661
+ * @param {String} technique - the technique to use to encrypt
662
+ *
663
+ * @param {Callback} callback - a callback function to return the result
664
+ * Encrypted String or the Error
665
+ */
666
+ encryptProperty(property, technique, callback) {
667
+ const origin = `${this.id}-adapterBase-encryptProperty`;
668
+ log.trace(origin);
669
+
670
+ // Make the call -
671
+ // encryptProperty(property, technique, callback)
672
+ return this.requestHandlerInst.encryptProperty(property, technique, callback);
673
+ }
674
+
675
+ /**
676
+ * @summary take the entities and add them to the cache
677
+ *
678
+ * @function addEntityCache
679
+ * @param {String} entityType - the type of the entities
680
+ * @param {Array} data - the list of entities
681
+ * @param {String} key - unique key for the entities
682
+ *
683
+ * @param {Callback} callback - An array of whether the adapter can has the
684
+ * desired capability or an error
685
+ */
686
+ addEntityCache(entityType, entities, key, callback) {
687
+ const meth = 'adapterBase-addEntityCache';
688
+ const origin = `${this.id}-${meth}`;
689
+ log.trace(origin);
690
+
691
+ // list containing the items to add to the cache
692
+ const entityIds = [];
693
+
694
+ if (entities && Object.hasOwnProperty.call(entities, 'response')
695
+ && Array.isArray(entities.response)) {
696
+ for (let e = 0; e < entities.response.length; e += 1) {
697
+ entityIds.push(entities.response[e][key]);
698
+ }
699
+ }
700
+
701
+ // add the entities to the cache
702
+ return this.requestHandlerInst.addEntityCache(entityType, entityIds, (loaded, error) => {
703
+ if (error) {
704
+ return callback(null, error);
705
+ }
706
+ if (!loaded) {
707
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Entity Cache Not Loading', [entityType], null, null, null);
708
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
709
+ return callback(null, errorObj);
710
+ }
711
+
712
+ return callback(loaded);
713
+ });
714
+ }
715
+
716
+ /**
717
+ * @summary sees if the entity is in the entity list or not
718
+ *
719
+ * @function entityInList
720
+ * @param {String/Array} entityId - the specific entity we are looking for
721
+ * @param {Array} data - the list of entities
722
+ *
723
+ * @param {Callback} callback - An array of whether the adapter can has the
724
+ * desired capability or an error
725
+ */
726
+ entityInList(entityId, data) {
727
+ const origin = `${this.id}-adapterBase-entityInList`;
728
+ log.trace(origin);
729
+
730
+ // need to check on the entities that were passed in
731
+ if (Array.isArray(entityId)) {
732
+ const resEntity = [];
733
+
734
+ for (let e = 0; e < entityId.length; e += 1) {
735
+ if (data.includes(entityId[e])) {
736
+ resEntity.push(true);
737
+ } else {
738
+ resEntity.push(false);
739
+ }
740
+ }
741
+
742
+ return resEntity;
743
+ }
744
+
745
+ // does the entity list include the specific entity
746
+ return [data.includes(entityId)];
747
+ }
748
+
749
+ /**
750
+ * @summary runs troubleshoot scripts for adapter
751
+ *
752
+ * @function troubleshoot
753
+ * @param {Object} props - the connection, healthcheck and authentication properties
754
+ * @param {boolean} persistFlag - whether the adapter properties should be updated
755
+ * @param {Adapter} adapter - adapter instance to troubleshoot
756
+ * @param {Callback} callback - callback function to return troubleshoot results
757
+ */
758
+ async troubleshoot(props, persistFlag, adapter, callback) {
759
+ try {
760
+ const result = await troubleshootingAdapter.troubleshoot(props, false, persistFlag, adapter);
761
+ if (result.healthCheck && result.connectivity.failCount === 0 && result.basicGet.failCount === 0) {
762
+ return callback(result);
763
+ }
764
+ return callback(null, result);
765
+ } catch (error) {
766
+ return callback(null, error);
767
+ }
768
+ }
769
+
770
+ /**
771
+ * @summary runs healthcheck script for adapter
772
+ *
773
+ * @function runHealthcheck
774
+ * @param {Adapter} adapter - adapter instance to troubleshoot
775
+ * @param {Callback} callback - callback function to return healthcheck status
776
+ */
777
+ async runHealthcheck(adapter, callback) {
778
+ try {
779
+ const result = await tbUtils.healthCheck(adapter);
780
+ if (result) {
781
+ return callback(result);
782
+ }
783
+ return callback(null, result);
784
+ } catch (error) {
785
+ return callback(null, error);
786
+ }
787
+ }
788
+
789
+ /**
790
+ * @summary runs connectivity check script for adapter
791
+ *
792
+ * @function runConnectivity
793
+ * @param {Adapter} adapter - adapter instance to troubleshoot
794
+ * @param {Callback} callback - callback function to return connectivity status
795
+ */
796
+ async runConnectivity(callback) {
797
+ try {
798
+ const { serviceItem } = await troubleshootingAdapter.getAdapterConfig();
799
+ const { host } = serviceItem.properties.properties;
800
+ const result = tbUtils.runConnectivity(host, false);
801
+ if (result.failCount > 0) {
802
+ return callback(null, result);
803
+ }
804
+ return callback(result);
805
+ } catch (error) {
806
+ return callback(null, error);
807
+ }
808
+ }
809
+
810
+ /**
811
+ * @summary runs basicGet script for adapter
812
+ *
813
+ * @function runBasicGet
814
+ * @param {Callback} callback - callback function to return basicGet result
815
+ */
816
+ runBasicGet(callback) {
817
+ try {
818
+ const result = tbUtils.runBasicGet(false);
819
+ if (result.failCount > 0) {
820
+ return callback(null, result);
821
+ }
822
+ return callback(result);
823
+ } catch (error) {
824
+ return callback(null, error);
825
+ }
826
+ }
827
+
828
+ /**
829
+ * @summary prepare results for verify capability so they are true/false
830
+ *
831
+ * @function capabilityResults
832
+ * @param {Array} results - the results from the capability check
833
+ *
834
+ * @param {Callback} callback - An array of whether the adapter can has the
835
+ * desired capability or an error
836
+ */
837
+ capabilityResults(results, callback) {
838
+ const meth = 'adapterBase-capabilityResults';
839
+ const origin = `${this.id}-${meth}`;
840
+ log.trace(origin);
841
+ let locResults = results;
842
+
843
+ if (locResults && locResults[0] === 'needupdate') {
844
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Entity Cache Not Loading', ['unknown'], null, null, null);
845
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
846
+ this.repeatCacheCount += 1;
847
+ return callback(null, errorObj);
848
+ }
849
+
850
+ // if an error occured, return the error
851
+ if (locResults && locResults[0] === 'error') {
852
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Error Verifying Entity Cache', null, null, null, null);
853
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
854
+ return callback(null, errorObj);
855
+ }
856
+
857
+ // go through the response and change to true/false
858
+ if (locResults) {
859
+ // if not an array, just convert the return
860
+ if (!Array.isArray(locResults)) {
861
+ if (locResults === 'found') {
862
+ locResults = [true];
863
+ } else {
864
+ locResults = [false];
865
+ }
866
+ } else {
867
+ const temp = [];
868
+
869
+ // go through each element in the array to convert
870
+ for (let r = 0; r < locResults.length; r += 1) {
871
+ if (locResults[r] === 'found') {
872
+ temp.push(true);
873
+ } else {
874
+ temp.push(false);
875
+ }
876
+ }
877
+ locResults = temp;
878
+ }
879
+ }
880
+
881
+ // return the results
882
+ return callback(locResults);
883
+ }
884
+
885
+ /**
886
+ * @summary Provides a way for the adapter to tell north bound integrations
887
+ * all of the capabilities for the current adapter
888
+ *
889
+ * @function getAllCapabilities
890
+ *
891
+ * @return {Array} - containing the entities and the actions available on each entity
892
+ */
893
+ getAllCapabilities() {
894
+ const origin = `${this.id}-adapterBase-getAllCapabilities`;
895
+ log.trace(origin);
896
+
897
+ // validate the capabilities for the adapter
898
+ try {
899
+ return this.requestHandlerInst.getAllCapabilities();
900
+ } catch (e) {
901
+ return [];
902
+ }
903
+ }
904
+ }
905
+
906
+ module.exports = AdapterBase;