@itentialopensource/adapter-meraki 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. package/.eslintignore +1 -0
  2. package/.eslintrc.js +12 -12
  3. package/CHANGELOG.md +32 -0
  4. package/README.md +270 -68
  5. package/adapter.js +2786 -24
  6. package/adapterBase.js +544 -17
  7. package/entities/.generic/action.json +109 -0
  8. package/entities/.generic/schema.json +23 -0
  9. package/entities/.system/action.json +1 -1
  10. package/entities/CameraQualityRetentionProfiles/action.json +3 -0
  11. package/entities/ConnectivityMonitoringDestinations/action.json +1 -0
  12. package/entities/DashboardBrandingPolicies/action.json +4 -0
  13. package/entities/Floorplans/action.json +3 -0
  14. package/entities/Licenses/action.json +5 -0
  15. package/entities/LinkAggregations/action.json +3 -0
  16. package/entities/MGConnectivityMonitoringDestinations/action.json +1 -0
  17. package/entities/MGDHCPSettings/action.json +1 -0
  18. package/entities/MGLANSettings/action.json +1 -0
  19. package/entities/MGPortforwardingRules/action.json +1 -0
  20. package/entities/MGSubnetPoolSettings/action.json +1 -0
  21. package/entities/MGUplinkSettings/action.json +1 -0
  22. package/entities/MXVLANPorts/action.json +1 -0
  23. package/entities/MXWarmSpareSettings/action.json +2 -0
  24. package/entities/NetFlowSettings/action.json +1 -0
  25. package/entities/Switch settings/action.json +9 -0
  26. package/entities/SwitchACLs/action.json +1 -0
  27. package/entities/SwitchPortsSchedules/action.json +3 -0
  28. package/entities/TrafficAnalysisSettings/action.json +1 -0
  29. package/entities/WirelessSettings/action.json +1 -0
  30. package/error.json +6 -0
  31. package/package.json +45 -23
  32. package/pronghorn.json +586 -16
  33. package/propertiesSchema.json +84 -11
  34. package/refs?service=git-upload-pack +0 -0
  35. package/report/meraki-newcalls-OpenApi3Json.json +5460 -0
  36. package/report/updateReport1594225126093.json +95 -0
  37. package/report/updateReport1615384306128.json +95 -0
  38. package/report/updateReport1642739939352.json +95 -0
  39. package/sampleProperties.json +20 -5
  40. package/test/integration/adapterTestBasicGet.js +85 -0
  41. package/test/integration/adapterTestConnectivity.js +93 -0
  42. package/test/integration/adapterTestIntegration.js +30 -11
  43. package/test/unit/adapterBaseTestUnit.js +944 -0
  44. package/test/unit/adapterTestUnit.js +638 -12
  45. package/utils/addAuth.js +94 -0
  46. package/utils/artifactize.js +9 -14
  47. package/utils/basicGet.js +50 -0
  48. package/utils/checkMigrate.js +63 -0
  49. package/utils/entitiesToDB.js +224 -0
  50. package/utils/findPath.js +74 -0
  51. package/utils/modify.js +154 -0
  52. package/utils/packModificationScript.js +1 -1
  53. package/utils/patches2bundledDeps.js +90 -0
  54. package/utils/pre-commit.sh +1 -1
  55. package/utils/removeHooks.js +20 -0
  56. package/utils/tbScript.js +169 -0
  57. package/utils/tbUtils.js +451 -0
  58. package/utils/troubleshootingAdapter.js +190 -0
  59. package/gl-code-quality-report.json +0 -1
package/adapterBase.js CHANGED
@@ -6,11 +6,14 @@
6
6
  /* eslint import/no-dynamic-require: warn */
7
7
  /* eslint no-loop-func: warn */
8
8
  /* eslint no-cond-assign: warn */
9
+ /* eslint global-require: warn */
10
+ /* eslint no-unused-vars: warn */
9
11
 
10
12
  /* Required libraries. */
11
13
  const fs = require('fs-extra');
12
14
  const path = require('path');
13
15
  const EventEmitterCl = require('events').EventEmitter;
