@itentialopensource/adapter-meraki 0.7.0 → 0.8.0

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 (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
@@ -0,0 +1,451 @@
1
+ /* @copyright Itential, LLC 2020 */
2
+
3
+ /* eslint import/no-extraneous-dependencies: warn */
4
+ /* eslint global-require: warn */
5
+ /* eslint import/no-dynamic-require: warn */
6
+
7
+ const path = require('path');
8
+ const fs = require('fs-extra');
9
+ const cp = require('child_process');
10
+
11
+ module.exports = {
12
+ SERVICE_CONFIGS_COLLECTION: 'service_configs',
13
+ IAP_PROFILES_COLLECTION: 'iap_profiles',
14
+
15
+ /**
16
+ * @summary update newConnection properties in adapter config
17
+ *
18
+ * @function updateNewConnection
19
+ * @param {Object} config - adaper configuration object required by IAP
20
+ * @param {Object} newConnection - connection related property collection from user
21
+ */
22
+ updateNewConnection: (config, newConnection) => {
23
+ const updatedConfig = JSON.parse(JSON.stringify(config));
24
+ Object.keys(newConnection).forEach((key) => {
25
+ updatedConfig.properties.properties[key] = newConnection[key];
26
+ });
27
+ return updatedConfig;
28
+ },
29
+
30
+ /**
31
+ * @summary assemble heathcheck endpoint into an URL
32
+ *
33
+ * @function getHealthCheckEndpointURL
34
+ * @param {Object} endpoint - user updated healthcheck endpoint object
35
+ * @param {Object} config - adaper configuration object required by IAP
36
+ */
37
+ getHealthCheckEndpointURL: (endpoint, config) => {
38
+ const p = config.properties.properties;
39
+ const healthCheckEndpointURL = `${p.protocol}://${p.host}${p.base_path}${p.version}${endpoint.healthCheckEndpoint}`;
40
+ console.log({ healthCheckEndpointURL });
41
+ return healthCheckEndpointURL;
42
+ },
43
+
44
+ /**
45
+ * @summary persist healthcheck endpoint when user make update
46
+ *
47
+ * @function updateHealthCheckEndpoint
48
+ * @param {Object} newHealthCheckEndpoint - user confirmed healthcheck object
49
+ * @param {Object} healthCheckEndpoint - existing healthcheck object
50
+ * @param {Object} healthcheck - ./entities/.system/action.json object
51
+ */
52
+ updateHealthCheckEndpoint: (newHealthCheckEndpoint, healthCheckEndpoint, healthcheck) => {
53
+ if (newHealthCheckEndpoint.healthCheckEndpoint !== healthCheckEndpoint.healthCheckEndpoint) {
54
+ const p = healthcheck.actions[1].entitypath;
55
+ const newEntitypath = p.slice(0, 21) + newHealthCheckEndpoint.healthCheckEndpoint + p.slice(p.length - 8);
56
+ const updatedHealthcheck = JSON.parse(JSON.stringify(healthcheck));
57
+ updatedHealthcheck.actions[1].entitypath = newEntitypath;
58
+ console.log('updating healthcheck setting');
59
+ fs.writeFileSync('./entities/.system/action.json', JSON.stringify(updatedHealthcheck, null, 2));
60
+ }
61
+ },
62
+
63
+ /**
64
+ * @summary update authentication property given new input value from user
65
+ * compare values from auth and newAuth, if there's difference
66
+ * update adapter config
67
+ * @function updateAuth
68
+ * @param {Object} newAuth - user confirmed authentication object
69
+ * @param {Object} auth - existing authentication object
70
+ * @param {Object} config - adaper configuration object required by IAP
71
+ */
72
+ updateAuth: (newAuth, auth, config) => {
73
+ const updatedConfig = JSON.parse(JSON.stringify(config));
74
+ if (Object.keys(newAuth).every((key) => newAuth[key] === auth[key])) {
75
+ return config;
76
+ }
77
+ Object.keys(newAuth).forEach((key) => {
78
+ updatedConfig.properties.properties.authentication[key] = newAuth[key];
79
+ });
80
+ console.log(updatedConfig.properties.properties.authentication);
81
+ return updatedConfig;
82
+ },
83
+
84
+ /**
85
+ * @summary add mark current auth_method with `(current)`
86
+ *
87
+ * @function getDisplayAuthOptions
88
+ * @param {String} currentAuth - current auth method in adapter config
89
+ * @param {Array} authOptions - available auth method
90
+ */
91
+ getDisplayAuthOptions: (currentAuth, authOptions) => {
92
+ const displayAuthOptions = JSON.parse(JSON.stringify(authOptions));
93
+ displayAuthOptions[authOptions.indexOf(currentAuth)] += ' (current)';
94
+ return displayAuthOptions;
95
+ },
96
+
97
+ /**
98
+ * @summary decrypt IAP properties
99
+ * code from pronghorn-core/migration_scripts/installService.js
100
+ *
101
+ * @function decryptProperties
102
+ */
103
+ decryptProperties: (props, iapDir, discovery) => {
104
+ const propertyEncryptionClassPath = path.join(iapDir, 'node_modules/@itential/pronghorn-core/core/PropertyEncryption.js');
105
+ const isEncrypted = props.pathProps.encrypted;
106
+ const PropertyEncryption = discovery.require(propertyEncryptionClassPath, isEncrypted);
107
+ const propertyEncryption = new PropertyEncryption({
108
+ algorithm: 'aes-256-ctr',
109
+ key: 'TG9uZ0Rpc3RhbmNlUnVubmVyUHJvbmdob3JuCg==',
110
+ encoding: 'utf-8'
111
+ });
112
+ return propertyEncryption.decryptProps(props);
113
+ },
114
+
115
+ /**
116
+ * @summary create connection object for verification
117
+ *
118
+ * @function getConnection
119
+ * @param {Object} props - adapter config.properties
120
+ */
121
+ getConnection: (props) => {
122
+ const connection = {
123
+ host: props.properties.host,
124
+ base_path: props.properties.base_path,
125
+ protocol: props.properties.protocol,
126
+ version: props.properties.version,
127
+ port: props.properties.port
128
+ };
129
+ return connection;
130
+ },
131
+
132
+ /**
133
+ * @summary update connection properties based on user answer
134
+ *
135
+ * @function getNewProps
136
+ * @param {Array} answers - values collected from CLI
137
+ * @param {Object} connection - connection property verified by user
138
+ */
139
+ getNewProps: (answers, connection) => {
140
+ if (answers.every((answer) => answer === '')) {
141
+ return connection;
142
+ }
143
+ const newConnection = {};
144
+ const properties = Object.keys(connection);
145
+ for (let i = 0; i < answers.length; i += 1) {
146
+ if (answers[i]) {
147
+ newConnection[properties[i]] = Number.isNaN(Number(answers[i])) ? answers[i] : Number(answers[i]);
148
+ } else {
149
+ newConnection[properties[i]] = connection[properties[i]];
150
+ }
151
+ }
152
+ return newConnection;
153
+ },
154
+
155
+ /**
156
+ * @summary extract endpoint string from healthcheck object
157
+ *
158
+ * @function getHealthCheckEndpoint
159
+ * @param {Object} healthcheck - {Object} healthcheck - ./entities/.system/action.json object
160
+ */
161
+ getHealthCheckEndpoint: (healthcheck) => {
162
+ const endpoint = healthcheck.actions[1].entitypath.slice(21,
163
+ healthcheck.actions[1].entitypath.length - 8);
164
+ return { healthCheckEndpoint: endpoint };
165
+ },
166
+
167
+ /**
168
+ * @summary Verify that the adapter is in the correct directory
169
+ * - Within IAP
170
+ * - In node_modules/@ namespace
171
+ * verify the adapter is installed under node_modules/
172
+ * and is consistent with the name property of package.json
173
+ * and the node_modules/ is in the correct path within IAP
174
+ * @param {String} dirname - current path
175
+ * @param {String} name - name property from package.json
176
+ */
177
+ verifyInstallationDir: (dirname, name) => {
178
+ const pathArray = dirname.split(path.sep);
179
+ const expectedPath = `node_modules/${name}`;
180
+ const currentPath = pathArray.slice(pathArray.length - 3, pathArray.length).join('/');
181
+ if (currentPath.trim() !== expectedPath.trim()) {
182
+ throw new Error(`adapter should be installed under ${expectedPath} but is installed under ${currentPath}`);
183
+ }
184
+
185
+ const serverFile = path.join(dirname, '../../../', 'server.js');
186
+ if (!fs.existsSync(serverFile)) {
187
+ throw new Error(`adapter should be installed under IAP/${expectedPath}`);
188
+ }
189
+ console.log(`adapter correctly installed at ${currentPath}`);
190
+ },
191
+
192
+ /**
193
+ * @summary execute command and preserve the output the same as run command in shell
194
+ *
195
+ * @function systemSync
196
+ * @param {String} cmd - Command to execute
197
+ * @param {boolean} process - Whether stdout should be processed and returned
198
+ */
199
+ systemSync: function systemSync(cmd, process) {
200
+ if (process) {
201
+ let stdout;
202
+ try {
203
+ stdout = cp.execSync(cmd).toString();
204
+ } catch (error) {
205
+ stdout = error.stdout.toString();
206
+ }
207
+ const output = this.getTestCount(stdout);
208
+ output.stdout = stdout;
209
+ return output;
210
+ }
211
+ try {
212
+ return cp.execSync(cmd, { stdio: 'inherit' });
213
+ } catch (error) {
214
+ return console.error(error.stdout);
215
+ }
216
+ },
217
+
218
+ /**
219
+ * @summary parses a string and returns the number parsed from startIndex backwards
220
+ *
221
+ * @function parseNum
222
+ * @param {String} inputStr - Any String
223
+ * @param {Number} startIndex - Index to begin parsing
224
+ */
225
+ parseNum: function parseNum(inputStr, startIndex) {
226
+ let count = '';
227
+ let currChar;
228
+ let start = startIndex;
229
+ while (currChar !== ' ') {
230
+ currChar = inputStr.charAt(start);
231
+ count = currChar + count;
232
+ start -= 1;
233
+ }
234
+ return parseInt(count, 10);
235
+ },
236
+
237
+ /**
238
+ * @summary Parses a mocha test result and returns the count of passing and failing tests
239
+ *
240
+ * @function getTestCount
241
+ * @param {String} testStr - Output from mocha test
242
+ */
243
+ getTestCount: function getTestCount(testStr) {
244
+ const passIndex = testStr.search('passing');
245
+ const failIndex = testStr.search('failing');
246
+ const passCount = passIndex >= 0 ? this.parseNum(testStr, passIndex - 2) : 0;
247
+ const failCount = failIndex >= 0 ? this.parseNum(testStr, failIndex - 2) : 0;
248
+ return { passCount, failCount };
249
+ },
250
+
251
+ /**
252
+ * @summary remove package-lock.json and node_modules directory if exists
253
+ * run npm install and print result to stdout
254
+ */
255
+ npmInstall: function npmInstall() {
256
+ fs.removeSync('../package-lock.json');
257
+ fs.removeSync('../node_modules/');
258
+ console.log('Run npm install ...');
259
+ this.systemSync('npm install');
260
+ },
261
+
262
+ /**
263
+ * @summary run lint, unit test and integration test
264
+ * print result to stdout
265
+ */
266
+ runTest: function runTest() {
267
+ this.systemSync('npm run lint:errors');
268
+ this.systemSync('npm run test:unit');
269
+ this.systemSync('npm run test:integration');
270
+ },
271
+
272
+ /**
273
+ * @summary run basicget with mocha
274
+ * @param {boolean} scriptFlag - whether the function is ran from a script
275
+ * print result to stdout
276
+ * returns mocha test results otherwise
277
+ */
278
+ runBasicGet: function runBasicGet(scriptFlag) {
279
+ const testPath = path.resolve(__dirname, '..', 'test/integration/adapterTestBasicGet.js');
280
+ return this.systemSync(`mocha ${testPath} --exit`, !scriptFlag);
281
+ },
282
+
283
+ /**
284
+ * @summary run connectivity with mocha
285
+ * @param {String} host - Host url to run healthcheck
286
+ * @param {boolean} scriptFlag - Whether the function is ran from a script
287
+ * print result to stdout if ran from script
288
+ * returns mocha test results otherwise
289
+ */
290
+ runConnectivity: function runConnectivity(host, scriptFlag) {
291
+ let testPath = 'test/integration/adapterTestConnectivity.js';
292
+ if (!scriptFlag) {
293
+ testPath = path.resolve(__dirname, '..', testPath);
294
+ }
295
+ return this.systemSync(`mocha ${testPath} --HOST=${host} --timeout 10000 --exit`, !scriptFlag);
296
+ },
297
+
298
+ /**
299
+ * @summary create Adapter property
300
+ *
301
+ * @function createAdapter
302
+ * @param {Object} pronghornProps - decrypted 'properties.json' from IAP root directory
303
+ * @param {Object} profileItem - pronghorn props saved in database
304
+ * @param {Object} adapterPronghorn - ./pronghorn.json in adapter dir
305
+ * @param {Object} sampleProperties - './sampleProperties.json' in adapter dir
306
+ */
307
+ createAdapter: function createAdapter(pronghornProps, profileItem, sampleProperties, adapterPronghorn) {
308
+ const dirname = this.getDirname();
309
+ const packagePath = `${dirname.split('node_modules')[0]}package.json`;
310
+ const info = JSON.parse(fs.readFileSync(packagePath));
311
+ const version = parseInt(info.version.split('.')[0], 10);
312
+
313
+ let adapter = {};
314
+ if (version >= 2020) {
315
+ adapter = {
316
+ isEncrypted: pronghornProps.pathProps.encrypted,
317
+ model: adapterPronghorn.id,
318
+ name: sampleProperties.id,
319
+ type: adapterPronghorn.type,
320
+ properties: sampleProperties,
321
+ loggerProps: profileItem.loggerProps
322
+ };
323
+ } else {
324
+ adapter = {
325
+ mongoProps: pronghornProps.mongoProps,
326
+ isEncrypted: pronghornProps.pathProps.encrypted,
327
+ model: adapterPronghorn.id,
328
+ name: sampleProperties.id,
329
+ type: adapterPronghorn.type,
330
+ properties: sampleProperties,
331
+ redisProps: profileItem.redisProps,
332
+ loggerProps: profileItem.loggerProps,
333
+ rabbitmq: profileItem.rabbitmq
334
+ };
335
+ adapter.mongoProps.pdb = true;
336
+ }
337
+
338
+ adapter.loggerProps.log_filename = `adapter-${adapter.name}.log`;
339
+ return adapter;
340
+ },
341
+
342
+ getPronghornProps: function getPronghornProps(iapDir) {
343
+ console.log('Retrieving properties.json file...');
344
+ const rawProps = require(path.join(iapDir, 'properties.json'));
345
+ console.log('Decrypting properties...');
346
+ const { Discovery } = require(path.join(iapDir, 'node_modules/@itential/itential-utils'));
347
+ const discovery = new Discovery();
348
+ const pronghornProps = this.decryptProperties(rawProps, iapDir, discovery);
349
+ console.log('Found properties.\n');
350
+ return pronghornProps;
351
+ },
352
+
353
+ // get database connection and existing adapter config
354
+ getAdapterConfig: async function getAdapterConfig() {
355
+ const newDirname = this.getDirname();
356
+ let iapDir;
357
+ if (this.withinIAP(newDirname)) { // when this script is called from IAP
358
+ iapDir = newDirname;
359
+ } else {
360
+ iapDir = path.join(this.getDirname(), 'utils', '../../../../');
361
+ }
362
+ const pronghornProps = this.getPronghornProps(iapDir);
363
+ console.log('Connecting to Database...');
364
+ const database = await this.connect(iapDir, pronghornProps);
365
+ console.log('Connection established.');
366
+ const { name } = require(path.join(__dirname, '..', 'package.json'));
367
+ const serviceItem = await database.collection(this.SERVICE_CONFIGS_COLLECTION).findOne(
368
+ { model: name }
369
+ );
370
+ return { database, serviceItem, pronghornProps };
371
+ },
372
+
373
+ /**
374
+ * @summary return async healthcheck result as a Promise
375
+ *
376
+ * @function request
377
+ * @param {Adapter} a - Adapter instance
378
+ */
379
+ request: function request(a) {
380
+ return new Promise((resolve, reject) => {
381
+ a.healthCheck(null, (data) => {
382
+ if (!data) reject(new Error('healthCheckEndpoint failed'));
383
+ resolve(data);
384
+ });
385
+ });
386
+ },
387
+
388
+ /**
389
+ * @summary deal with healthcheck response returned from adapter instace
390
+ *
391
+ * @function healthCheck
392
+ * @param {Adapter} a - Adapter instance
393
+ */
394
+ healthCheck: async function healthCheck(a) {
395
+ const result = await this.request(a)
396
+ .then((res) => {
397
+ console.log('healthCheckEndpoint OK');
398
+ return res;
399
+ })
400
+ .catch((error) => {
401
+ console.error(error.message);
402
+ return false;
403
+ });
404
+ return result;
405
+ },
406
+
407
+ /**
408
+ * @summary Check whether adapter is located within IAP node_modules
409
+ * by loading properties.json. If not, return false.
410
+ * @function withinIAP
411
+ * @param {String} iapDir root directory of IAP
412
+ */
413
+ withinIAP: (iapDir) => {
414
+ try {
415
+ const rawProps = require(path.join(iapDir, 'properties.json'));
416
+ return rawProps;
417
+ } catch (error) {
418
+ return false;
419
+ }
420
+ },
421
+
422
+ /**
423
+ * @summary Used to determine the proper dirname to return in case adapter reference is
424
+ * symlinked withink IAP
425
+ * @returns the symlinked path (using pwd command) of the adapter in case properties.json
426
+ * is not found in the original path
427
+ * @function getDirname
428
+ */
429
+ getDirname: function getDirname() {
430
+ if (this.withinIAP(path.join(__dirname, '../../../../'))) {
431
+ return __dirname;
432
+ }
433
+ const { stdout } = this.systemSync('pwd', true);
434
+ return stdout.trim();
435
+ },
436
+
437
+ /**
438
+ * @summary connect to mongodb
439
+ *
440
+ * @function connect
441
+ * @param {Object} properties - pronghornProps
442
+ */
443
+ connect: async function connect(iapDir, properties) {
444
+ // Connect to Mongo
445
+ const { MongoDBConnection } = require(path.join(iapDir, 'node_modules/@itential/database'));
446
+ const connection = new MongoDBConnection(properties.mongoProps);
447
+ const database = await connection.connect(true);
448
+ return database;
449
+ }
450
+
451
+ };
@@ -0,0 +1,190 @@
1
+ /* @copyright Itential, LLC 2020 */
2
+ /* eslint global-require: warn */
3
+ /* eslint no-console: warn */
4
+ /* eslint import/no-unresolved: warn */
5
+ /* eslint import/no-dynamic-require: warn */
6
+
7
+ const path = require('path');
8
+ const rls = require('readline-sync');
9
+ const fs = require('fs-extra');
10
+
11
+ const utils = require(path.join(__dirname, 'tbUtils'));
12
+ const basicGet = require(path.join(__dirname, 'basicGet'));
13
+ const { name } = require(path.join(__dirname, '..', 'package.json'));
14
+ const sampleProperties = require(path.join(__dirname, '..', 'sampleProperties.json'));
15
+
16
+ // send interactive questions and collection answers
17
+ // return updated connection object
18
+ const collectAnswersSync = (questions, props) => {
19
+ const answers = [];
20
+ questions.forEach((q) => {
21
+ const answer = rls.question(q);
22
+ answers.push(answer);
23
+ });
24
+ return utils.getNewProps(answers, props);
25
+ };
26
+
27
+ // change object into array of questions
28
+ const confirm = (props) => {
29
+ const questions = Object.keys(props).map((key) => `${key}: (${props[key]}) `);
30
+ return collectAnswersSync(questions, props);
31
+ };
32
+
33
+ // allow user to change auth_method
34
+ const confirmAuthOptions = (authentication) => {
35
+ const authOptions = ['basic user_password', 'request_token', 'static_token', 'no_authentication'];
36
+ const displayAuthOptions = utils.getDisplayAuthOptions(authentication.auth_method, authOptions);
37
+ const index = rls.keyInSelect(displayAuthOptions, 'Which authentication?');
38
+ if (index === -1) {
39
+ return authentication.auth_method;
40
+ }
41
+ console.log(`${authOptions[index]} is selected.`);
42
+ return authOptions[index];
43
+ };
44
+
45
+ // helper function to update auth properties
46
+ const confirmAndUpdate = (auth, config) => {
47
+ const newAuth = confirm(auth);
48
+ return utils.updateAuth(newAuth, auth, config);
49
+ };
50
+
51
+ // extract basic auth properties
52
+ const updateBasicAuth = (config, authentication) => {
53
+ const auth = {
54
+ username: authentication.username,
55
+ password: authentication.password
56
+ };
57
+ return confirmAndUpdate(auth, config);
58
+ };
59
+
60
+ // extract static auth properties
61
+ const updateStaticAuth = (config, authentication) => {
62
+ const auth = {
63
+ token: authentication.token,
64
+ auth_field: authentication.auth_field,
65
+ auth_field_format: authentication.auth_field_format
66
+ };
67
+ return confirmAndUpdate(auth, config);
68
+ };
69
+
70
+ // troubleshooting connection and healthcheck endpoint setting of adapter
71
+ const VerifyHealthCheckEndpoint = (serviceItem, props, scriptFlag) => {
72
+ // Updates connectivity params and runs connectivity
73
+ let connConfig;
74
+ const result = {};
75
+ if (scriptFlag) {
76
+ const connection = utils.getConnection(serviceItem.properties);
77
+ const newConnection = confirm(connection);
78
+ utils.runConnectivity(newConnection.host, scriptFlag);
79
+ connConfig = utils.updateNewConnection(serviceItem, newConnection);
80
+ } else {
81
+ let { properties: { properties: { host } } } = serviceItem;
82
+ if (props.connProps) {
83
+ connConfig = utils.updateNewConnection(serviceItem, props.connProps);
84
+ host = connConfig.properties.properties.host;
85
+ } else {
86
+ connConfig = serviceItem;
87
+ }
88
+ result.connectivity = utils.runConnectivity(host, scriptFlag);
89
+ }
90
+ // Updates the healthcheck endpoing
91
+ const healthcheck = require('../entities/.system/action.json');
92
+ const healthCheckEndpoint = utils.getHealthCheckEndpoint(healthcheck);
93
+ let newHealthCheckEndpoint = healthCheckEndpoint;
94
+ if (scriptFlag) {
95
+ newHealthCheckEndpoint = confirm(healthCheckEndpoint);
96
+ utils.getHealthCheckEndpointURL(newHealthCheckEndpoint, connConfig);
97
+ } else if (props.healthCheckEndpoint) {
98
+ newHealthCheckEndpoint = props.healthCheckEndpoint;
99
+ }
100
+ // Updates the authorization params
101
+ const { authentication } = connConfig.properties.properties;
102
+ let updatedAdapter = connConfig;
103
+ if (scriptFlag) {
104
+ authentication.auth_method = confirmAuthOptions(authentication);
105
+ if (authentication.auth_method === 'basic user_password') {
106
+ updatedAdapter = updateBasicAuth(connConfig, authentication);
107
+ } else if (authentication.auth_method === 'static_token') {
108
+ updatedAdapter = updateStaticAuth(connConfig, authentication);
109
+ } else if (authentication.auth_method === 'request_token') {
110
+ console.log('current troubleshooting script does not support updating request_token authentication');
111
+ }
112
+ } else if (props.auth) {
113
+ updatedAdapter = utils.updateAuth(props.auth, authentication, connConfig);
114
+ }
115
+ // Writes the new healthcheck endpoint into action.json
116
+ utils.updateHealthCheckEndpoint(newHealthCheckEndpoint, healthCheckEndpoint, healthcheck);
117
+ return { result, updatedAdapter };
118
+ };
119
+
120
+ const offline = async () => {
121
+ console.log('Start offline troubleshooting');
122
+ const { updatedAdapter } = VerifyHealthCheckEndpoint({ properties: sampleProperties }, {}, true);
123
+ const a = basicGet.getAdapterInstance(updatedAdapter);
124
+ const res = await utils.healthCheck(a);
125
+ if (!res) {
126
+ console.log('run `npm run troubleshoot` again to update settings');
127
+ process.exit(0);
128
+ }
129
+ console.log('Save changes to sampleProperties.json');
130
+ await fs.writeFile('sampleProperties.json', JSON.stringify(updatedAdapter.properties, null, 2));
131
+ if (rls.keyInYN('Test with more GET request')) {
132
+ await utils.runBasicGet(true);
133
+ }
134
+ };
135
+
136
+ const troubleshoot = async (props, scriptFlag, persistFlag, adapter) => {
137
+ // get database connection and existing adapter config
138
+ const { database, serviceItem } = await utils.getAdapterConfig();
139
+ // where troubleshoot should start
140
+ if (serviceItem) {
141
+ if (!scriptFlag || rls.keyInYN(`Start verifying the connection and authentication properties for ${name}?`)) {
142
+ const { result, updatedAdapter } = VerifyHealthCheckEndpoint(serviceItem, props, scriptFlag);
143
+ let a;
144
+ if (scriptFlag) {
145
+ a = basicGet.getAdapterInstance(updatedAdapter);
146
+ } else {
147
+ a = adapter;
148
+ }
149
+ const healthRes = await utils.healthCheck(a);
150
+ result.healthCheck = healthRes;
151
+ if (scriptFlag && !healthRes) {
152
+ console.log('run `npm run troubleshoot` again to update settings');
153
+ process.exit(0);
154
+ }
155
+
156
+ if (persistFlag && healthRes) {
157
+ const update = { $set: { properties: updatedAdapter.properties } };
158
+ await database.collection(utils.SERVICE_CONFIGS_COLLECTION).updateOne(
159
+ { model: name }, update
160
+ );
161
+ if (scriptFlag) {
162
+ console.log(`${name} updated.`);
163
+ }
164
+ }
165
+ if (scriptFlag) {
166
+ if (rls.keyInYN('Test with more GET request')) {
167
+ await utils.runBasicGet(scriptFlag);
168
+ process.exit(0);
169
+ } else {
170
+ console.log('Exiting');
171
+ process.exit(0);
172
+ }
173
+ } else {
174
+ result.basicGet = await utils.runBasicGet(scriptFlag);
175
+ return result;
176
+ }
177
+ } else {
178
+ console.log('You can update healthCheckEndpoint in ./entities/.system/action.json');
179
+ console.log('You can update authentication credientials under Settings/Services');
180
+ console.log('Exiting');
181
+ process.exit(0);
182
+ }
183
+ } else {
184
+ console.log(`${name} not installed`);
185
+ console.log('run `npm run install:adapter` to install current adapter to IAP first. Exiting...');
186
+ }
187
+ return null;
188
+ };
189
+
190
+ module.exports = { troubleshoot, offline };