@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.
- package/.eslintignore +1 -0
- package/.eslintrc.js +12 -12
- package/CHANGELOG.md +32 -0
- package/README.md +270 -68
- package/adapter.js +2786 -24
- package/adapterBase.js +544 -17
- package/entities/.generic/action.json +109 -0
- package/entities/.generic/schema.json +23 -0
- package/entities/.system/action.json +1 -1
- package/entities/CameraQualityRetentionProfiles/action.json +3 -0
- package/entities/ConnectivityMonitoringDestinations/action.json +1 -0
- package/entities/DashboardBrandingPolicies/action.json +4 -0
- package/entities/Floorplans/action.json +3 -0
- package/entities/Licenses/action.json +5 -0
- package/entities/LinkAggregations/action.json +3 -0
- package/entities/MGConnectivityMonitoringDestinations/action.json +1 -0
- package/entities/MGDHCPSettings/action.json +1 -0
- package/entities/MGLANSettings/action.json +1 -0
- package/entities/MGPortforwardingRules/action.json +1 -0
- package/entities/MGSubnetPoolSettings/action.json +1 -0
- package/entities/MGUplinkSettings/action.json +1 -0
- package/entities/MXVLANPorts/action.json +1 -0
- package/entities/MXWarmSpareSettings/action.json +2 -0
- package/entities/NetFlowSettings/action.json +1 -0
- package/entities/Switch settings/action.json +9 -0
- package/entities/SwitchACLs/action.json +1 -0
- package/entities/SwitchPortsSchedules/action.json +3 -0
- package/entities/TrafficAnalysisSettings/action.json +1 -0
- package/entities/WirelessSettings/action.json +1 -0
- package/error.json +6 -0
- package/package.json +45 -23
- package/pronghorn.json +586 -16
- package/propertiesSchema.json +84 -11
- package/refs?service=git-upload-pack +0 -0
- package/report/meraki-newcalls-OpenApi3Json.json +5460 -0
- package/report/updateReport1594225126093.json +95 -0
- package/report/updateReport1615384306128.json +95 -0
- package/report/updateReport1642739939352.json +95 -0
- package/sampleProperties.json +20 -5
- package/test/integration/adapterTestBasicGet.js +85 -0
- package/test/integration/adapterTestConnectivity.js +93 -0
- package/test/integration/adapterTestIntegration.js +30 -11
- package/test/unit/adapterBaseTestUnit.js +944 -0
- package/test/unit/adapterTestUnit.js +638 -12
- package/utils/addAuth.js +94 -0
- package/utils/artifactize.js +9 -14
- package/utils/basicGet.js +50 -0
- package/utils/checkMigrate.js +63 -0
- package/utils/entitiesToDB.js +224 -0
- package/utils/findPath.js +74 -0
- package/utils/modify.js +154 -0
- package/utils/packModificationScript.js +1 -1
- package/utils/patches2bundledDeps.js +90 -0
- package/utils/pre-commit.sh +1 -1
- package/utils/removeHooks.js +20 -0
- package/utils/tbScript.js +169 -0
- package/utils/tbUtils.js +451 -0
- package/utils/troubleshootingAdapter.js +190 -0
- 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
|
-
|
114
|
-
|
115
|
-
|
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
|
-
|
166
|
-
|
167
|
-
|
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
|
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] !== '
|
274
|
-
|
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-
|
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;
|