16
+ const { execSync } = require('child_process');
14
17
 
15
18
  /* The schema validator */
16
19
  const AjvCl = require('ajv');
@@ -19,6 +22,127 @@ const AjvCl = require('ajv');
19
22
  const PropUtilCl = require('@itentialopensource/adapter-utils').PropertyUtility;
20
23
  const RequestHandlerCl = require('@itentialopensource/adapter-utils').RequestHandler;
21
24
 
25
+ const entitiesToDB = require(path.join(__dirname, 'utils/entitiesToDB'));
26
+ const troubleshootingAdapter = require(path.join(__dirname, 'utils/troubleshootingAdapter'));
27
+ const tbUtils = require(path.join(__dirname, 'utils/tbUtils'));
28
+
29
+ let propUtil = null;
30
+
31
+ /*
32
+ * INTERNAL FUNCTION: force fail the adapter - generally done to cause restart
33
+ */
34
+ function forceFail(packChg) {
35
+ if (packChg !== undefined && packChg !== null && packChg === true) {
36
+ execSync(`rm -rf ${__dirname}/node modules`, { encoding: 'utf-8' });
37
+ execSync(`rm -rf ${__dirname}/package-lock.json`, { encoding: 'utf-8' });
38
+ execSync('npm install', { encoding: 'utf-8' });
39
+ }
40
+ log.error('NEED TO RESTART ADAPTER - FORCE FAIL');
41
+ const errorObj = {
42
+ origin: 'adapter-forceFail',
43
+ type: 'Force Fail so adapter will restart',
44
+ vars: []
45
+ };
46
+ setTimeout(() => {
47
+ throw new Error(JSON.stringify(errorObj));
48
+ }, 1000);
49
+ }
50
+
51
+ /*
52
+ * INTERNAL FUNCTION: update the action.json
53
+ */
54
+ function updateAction(entityPath, action, changes) {
55
+ // if the action file does not exist - error
56
+ const actionFile = path.join(entityPath, '/action.json');
57
+ if (!fs.existsSync(actionFile)) {
58
+ return 'Missing Action File';
59
+ }
60
+
61
+ // read in the file as a json object
62
+ const ajson = require(path.resolve(entityPath, 'action.json'));
63
+ let chgAct = {};
64
+
65
+ // get the action we need to change
66
+ for (let a = 0; a < ajson.actions.length; a += 1) {
67
+ if (ajson.actions[a].name === action) {
68
+ chgAct = ajson.actions[a];
69
+ break;
70
+ }
71
+ }
72
+ // merge the changes into the desired action
73
+ chgAct = propUtil.mergeProperties(changes, chgAct);
74
+
75
+ fs.writeFileSync(actionFile, JSON.stringify(ajson, null, 2));
76
+ return null;
77
+ }
78
+
79
+ /*
80
+ * INTERNAL FUNCTION: update the schema file
81
+ */
82
+ function updateSchema(entityPath, configFile, changes) {
83
+ // if the schema file does not exist - error
84
+ const schemaFile = path.join(entityPath, `/${configFile}`);
85
+ if (!fs.existsSync(schemaFile)) {
86
+ return 'Missing Schema File';
87
+ }
88
+
89
+ // read in the file as a json object
90
+ let schema = require(path.resolve(entityPath, configFile));
91
+
92
+ // merge the changes into the schema file
93
+ schema = propUtil.mergeProperties(changes, schema);
94
+
95
+ fs.writeFileSync(schemaFile, JSON.stringify(schema, null, 2));
96
+ return null;
97
+ }
98
+
99
+ /*
100
+ * INTERNAL FUNCTION: update the mock data file
101
+ */
102
+ function updateMock(mockPath, configFile, changes) {
103
+ // if the mock file does not exist - create it
104
+ const mockFile = path.join(mockPath, `/${configFile}`);
105
+ if (!fs.existsSync(mockFile)) {
106
+ const newMock = {};
107
+ fs.writeFileSync(mockFile, JSON.stringify(newMock, null, 2));
108
+ }
109
+
110
+ // read in the file as a json object
111
+ let mock = require(path.resolve(mockPath, configFile));
112
+
113
+ // merge the changes into the mock file
114
+ mock = propUtil.mergeProperties(changes, mock);
115
+
116
+ fs.writeFileSync(mockFile, JSON.stringify(mock, null, 2));
117
+ return null;
118
+ }
119
+
120
+ /*
121
+ * INTERNAL FUNCTION: update the package dependencies
122
+ */
123
+ function updatePackage(changes) {
124
+ // if the schema file does not exist - error
125
+ const packFile = path.join(__dirname, '/package.json');
126
+ if (!fs.existsSync(packFile)) {
127
+ return 'Missing Pacakge File';
128
+ }
129
+
130
+ // read in the file as a json object
131
+ const pack = require(path.resolve(__dirname, 'package.json'));
132
+
133
+ // only certain changes are allowed
134
+ if (changes.dependencies) {
135
+ const keys = Object.keys(changes.dependencies);
136
+
137
+ for (let k = 0; k < keys.length; k += 1) {
138
+ pack.dependencies[keys[k]] = changes.dependencies[keys[k]];
139
+ }
140
+ }
141
+
142
+ fs.writeFileSync(packFile, JSON.stringify(pack, null, 2));
143
+ return null;
144
+ }
145
+
22
146
  /* GENERAL ADAPTER FUNCTIONS THESE SHOULD NOT BE DIRECTLY MODIFIED */
