@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
@@ -0,0 +1,154 @@
1
+ const fs = require('fs-extra');
2
+ const Ajv = require('ajv');
3
+ const rls = require('readline-sync');
4
+ const { execSync } = require('child_process');
5
+ const { existsSync } = require('fs-extra');
6
+ const { getAdapterConfig } = require('./tbUtils');
7
+ const { name } = require('../package.json');
8
+ const propertiesSchema = require('../propertiesSchema.json');
9
+
10
+ const flags = process.argv[2];
11
+
12
+ /**
13
+ * @summary Updates database instance with new adapter properties
14
+ *
15
+ * @function updateServiceItem
16
+ */
17
+ async function updateServiceItem() {
18
+ const { database, serviceItem } = await getAdapterConfig();
19
+ const currentProps = serviceItem.properties.properties;
20
+ const ajv = new Ajv({ allErrors: true, useDefaults: true });
21
+ const validate = ajv.compile(propertiesSchema);
22
+ validate(currentProps);
23
+ console.log('Updating Properties...');
24
+ await database.collection('service_configs').updateOne(
25
+ { model: name }, { $set: serviceItem }
26
+ );
27
+ console.log('Properties Updated');
28
+ }
29
+
30
+ /**
31
+ * @summary Creates a backup zip file of current adapter
32
+ *
33
+ * @function backup
34
+ */
35
+ function backup() {
36
+ // zip all files except node_modules and package-lock
37
+ const backupCmd = 'zip -r previousVersion.zip .';
38
+ execSync(backupCmd, { encoding: 'utf-8' });
39
+ }
40
+
41
+ /**
42
+ * @summary Archives previous modifications and removes the modification package
43
+ *
44
+ * @function archiveMod
45
+ * @param {String} modType - update(UPD) or migrate(MIG)
46
+ */
47
+ function archiveMod(modType) {
48
+ if (!existsSync('./adapter_modifications/archive')) {
49
+ execSync('mkdir ./adapter_modifications/archive');
50
+ }
51
+ const zipFile = modType === 'UPD' ? 'updatePackage.zip' : 'migrationPackage.zip';
52
+ const now = new Date();
53
+ const archiveName = `${modType}-${now.toISOString()}`;
54
+ execSync(`mkdir adapter_modifications/archive/${archiveName}`);
55
+ const archiveCmd = 'mv adapter_modifications/archive .'
56
+ + ` && mv adapter_modifications/* archive/${archiveName}`
57
+ + ' && mv archive adapter_modifications'
58
+ + ` && rm ${zipFile}`;
59
+ execSync(archiveCmd, { encoding: 'utf-8' });
60
+ }
61
+
62
+ /**
63
+ * @summary Reverts modifications using backup zip file
64
+ *
65
+ * @function revertMod
66
+ */
67
+ function revertMod() {
68
+ const files = fs.readdirSync('./');
69
+ // remove all files except previousVersion
70
+ files.forEach((file) => {
71
+ if (file !== 'previousVersion.zip') {
72
+ fs.removeSync(file);
73
+ }
74
+ });
75
+ // // unzip previousVersion, reinstall dependencies and delete zipfile
76
+ execSync('unzip -o previousVersion.zip && rm -rf node_modules && rm package-lock.json && npm install');
77
+ execSync('rm previousVersion.zip');
78
+ console.log('Changes have been reverted');
79
+ }
80
+
81
+ // Main Script
82
+
83
+ // Migrate
84
+ if (flags === '-m') {
85
+ if (!fs.existsSync('migrationPackage.zip')) {
86
+ console.log('Migration Package not found. Download and place migrationPackage in the adapter root directory');
87
+ process.exit();
88
+ }
89
+ // Backup current adapter
90
+ backup();
91
+ console.log('Migrating adapter and running tests...');
92
+ const migrateCmd = 'unzip -o migrationPackage.zip'
93
+ + ' && cd adapter_modifications'
94
+ + ' && node migrate';
95
+ const migrateOutput = execSync(migrateCmd, { encoding: 'utf-8' });
96
+ console.log(migrateOutput);
97
+ if (migrateOutput.indexOf('Lint exited with code 1') >= 0
98
+ || migrateOutput.indexOf('Tests exited with code 1') >= 0) {
99
+ if (rls.keyInYN('Adapter failed tests or lint after migrating. Would you like to revert the changes?')) {
100
+ console.log('Reverting changes...');
101
+ revertMod();
102
+ process.exit();
103
+ }
104
+ console.log('Adapter Migration will continue. If you want to revert the changes, run the command npm run adapter:revert');
105
+ }
106
+ console.log('Installing new dependencies..');
107
+ const updatePackageCmd = 'rm -rf node_modules && rm package-lock.json && npm install';
108
+ const updatePackageOutput = execSync(updatePackageCmd, { encoding: 'utf-8' });
109
+ console.log(updatePackageOutput);
110
+ console.log('New dependencies installed');
111
+ console.log('Updating adapter properties..');
112
+ updateServiceItem().then(() => {
113
+ console.log('Adapter Successfully Migrated. Restart adapter in IAP to apply the changes');
114
+ archiveMod('MIG');
115
+ process.exit();
116
+ });
117
+ }
118
+
119
+ // Update
120
+ if (flags === '-u') {
121
+ if (!fs.existsSync('updatePackage.zip')) {
122
+ console.log('Update Package not found. Download and place updateAdapter.zip in the adapter root directory');
123
+ process.exit();
124
+ }
125
+ // Backup current adapter
126
+ backup();
127
+ const updateCmd = 'unzip -o updatePackage.zip'
128
+ + ' && cd adapter_modifications'
129
+ + ' && node update.js updateFiles';
130
+ execSync(updateCmd, { encoding: 'utf-8' });
131
+ const updateOutput = execSync(updateCmd, { encoding: 'utf-8' });
132
+ if (updateOutput.indexOf('Lint exited with code 1') >= 0
133
+ || updateOutput.indexOf('Tests exited with code 1') >= 0) {
134
+ if (rls.keyInYN('Adapter failed tests or lint after updating. Would you like to revert the changes?')) {
135
+ console.log('Reverting changes...');
136
+ revertMod();
137
+ process.exit();
138
+ }
139
+ console.log('Adapter Update will continue. If you want to revert the changes, run the command npm run adapter:revert');
140
+ }
141
+ console.log(updateOutput);
142
+ console.log('Adapter Successfully Updated. Restart adapter in IAP to apply the changes');
143
+ archiveMod('UPD');
144
+ process.exit();
145
+ }
146
+
147
+ // Revert
148
+ if (flags === '-r') {
149
+ if (!fs.existsSync('previousVersion.zip')) {
150
+ console.log('Previous adapter version not found. There are no changes to revert');
151
+ process.exit();
152
+ }
153
+ revertMod();
154
+ }
@@ -4,7 +4,7 @@
4
4
  const fs = require('fs-extra');