23
147
  /* IF YOU NEED MODIFICATIONS, REDEFINE THEM IN adapter.js!!! */
24
148
  class AdapterBase extends EventEmitterCl {
@@ -34,9 +158,12 @@ class AdapterBase extends EventEmitterCl {
34
158
  // Capture the adapter id
35
159
  this.id = prongid;
36
160
  this.propUtilInst = new PropUtilCl(prongid, __dirname);
37
-
161
+ propUtil = this.propUtilInst;
162
+ this.initProps = properties;
38
163
  this.alive = false;
39
164
  this.healthy = false;
165
+ this.suspended = false;
166
+ this.suspendMode = 'pause';
40
167
  this.caching = false;
41
168
  this.repeatCacheCount = 0;
42
169
  this.allowFailover = 'AD.300';
@@ -54,7 +181,6 @@ class AdapterBase extends EventEmitterCl {
54
181
  }
55
182
  }
56
183
 
57
-
58
184
  /**
59
185
  * @callback healthCallback
60
186
  * @param {Object} result - the result of the get request (contains an id and a status)
@@ -80,7 +206,6 @@ class AdapterBase extends EventEmitterCl {
80
206
  * @param {String} error - any error that occured
81
207
  */
82
208
 
83
-
84
209
  /**
85
210
  * refreshProperties is used to set up all of the properties for the connector.
86
211
  * It allows properties to be changed later by simply calling refreshProperties rather
@@ -110,14 +235,20 @@ class AdapterBase extends EventEmitterCl {
110
235
 
111
236
  // if invalid properties throw an error
112
237
  if (!result) {
113
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Invalid Properties', [JSON.stringify(validate.errors)], null, null, null);
114
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
115
- throw new Error(JSON.stringify(errorObj));
238
+ if (this.requestHandlerInst) {
239
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Invalid Properties', [JSON.stringify(validate.errors)], null, null, null);
240
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
241
+ throw new Error(JSON.stringify(errorObj));
242
+ } else {
243
+ log.error(`${origin}: ${JSON.stringify(validate.errors)}`);
244
+ throw new Error(`${origin}: ${JSON.stringify(validate.errors)}`);
245
+ }
116
246
  }
117
247
 
118
248
  // properties that this code cares about
119
249
  this.healthcheckType = this.allProps.healthcheck.type;
120
250
  this.healthcheckInterval = this.allProps.healthcheck.frequency;
251
+ this.healthcheckQuery = this.allProps.healthcheck.query_object;
121
252
 
122
253
  // set the failover codes from properties
123
254
  if (this.allProps.request.failover_codes) {
@@ -146,6 +277,129 @@ class AdapterBase extends EventEmitterCl {
146
277
  }
147
278
  }
148
279
 
280
+ /**
281
+ * updateAdapterConfiguration is used to update any of the adapter configuration files. This
282
+ * allows customers to make changes to adapter configuration without having to be on the
283
+ * file system.
284
+ *
285
+ * @function updateAdapterConfiguration
286
+ * @param {string} configFile - the name of the file being updated (required)
287
+ * @param {Object} changes - an object containing all of the changes = formatted like the configuration file (required)
288
+ * @param {string} entity - the entity to be changed, if an action, schema or mock data file (optional)
289
+ * @param {string} type - the type of entity file to change, (action, schema, mock) (optional)
290
+ * @param {string} action - the action to be changed, if an action, schema or mock data file (optional)
291
+ * @param {Callback} callback - The results of the call
292
+ */
293
+ updateAdapterConfiguration(configFile, changes, entity, type, action, callback) {
294
+ const meth = 'adapterBase-updateAdapterConfiguration';
295
+ const origin = `${this.id}-${meth}`;
296
+ log.trace(origin);
297
+
298
+ // verify the parameters are valid
299
+ if (changes === undefined || changes === null || typeof changes !== 'object'
300
+ || Object.keys(changes).length === 0) {
301
+ const result = {
302
+ response: 'No configuration updates to make'
303
+ };
304
+ log.info(result.response);
305
+ return callback(result, null);
306
+ }
307
+ if (configFile === undefined || configFile === null || configFile === '') {
308
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['configFile'], null, null, null);
309
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
310
+ return callback(null, errorObj);
311
+ }
312
+
313
+ // take action based on configFile being changed
314
+ if (configFile === 'package.json') {
315
+ const pres = updatePackage(changes);
316
+ if (pres) {
317
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: ${pres}`, [], null, null, null);
318
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
319
+ return callback(null, errorObj);
320
+ }
321
+ const result = {
322
+ response: 'Package updates completed - restarting adapter'
323
+ };
324
+ log.info(result.response);
325
+ forceFail(true);
326
+ return callback(result, null);
327
+ }
328
+ if (entity === undefined || entity === null || entity === '') {
329
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Unsupported Configuration Change or Missing Entity', [], null, null, null);
330
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
331
+ return callback(null, errorObj);
332
+ }
333
+
334
+ // this means we are changing an entity file so type is required
335
+ if (type === undefined || type === null || type === '') {
336
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['type'], null, null, null);
337
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
338
+ return callback(null, errorObj);
339
+ }
340
+
341
+ // if the entity does not exist - error
342
+ const epath = `${__dirname}/entities/${entity}`;
343
+ if (!fs.existsSync(epath)) {
344
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: Invalid Entity - ${entity}`, [], null, null, null);
345
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
346
+ return callback(null, errorObj);
347
+ }
348
+
349
+ // take action based on type of file being changed
350
+ if (type === 'action') {
351
+ // BACKUP???
352
+ const ares = updateAction(epath, action, changes);
353
+ if (ares) {
354
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: ${ares}`, [], null, null, null);
355
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
356
+ return callback(null, errorObj);
357
+ }
358
+ // AJV CHECK???
359
+ // RESTORE IF NEEDED???
360
+ const result = {
361
+ response: `Action updates completed to entity: ${entity} - ${action}`
362
+ };
363
+ log.info(result.response);
364
+ return callback(result, null);
365
+ }
366
+ if (type === 'schema') {
367
+ const sres = updateSchema(epath, configFile, changes);
368
+ if (sres) {
369
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: ${sres}`, [], null, null, null);
370
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
371
+ return callback(null, errorObj);
372
+ }
373
+ const result = {
374
+ response: `Schema updates completed to entity: ${entity} - ${configFile}`
375
+ };
376
+ log.info(result.response);
377
+ return callback(result, null);
378
+ }
379
+ if (type === 'mock') {
380
+ // if the mock directory does not exist - error
381
+ const mpath = `${__dirname}/entities/${entity}/mockdatafiles`;
382
+ if (!fs.existsSync(mpath)) {
383
+ fs.mkdirSync(mpath);
384
+ }
385
+
386
+ const mres = updateMock(mpath, configFile, changes);
387
+ if (mres) {
388
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: ${mres}`, [], null, null, null);
389
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
390
+ return callback(null, errorObj);
391
+ }
392
+ const result = {
393
+ response: `Mock data updates completed to entity: ${entity} - ${configFile}`
394
+ };
395
+ log.info(result.response);
396
+ return callback(result, null);
397
+ }
398
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: Unsupported Type - ${type}`, [], null, null, null);
399
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
400
+ return callback(null, errorObj);
401
+ }
402
+
149
403
  /**
150
404
  * @summary Connect function is used during Pronghorn startup to provide instantiation feedback.
151
405
  *
@@ -162,9 +416,11 @@ class AdapterBase extends EventEmitterCl {
162
416
  // if there is no healthcheck just change the emit to ONLINE
163
417
  // We do not recommend no healthcheck!!!
164
418
  if (this.healthcheckType === 'none') {
165
- // validate all of the action files - normally done in healthcheck
166
- this.emit('ONLINE', { id: this.id });
167
- this.healthy = true;
419
+ log.error(`${origin}: Waiting 1 Seconds to emit Online`);
420
+ setTimeout(() => {
421
+ this.emit('ONLINE', { id: this.id });
422
+ this.healthy = true;
423
+ }, 1000);
168
424
  }
169
425
 
170
426
  // is the healthcheck only suppose to run on startup
@@ -197,6 +453,20 @@ class AdapterBase extends EventEmitterCl {
197
453
  const origin = `${this.id}-adapterBase-healthCheck`;
198
454
  log.trace(origin);
199
455
 
456
+ // if there is healthcheck query_object property, it needs to be added to the adapter
457
+ let myRequest = reqObj;
458
+ if (this.healthcheckQuery && Object.keys(this.healthcheckQuery).length > 0) {
459
+ if (myRequest && myRequest.uriQuery) {
460
+ myRequest.uriQuery = { ...myRequest.uriQuery, ...this.healthcheckQuery };
461
+ } else if (myRequest) {
462
+ myRequest.uriQuery = this.healthcheckQuery;
463
+ } else {
464
+ myRequest = {
465
+ uriQuery: this.healthcheckQuery
466
+ };
467
+ }
468
+ }
469
+
200
470
  // call to the healthcheck in connector
201
471
  return this.requestHandlerInst.identifyHealthcheck(reqObj, (res, error) => {
202
472
  // unhealthy
@@ -230,6 +500,68 @@ class AdapterBase extends EventEmitterCl {
230
500
  });
231
501
  }
232
502
 
503
+ /**
504
+ * @summary Suspends the adapter
505
+ * @param {Callback} callback - The adapater suspension status
506
+ * @function suspend
507
+ */
508
+ suspend(mode, callback) {
509
+ const origin = `${this.id}-adapterBase-suspend`;
510
+ if (this.suspended) {
511
+ throw new Error(`${origin}: Adapter is already suspended`);
512
+ }
513
+ try {
514
+ this.suspended = true;
515
+ this.suspendMode = mode;
516
+ if (this.suspendMode === 'pause') {
517
+ const props = JSON.parse(JSON.stringify(this.initProps));
518
+ // To suspend adapter, enable throttling and set concurrent max to 0
519
+ props.throttle.throttle_enabled = true;
520
+ props.throttle.concurrent_max = 0;
521
+ this.refreshProperties(props);
522
+ }
523
+ return callback({ suspended: true });
524
+ } catch (error) {
525
+ return callback(null, error);
526
+ }
527
+ }
528
+
529
+ /**
530
+ * @summary Unsuspends the adapter
531
+ * @param {Callback} callback - The adapater suspension status
532
+ *
533
+ * @function unsuspend
534
+ */
535
+ unsuspend(callback) {
536
+ const origin = `${this.id}-adapterBase-unsuspend`;
537
+ if (!this.suspended) {
538
+ throw new Error(`${origin}: Adapter is not suspended`);
539
+ }
540
+ if (this.suspendMode === 'pause') {
541
+ const props = JSON.parse(JSON.stringify(this.initProps));
542
+ // To unsuspend adapter, keep throttling enabled and begin processing queued requests in order
543
+ props.throttle.throttle_enabled = true;
544
+ props.throttle.concurrent_max = 1;
545
+ this.refreshProperties(props);
546
+ setTimeout(() => {
547
+ this.getQueue((q, error) => {
548
+ // console.log("Items in queue: " + String(q.length))
549
+ if (q.length === 0) {
550
+ // if queue is empty, return to initial properties state
551
+ this.refreshProperties(this.initProps);
552
+ this.suspended = false;
553
+ return callback({ suspended: false });
554
+ }
555
+ // recursive call to check queue again every second
556
+ return this.unsuspend(callback);
557
+ });
558
+ }, 1000);
559
+ } else {
560
+ this.suspended = false;
561
+ callback({ suspend: false });
562
+ }
563
+ }
564
+
233
565
  /**
234
566
  * getAllFunctions is used to get all of the exposed function in the adapter
235
567
  *
@@ -242,7 +574,7 @@ class AdapterBase extends EventEmitterCl {
242
574
  // find the functions in this class
243
575
  do {
244
576
  const l = Object.getOwnPropertyNames(obj)
245
- .concat(Object.getOwnPropertySymbols(obj).map(s => s.toString()))
577
+ .concat(Object.getOwnPropertySymbols(obj).map((s) => s.toString()))
246
578
  .sort()
247
579
  .filter((p, i, arr) => typeof obj[p] === 'function' && p !== 'constructor' && (i === 0 || p !== arr[i - 1]) && myfunctions.indexOf(p) === -1);
248
580
  myfunctions = myfunctions.concat(l);
@@ -256,10 +588,11 @@ class AdapterBase extends EventEmitterCl {
256
588
 
257
589
  /**
258
590
  * getWorkflowFunctions is used to get all of the workflow function in the adapter
591
+ * @param {array} ignoreThese - additional methods to ignore (optional)
259
592
  *
260
- * @function getAllFunctions
593
+ * @function getWorkflowFunctions
261
594
  */
262
- getWorkflowFunctions() {
595
+ getWorkflowFunctions(ignoreThese) {
263
596
  const myfunctions = this.getAllFunctions();
264
597
  const wffunctions = [];
265
598
 
@@ -269,9 +602,20 @@ class AdapterBase extends EventEmitterCl {
269
602
  // got to the second tier (adapterBase)
270
603
  break;
271
604
  }
272
- if (myfunctions[m] !== 'hasEntity' && myfunctions[m] !== 'verifyCapability'
273
- && myfunctions[m] !== 'updateEntityCache') {
274
- wffunctions.push(myfunctions[m]);
605
+ if (myfunctions[m] !== 'hasEntity' && myfunctions[m] !== 'verifyCapability' && myfunctions[m] !== 'updateEntityCache'
606
+ && myfunctions[m] !== 'healthCheck' && myfunctions[m] !== 'getWorkflowFunctions'
607
+ && !(myfunctions[m].endsWith('Emit') || myfunctions[m].match(/Emit__v[0-9]+/))) {
608
+ let found = false;
609
+ if (ignoreThese && Array.isArray(ignoreThese)) {
610
+ for (let i = 0; i < ignoreThese.length; i += 1) {
611
+ if (myfunctions[m].toUpperCase() === ignoreThese[i].toUpperCase()) {
612
+ found = true;
613
+ }
614
+ }
615
+ }
616
+ if (!found) {
617
+ wffunctions.push(myfunctions[m]);
618
+ }
275
619
  }
276
620
  }
277
621
 
@@ -295,6 +639,89 @@ class AdapterBase extends EventEmitterCl {
295
639
  }
296
640
  }
297
641
 
642
+ /**
643
+ * See if the API path provided is found in this adapter
644
+ *
645
+ * @function findPath
646
+ * @param {string} apiPath - the api path to check on
647
+ * @param {Callback} callback - The results of the call
648
+ */
649
+ findPath(apiPath, callback) {
650
+ const result = {
651
+ apiPath
652
+ };
653
+
654
+ // verify the path was provided
655
+ if (!apiPath) {
656
+ log.error('NO API PATH PROVIDED!');
657
+ result.found = false;
658
+ result.message = 'NO PATH PROVIDED!';
659
+ return callback(null, result);
660
+ }
661
+
662
+ // make sure the entities directory exists
663
+ const entitydir = path.join(__dirname, 'entities');
664
+ if (!fs.statSync(entitydir).isDirectory()) {
665
+ log.error('Could not find the entities directory');
666
+ result.found = false;
667
+ result.message = 'Could not find the entities directory';
668
+ return callback(null, result);
669
+ }
670
+
671
+ const entities = fs.readdirSync(entitydir);
672
+ const fitems = [];
673
+
674
+ // need to go through each entity in the entities directory
675
+ for (let e = 0; e < entities.length; e += 1) {
676
+ // make sure the entity is a directory - do not care about extra files
677
+ // only entities (dir)
678
+ if (fs.statSync(`${entitydir}/${entities[e]}`).isDirectory()) {
679
+ // see if the action file exists in the entity
680
+ if (fs.existsSync(`${entitydir}/${entities[e]}/action.json`)) {
681
+ // Read the entity actions from the file system
682
+ const actions = require(`${entitydir}/${entities[e]}/action.json`);
683
+
684
+ // go through all of the actions set the appropriate info in the newActions
685
+ for (let a = 0; a < actions.actions.length; a += 1) {
686
+ if (actions.actions[a].entitypath.indexOf(apiPath) >= 0) {
687
+ log.info(` Found - entity: ${entities[e]} action: ${actions.actions[a].name}`);
688
+ log.info(` method: ${actions.actions[a].method} path: ${actions.actions[a].entitypath}`);
689
+ const fitem = {
690
+ entity: entities[e],
691
+ action: actions.actions[a].name,
692
+ method: actions.actions[a].method,
693
+ path: actions.actions[a].entitypath
694
+ };
695
+ fitems.push(fitem);
696
+ }
697
+ }
698
+ } else {
699
+ log.error(`Could not find entities ${entities[e]} action.json file`);
700
+ result.found = false;
701
+ result.message = `Could not find entities ${entities[e]} action.json file`;
702
+ return callback(null, result);
703
+ }
704
+ } else {
705
+ log.error(`Could not find entities ${entities[e]} directory`);
706
+ result.found = false;
707
+ result.message = `Could not find entities ${entities[e]} directory`;
708
+ return callback(null, result);
709
+ }
710
+ }
711
+
712
+ if (fitems.length === 0) {
713
+ log.info('PATH NOT FOUND!');
714
+ result.found = false;
715
+ result.message = 'API PATH NOT FOUND!';
716
+ return callback(null, result);
717
+ }
718
+
719
+ result.foundIn = fitems;
720
+ result.found = true;
721
+ result.message = 'API PATH FOUND!';
722
+ return callback(result, null);
723
+ }
724
+
298
725
  /**
299
726
  * checkProperties is used to validate the adapter properties.
300
727
  *
@@ -346,6 +773,85 @@ class AdapterBase extends EventEmitterCl {
346
773
  return this.requestHandlerInst.encryptProperty(property, technique, callback);
347
774
  }
348
775
 
776
+ /**
777
+ * @summary runs troubleshoot scripts for adapter
778
+ *
779
+ * @function troubleshoot
780
+ * @param {Object} props - the connection, healthcheck and authentication properties
781
+ * @param {boolean} persistFlag - whether the adapter properties should be updated
782
+ * @param {Adapter} adapter - adapter instance to troubleshoot
783
+ * @param {Callback} callback - callback function to return troubleshoot results
784
+ */
785
+ async troubleshoot(props, persistFlag, adapter, callback) {
786
+ try {
787
+ const result = await troubleshootingAdapter.troubleshoot(props, false, persistFlag, adapter);
788
+ if (result.healthCheck && result.connectivity.failCount === 0 && result.basicGet.failCount === 0) {
789
+ return callback(result);
790
+ }
791
+ return callback(null, result);
792
+ } catch (error) {
793
+ return callback(null, error);
794
+ }
795
+ }
796
+
797
+ /**
798
+ * @summary runs healthcheck script for adapter
799
+ *
800
+ * @function runHealthcheck
801
+ * @param {Adapter} adapter - adapter instance to troubleshoot
802
+ * @param {Callback} callback - callback function to return healthcheck status
803
+ */
804
+ async runHealthcheck(adapter, callback) {
805
+ try {
806
+ const result = await tbUtils.healthCheck(adapter);
807
+ if (result) {
808
+ return callback(result);
809
+ }
810
+ return callback(null, result);
811
+ } catch (error) {
812
+ return callback(null, error);
813
+ }
814
+ }
815
+
816
+ /**
817
+ * @summary runs connectivity check script for adapter
818
+ *
819
+ * @function runConnectivity
820
+ * @param {Adapter} adapter - adapter instance to troubleshoot
821
+ * @param {Callback} callback - callback function to return connectivity status
822
+ */
823
+ async runConnectivity(callback) {
824
+ try {
825
+ const { serviceItem } = await tbUtils.getAdapterConfig();
826
+ const { host } = serviceItem.properties.properties;
827
+ const result = tbUtils.runConnectivity(host, false);
828
+ if (result.failCount > 0) {
829
+ return callback(null, result);
830
+ }
831
+ return callback(result);
832
+ } catch (error) {
833
+ return callback(null, error);
834
+ }
835
+ }
836
+
837
+ /**
838
+ * @summary runs basicGet script for adapter
839
+ *
840
+ * @function runBasicGet
841
+ * @param {Callback} callback - callback function to return basicGet result
842
+ */
843
+ runBasicGet(callback) {
844
+ try {
845
+ const result = tbUtils.runBasicGet(false);
846
+ if (result.failCount > 0) {
847
+ return callback(null, result);
848
+ }
849
+ return callback(result);
850
+ } catch (error) {
851
+ return callback(null, error);
852
+ }
853
+ }
854
+
349
855
  /**
350
856
  * @summary take the entities and add them to the cache
351
857
  *
@@ -406,7 +912,7 @@ class AdapterBase extends EventEmitterCl {
406
912
  const resEntity = [];
407
913
 
408
914
  for (let e = 0; e < entityId.length; e += 1) {
409
- if (data.includes(entityId)) {
915
+ if (data.includes(entityId[e])) {
410
916
  resEntity.push(true);
411
917
  } else {
412
918
  resEntity.push(false);
@@ -430,7 +936,7 @@ class AdapterBase extends EventEmitterCl {
430
936
  * desired capability or an error
431
937
  */
432
938
  capabilityResults(results, callback) {
433
- const meth = 'adapterBase-getQueue';
939
+ const meth = 'adapterBase-capabilityResults';
434
940
  const origin = `${this.id}-${meth}`;
435
941
  log.trace(origin);
436
942
  let locResults = results;
@@ -496,6 +1002,27 @@ class AdapterBase extends EventEmitterCl {
496
1002
  return [];
497
1003
  }
498
1004
  }
1005
+
1006
+ /**
1007
+ * @summary moves entities to mongo database
1008
+ *
1009
+ * @function moveEntitiesToDB
1010
+ *
1011
+ * @return {Callback} - containing the response from the mongo transaction
1012
+ */
1013
+ moveEntitiesToDB(callback) {
1014
+ const meth = 'adapterBase-moveEntitiesToDB';
1015
+ const origin = `${this.id}-${meth}`;
1016
+ log.trace(origin);
1017
+
1018
+ try {
1019
+ return callback(entitiesToDB.moveEntitiesToDB(__dirname, { pronghornProps: this.allProps, id: this.id }), null);
1020
+ } catch (err) {
1021
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, err);
1022
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1023
+ return callback(null, errorObj);
1024
+ }
1025
+ }
499
1026
  }
500
1027
 
501
1028
  module.exports = AdapterBase;