5
5
  const path = require('path');
6
6
  const { spawnSync } = require('child_process');
7
- const { createBundle } = require('./artifactize.js');
7
+ const { createBundle } = require('./artifactize');
8
8
 
9
9
  const nodeEntryPath = path.resolve('.');
10
10
  createBundle(nodeEntryPath).then((pathObj) => {
@@ -0,0 +1,90 @@
1
+ const fs = require('fs');
2
+ const semverSatisfies = require('semver/functions/satisfies');
3
+ const packageJson = require('../package.json');
4
+
5
+ try {
6
+ // pattern supplied by semver.org via https://regex101.com/r/vkijKf/1/ but removed gm from end to only match a single semver
7
+ // const semverPat = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
8
+ // pattern supplied by semver.org via https://regex101.com/r/Ly7O1x/3/ with following changes
9
+ // removed P's from before capturing group names and
10
+ // removed gm from end to only match a single semver
11
+ // const semverPat = /^(?<major>0|[1-9]\d*)\.(?<minor>0|[1-9]\d*)\.(?<patch>0|[1-9]\d*)(?:-(?<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
12
+
13
+ const patches = (fs.existsSync('./patches')) ? fs.readdirSync('./patches', { withFileTypes: true }) : [];
14
+ if (!patches.length) {
15
+ console.error('\nno patches - nothing to do\n');
16
+ process.exitCode = 1;
17
+ }
18
+
19
+ const dependencies = packageJson.dependencies || {};
20
+ if (!Object.keys(dependencies).length) {
21
+ console.error('\nno dependencies - nothing to do\n');
22
+ process.exitCode = 1;
23
+ }
24
+
25
+ let changed = false;
26
+ console.error('\nprocessing patches');
27
+ const bundledDependencies = packageJson.bundledDependencies || packageJson.bundleDependencies || [];
28
+
29
+ patches.forEach((patch) => {
30
+ if (!patch.isFile()) {
31
+ console.error(`${patch.name} skipped, is not a regular file`);
32
+ return;
33
+ }
34
+ if (!patch.name.endsWith('.patch')) {
35
+ console.error(`${patch.name} skipped, does not end with .patch`);
36
+ return;
37
+ }
38
+ const splits = patch.name.slice(0, -6).split('+');
39
+ if (splits.length > 4) {
40
+ console.error(`${patch.name} skipped, does not follow the naming convention (cannot use '+' other than to separate scope/package/semver and at most once within semver)`);
41
+ return;
42
+ }
43
+ const scope = splits[0][0] === '@' ? splits.shift() : null;
44
+ const packageName = splits.shift();
45
+ const semver = splits.join('+');
46
+ // const { groups } = semver.match(semverPat);
47
+ const file = scope ? `${scope}/${packageName}` : packageName;
48
+ if (dependencies[file] && semverSatisfies(semver, dependencies[file])) {
49
+ if (!bundledDependencies.includes(file)) {
50
+ bundledDependencies.push(file);
51
+ console.error(`added ${file} to bundledDependencies`);
52
+ changed = true;
53
+ } else {
54
+ console.error(`bundledDependencies already has ${file}`);
55
+ }
56
+ } else {
57
+ const depmsg = dependencies[file] ? `version mismatch (${dependencies[file]}) in dependencies` : 'not found in dependencies';
58
+ console.error(`patch ${patch.name} ${depmsg}`);
59
+ }
60
+ });
61
+
62
+ if (!packageJson.bundledDependencies && bundledDependencies.length) {
63
+ delete packageJson.bundleDependencies;
64
+ packageJson.bundledDependencies = bundledDependencies;
65
+ console.error('renaming bundleDependencies to bundledDependencies');
66
+ changed = true;
67
+ }
68
+ if (changed) {
69
+ fs.writeFileSync('./package.json.new', JSON.stringify(packageJson, null, 2));
70
+ console.error('wrote package.json.new');
71
+ fs.renameSync('./package.json', './package.json.old');
72
+ console.error('moved package.json to package.json.old');
73
+ fs.renameSync('./package.json.new', './package.json');
74
+ console.error('moved package.json.new to package.json');
75
+ } else {
76
+ console.error('no changes\n');
77
+ process.exitCode = 1;
78
+ }
79
+ } catch (e) {
80
+ if (e) {
81
+ // caught error, exit with status 2 to signify abject failure
82
+ console.error(`\ncaught exception - ${e}\n`);
83
+ process.exitCode = 2;
84
+ } else {
85
+ // caught false, exit with status 1 to signify nothing done
86
+ process.exitCode = 1;
87
+ }
88
+ } finally {
89
+ console.error('done\n');
90
+ }
@@ -18,7 +18,7 @@ printf "%b" "Running pre-commit hooks...\\n"
18
18
  node utils/testRunner.js -r
19
19
 
20
20
  # security audit on the code
21
- npm audit --registry=https://registry.npmjs.org
21
+ npm audit --registry=https://registry.npmjs.org --audit-level=moderate
22
22
 
23
23
  # lint the code
24
24
  npm run lint
@@ -0,0 +1,20 @@
1
+ const fs = require('fs');
2
+
3
+ /**
4
+ * This script will uninstall pre-commit or pre-push hooks in case there's ever a need to
5
+ * commit/push something that has issues
6
+ */
7
+
8
+ const precommitPath = '.git/hooks/pre-commit';
9
+ const prepushPath = '.git/hooks/pre-push';
10
+ fs.unlink(precommitPath, (err) => {
11
+ if (err && err.code !== 'ENOENT') {
12
+ console.log(`${err.message}`);
13
+ }
14
+ });
15
+
16
+ fs.unlink(prepushPath, (err) => {
17
+ if (err && err.code !== 'ENOENT') {
18
+ console.log(`${err.message}`);
19
+ }
20
+ });
@@ -0,0 +1,169 @@
1
+ /* eslint no-console: warn */
2
+ /* eslint import/no-unresolved: warn */
3
+ /* eslint global-require: warn */
4
+
5
+ // suppress eslint rule in adapter
6
+ /* eslint arrow-parens: warn */
7
+ /* eslint import/no-extraneous-dependencies: warn */
8
+ /* eslint import/no-dynamic-require: warn */
9
+
10
+ const path = require('path');
11
+ const program = require('commander');
12
+ const rls = require('readline-sync');
13
+ const utils = require('./tbUtils');
14
+ const basicGet = require('./basicGet');
15
+ const { name } = require('../package.json');
16
+ const sampleProperties = require('../sampleProperties.json');
17
+ const adapterPronghorn = require('../pronghorn.json');
18
+ const { addAuthInfo } = require('./addAuth');
19
+
20
+ const { troubleshoot, offline } = require('./troubleshootingAdapter');
21
+
22
+ const main = async (command) => {
23
+ const dirname = utils.getDirname();
24
+ const iapDir = path.join(dirname, '../../../');
25
+ if (!utils.withinIAP(iapDir)) {
26
+ if (command === 'install') {
27
+ console.log('Not currently in IAP directory - installation not possible');
28
+ process.exit(0);
29
+ } else if (command === 'connectivity') {
30
+ const { host } = sampleProperties.properties;
31
+ console.log(`perform networking diagnositics to ${host}`);
32
+ await utils.runConnectivity(host);
33
+ process.exit(0);
34
+ } else if (command === 'healthcheck') {
35
+ const a = basicGet.getAdapterInstance({ properties: sampleProperties });
36
+ await utils.healthCheck(a);
37
+ process.exit(0);
38
+ } else if (command === 'basicget') {
39
+ await utils.runBasicGet();
40
+ process.exit(0);
41
+ }
42
+ if (rls.keyInYN('Troubleshooting without IAP?')) {
43
+ await offline();
44
+ }
45
+ process.exit(0);
46
+ }
47
+
48
+ if (command === undefined) {
49
+ await troubleshoot({}, true, true);
50
+ } else if (command === 'install') {
51
+ const { database, serviceItem, pronghornProps } = await utils.getAdapterConfig();
52
+ const filter = { id: pronghornProps.id };
53
+ const profileItem = await database.collection(utils.IAP_PROFILES_COLLECTION).findOne(filter);
54
+ if (!profileItem) {
55
+ console.log(`Could not find IAP profile for id ${pronghornProps.id}`);
56
+ process.exit(0);
57
+ }
58
+ if (serviceItem) {
59
+ console.log(`A service by the name ${name} already exits!`);
60
+ if (rls.keyInYN(`Do you want to completely remove ${name}?`)) {
61
+ console.log(`Removing ${name} from db...`);
62
+ await database.collection(utils.SERVICE_CONFIGS_COLLECTION).deleteOne({ model: name });
63
+ console.log(`${name} removed from db.`);
64
+ if (profileItem.services.includes(serviceItem.name)) {
65
+ const serviceIndex = profileItem.services.indexOf(serviceItem.name);
66
+ profileItem.services.splice(serviceIndex, 1);
67
+ const update = { $set: { services: profileItem.services } };
68
+ await database.collection(utils.IAP_PROFILES_COLLECTION).updateOne(
69
+ { id: pronghornProps.id }, update
70
+ );
71
+ console.log(`${serviceItem.name} removed from profileItem.services.`);
72
+ console.log(`Rerun the script to reinstall ${serviceItem.name}.`);
73
+ process.exit(0);
74
+ } else {
75
+ process.exit(0);
76
+ }
77
+ } else {
78
+ console.log('Exiting...');
79
+ process.exit(0);
80
+ }
81
+ } else {
82
+ utils.verifyInstallationDir(dirname, name);
83
+ utils.runTest();
84
+ if (rls.keyInYN(`Do you want to install ${name} to IAP?`)) {
85
+ console.log('Creating database entries...');
86
+ const adapter = utils.createAdapter(
87
+ pronghornProps, profileItem, sampleProperties, adapterPronghorn
88
+ );
89
+
90
+ adapter.properties.properties = await addAuthInfo(adapter.properties.properties);
91
+
92
+ await database.collection(utils.SERVICE_CONFIGS_COLLECTION).insertOne(adapter);
93
+ profileItem.services.push(adapter.name);
94
+ const update = { $set: { services: profileItem.services } };
95
+ await database.collection(utils.IAP_PROFILES_COLLECTION).updateOne(
96
+ { id: pronghornProps.id }, update
97
+ );
98
+ console.log('Database entry creation complete.');
99
+ }
100
+ console.log('Exiting...');
101
+ process.exit(0);
102
+ }
103
+ } else if (['healthcheck', 'basicget', 'connectivity'].includes(command)) {
104
+ const { serviceItem } = await utils.getAdapterConfig();
105
+ if (serviceItem) {
106
+ const adapter = serviceItem;
107
+ const a = basicGet.getAdapterInstance(adapter);
108
+ if (command === 'healthcheck') {
109
+ await utils.healthCheck(a);
110
+ process.exit(0);
111
+ } else if (command === 'basicget') {
112
+ await utils.runBasicGet(true);
113
+ } else if (command === 'connectivity') {
114
+ const { host } = adapter.properties.properties;
115
+ console.log(`perform networking diagnositics to ${host}`);
116
+ await utils.runConnectivity(host, true);
117
+ process.exit(0);
118
+ }
119
+ } else {
120
+ console.log(`${name} not installed. Run npm \`run install:adapter\` to install.`);
121
+ process.exit(0);
122
+ }
123
+ }
124
+ };
125
+
126
+ program
127
+ .command('connectivity')
128
+ .alias('c')
129
+ .description('networking diagnostics')
130
+ .action(() => {
131
+ main('connectivity');
132
+ });
133
+
134
+ program
135
+ .command('install')
136
+ .alias('i')
137
+ .description('install current adapter')
138
+ .action(() => {
139
+ main('install');
140
+ });
141
+
142
+ program
143
+ .command('healthcheck')
144
+ .alias('hc')
145
+ .description('perfom none interative healthcheck with current setting')
146
+ .action(() => {
147
+ main('healthcheck');
148
+ });
149
+
150
+ program
151
+ .command('basicget')
152
+ .alias('bg')
153
+ .description('perfom basicget')
154
+ .action(() => {
155
+ main('basicget');
156
+ });
157
+
158
+ // Allow commander to parse `process.argv`
159
+ program.parse(process.argv);
160
+
161
+ if (process.argv.length < 3) {
162
+ main();
163
+ }
164
+ const allowedParams = ['install', 'healthcheck', 'basicget', 'connectivity'];
165
+ if (process.argv.length === 3 && !allowedParams.includes(process.argv[2])) {
166
+ console.log(`unknown parameter ${process.argv[2]}`);
167
+ console.log('try `node troubleshootingAdapter.js -h` to see allowed parameters. Exiting...');
168
+ process.exit(0);
169
+ }