@itentialopensource/adapter-winston_syslog 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +5 -0
- package/.eslintrc.js +18 -0
- package/.jshintrc +3 -0
- package/CHANGELOG.md +9 -0
- package/LICENSE +201 -0
- package/README.md +285 -0
- package/adapter.js +250 -0
- package/adapterBase.js +1782 -0
- package/entities/.generic/action.json +214 -0
- package/entities/.generic/schema.json +28 -0
- package/entities/.system/action.json +50 -0
- package/entities/.system/mockdatafiles/getToken-default.json +3 -0
- package/entities/.system/mockdatafiles/healthcheck-default.json +3 -0
- package/entities/.system/schema.json +19 -0
- package/entities/.system/schemaTokenReq.json +53 -0
- package/entities/.system/schemaTokenResp.json +53 -0
- package/error.json +190 -0
- package/package.json +87 -0
- package/pronghorn.json +93 -0
- package/propertiesDecorators.json +14 -0
- package/propertiesSchema.json +1243 -0
- package/refs?service=git-upload-pack +0 -0
- package/report/adapterInfo.json +10 -0
- package/sampleProperties.json +60 -0
- package/test/integration/adapterTestIntegration.js +329 -0
- package/test/unit/adapterBaseTestUnit.js +949 -0
- package/test/unit/adapterTestUnit.js +1207 -0
- package/utils/adapterInfo.js +206 -0
- package/utils/addAuth.js +94 -0
- package/utils/artifactize.js +146 -0
- package/utils/basicGet.js +50 -0
- package/utils/checkMigrate.js +63 -0
- package/utils/entitiesToDB.js +179 -0
- package/utils/findPath.js +74 -0
- package/utils/modify.js +154 -0
- package/utils/packModificationScript.js +35 -0
- package/utils/patches2bundledDeps.js +90 -0
- package/utils/pre-commit.sh +30 -0
- package/utils/removeHooks.js +20 -0
- package/utils/setup.js +33 -0
- package/utils/tbScript.js +184 -0
- package/utils/tbUtils.js +469 -0
- package/utils/testRunner.js +298 -0
- package/utils/troubleshootingAdapter.js +190 -0
- package/workflows/README.md +3 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
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 program = require('commander');
|
|
11
|
+
const rls = require('readline-sync');
|
|
12
|
+
const utils = require('./tbUtils');
|
|
13
|
+
const basicGet = require('./basicGet');
|
|
14
|
+
const { name } = require('../package.json');
|
|
15
|
+
const sampleProperties = require('../sampleProperties.json');
|
|
16
|
+
const adapterPronghorn = require('../pronghorn.json');
|
|
17
|
+
const { addAuthInfo } = require('./addAuth');
|
|
18
|
+
|
|
19
|
+
const { troubleshoot, offline } = require('./troubleshootingAdapter');
|
|
20
|
+
|
|
21
|
+
const executeInStandaloneMode = async (command) => {
|
|
22
|
+
console.info('\n> Executing the script outside of IAP installation directory');
|
|
23
|
+
console.info('> Using sampleProperties.json configuration');
|
|
24
|
+
switch (command) {
|
|
25
|
+
case 'install': {
|
|
26
|
+
console.error('Not currently in IAP directory - installation not possible');
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
case 'connectivity': {
|
|
30
|
+
const { host } = sampleProperties.properties;
|
|
31
|
+
console.log(`perform networking diagnositics to ${host}`);
|
|
32
|
+
utils.runConnectivity(host);
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
case 'healthcheck': {
|
|
36
|
+
const a = basicGet.getAdapterInstance({ properties: sampleProperties });
|
|
37
|
+
await utils.healthCheck(a);
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
case 'basicget': {
|
|
41
|
+
utils.runBasicGet();
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
default: {
|
|
45
|
+
if (rls.keyInYN('Troubleshooting without IAP?')) {
|
|
46
|
+
await offline();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
process.exit(0);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const executeUnderIAPInstallationDirectory = async (command) => {
|
|
54
|
+
if (command === undefined) {
|
|
55
|
+
await troubleshoot({}, true, true);
|
|
56
|
+
} else if (command === 'install') {
|
|
57
|
+
const { database, serviceItem, pronghornProps } = await utils.getAdapterConfig();
|
|
58
|
+
const filter = { id: pronghornProps.id };
|
|
59
|
+
const profileItem = await database.collection(utils.IAP_PROFILES_COLLECTION).findOne(filter);
|
|
60
|
+
if (!profileItem) {
|
|
61
|
+
console.log(`Could not find IAP profile for id ${pronghornProps.id}`);
|
|
62
|
+
process.exit(0);
|
|
63
|
+
}
|
|
64
|
+
if (serviceItem) {
|
|
65
|
+
console.log(`A service by the name ${name} already exits!`);
|
|
66
|
+
if (rls.keyInYN(`Do you want to completely remove ${name}?`)) {
|
|
67
|
+
console.log(`Removing ${name} from db...`);
|
|
68
|
+
await database.collection(utils.SERVICE_CONFIGS_COLLECTION).deleteOne({ model: name });
|
|
69
|
+
console.log(`${name} removed from db.`);
|
|
70
|
+
if (profileItem.services.includes(serviceItem.name)) {
|
|
71
|
+
const serviceIndex = profileItem.services.indexOf(serviceItem.name);
|
|
72
|
+
profileItem.services.splice(serviceIndex, 1);
|
|
73
|
+
const update = { $set: { services: profileItem.services } };
|
|
74
|
+
await database.collection(utils.IAP_PROFILES_COLLECTION).updateOne(
|
|
75
|
+
{ id: pronghornProps.id }, update
|
|
76
|
+
);
|
|
77
|
+
console.log(`${serviceItem.name} removed from profileItem.services.`);
|
|
78
|
+
console.log(`Rerun the script to reinstall ${serviceItem.name}.`);
|
|
79
|
+
process.exit(0);
|
|
80
|
+
} else {
|
|
81
|
+
process.exit(0);
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
console.log('Exiting...');
|
|
85
|
+
process.exit(0);
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
const dirname = utils.getCurrentExecutionPath();
|
|
89
|
+
utils.verifyInstallationDir(dirname, name);
|
|
90
|
+
utils.runTest();
|
|
91
|
+
if (rls.keyInYN(`Do you want to install ${name} to IAP?`)) {
|
|
92
|
+
console.log('Creating database entries...');
|
|
93
|
+
const adapter = utils.createAdapter(
|
|
94
|
+
pronghornProps, profileItem, sampleProperties, adapterPronghorn
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
adapter.properties.properties = await addAuthInfo(adapter.properties.properties);
|
|
98
|
+
|
|
99
|
+
await database.collection(utils.SERVICE_CONFIGS_COLLECTION).insertOne(adapter);
|
|
100
|
+
profileItem.services.push(adapter.name);
|
|
101
|
+
const update = { $set: { services: profileItem.services } };
|
|
102
|
+
await database.collection(utils.IAP_PROFILES_COLLECTION).updateOne(
|
|
103
|
+
{ id: pronghornProps.id }, update
|
|
104
|
+
);
|
|
105
|
+
console.log('Database entry creation complete.');
|
|
106
|
+
}
|
|
107
|
+
console.log('Exiting...');
|
|
108
|
+
process.exit(0);
|
|
109
|
+
}
|
|
110
|
+
} else if (['healthcheck', 'basicget', 'connectivity'].includes(command)) {
|
|
111
|
+
const { serviceItem } = await utils.getAdapterConfig();
|
|
112
|
+
if (serviceItem) {
|
|
113
|
+
const adapter = serviceItem;
|
|
114
|
+
const a = basicGet.getAdapterInstance(adapter);
|
|
115
|
+
if (command === 'healthcheck') {
|
|
116
|
+
await utils.healthCheck(a);
|
|
117
|
+
process.exit(0);
|
|
118
|
+
} else if (command === 'basicget') {
|
|
119
|
+
await utils.runBasicGet(true);
|
|
120
|
+
} else if (command === 'connectivity') {
|
|
121
|
+
const { host } = adapter.properties.properties;
|
|
122
|
+
console.log(`perform networking diagnositics to ${host}`);
|
|
123
|
+
await utils.runConnectivity(host, true);
|
|
124
|
+
process.exit(0);
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
console.log(`${name} not installed. Run npm \`run install:adapter\` to install.`);
|
|
128
|
+
process.exit(0);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const main = async (command) => {
|
|
134
|
+
if (!utils.areWeUnderIAPinstallationDirectory()) {
|
|
135
|
+
executeInStandaloneMode(command); // configuration from sampleproperties.json
|
|
136
|
+
} else {
|
|
137
|
+
executeUnderIAPInstallationDirectory(command); // configuration from $IAP_HOME/properties.json
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
program
|
|
142
|
+
.command('connectivity')
|
|
143
|
+
.alias('c')
|
|
144
|
+
.description('networking diagnostics')
|
|
145
|
+
.action(() => {
|
|
146
|
+
main('connectivity');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
program
|
|
150
|
+
.command('install')
|
|
151
|
+
.alias('i')
|
|
152
|
+
.description('install current adapter')
|
|
153
|
+
.action(() => {
|
|
154
|
+
main('install');
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
program
|
|
158
|
+
.command('healthcheck')
|
|
159
|
+
.alias('hc')
|
|
160
|
+
.description('perfom none interative healthcheck with current setting')
|
|
161
|
+
.action(() => {
|
|
162
|
+
main('healthcheck');
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
program
|
|
166
|
+
.command('basicget')
|
|
167
|
+
.alias('bg')
|
|
168
|
+
.description('perfom basicget')
|
|
169
|
+
.action(() => {
|
|
170
|
+
main('basicget');
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Allow commander to parse `process.argv`
|
|
174
|
+
program.parse(process.argv);
|
|
175
|
+
|
|
176
|
+
if (process.argv.length < 3) {
|
|
177
|
+
main();
|
|
178
|
+
}
|
|
179
|
+
const allowedParams = ['install', 'healthcheck', 'basicget', 'connectivity'];
|
|
180
|
+
if (process.argv.length === 3 && !allowedParams.includes(process.argv[2])) {
|
|
181
|
+
console.log(`unknown parameter ${process.argv[2]}`);
|
|
182
|
+
console.log('try `node troubleshootingAdapter.js -h` to see allowed parameters. Exiting...');
|
|
183
|
+
process.exit(0);
|
|
184
|
+
}
|
package/utils/tbUtils.js
ADDED
|
@@ -0,0 +1,469 @@
|
|
|
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
|
+
/* eslint-disable no-console */
|
|
7
|
+
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const fs = require('fs-extra');
|
|
10
|
+
const cp = require('child_process');
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
SERVICE_CONFIGS_COLLECTION: 'service_configs',
|
|
14
|
+
IAP_PROFILES_COLLECTION: 'iap_profiles',
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @summary update newConnection properties in adapter config
|
|
18
|
+
*
|
|
19
|
+
* @function updateNewConnection
|
|
20
|
+
* @param {Object} config - adaper configuration object required by IAP
|
|
21
|
+
* @param {Object} newConnection - connection related property collection from user
|
|
22
|
+
*/
|
|
23
|
+
updateNewConnection: (config, newConnection) => {
|
|
24
|
+
const updatedConfig = JSON.parse(JSON.stringify(config));
|
|
25
|
+
Object.keys(newConnection).forEach((key) => {
|
|
26
|
+
updatedConfig.properties.properties[key] = newConnection[key];
|
|
27
|
+
});
|
|
28
|
+
return updatedConfig;
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @summary assemble heathcheck endpoint into an URL
|
|
33
|
+
*
|
|
34
|
+
* @function getHealthCheckEndpointURL
|
|
35
|
+
* @param {Object} endpoint - user updated healthcheck endpoint object
|
|
36
|
+
* @param {Object} config - adaper configuration object required by IAP
|
|
37
|
+
*/
|
|
38
|
+
getHealthCheckEndpointURL: (endpoint, config) => {
|
|
39
|
+
const p = config.properties.properties;
|
|
40
|
+
const healthCheckEndpointURL = `${p.protocol}://${p.host}${p.base_path}${p.version}${endpoint.healthCheckEndpoint}`;
|
|
41
|
+
console.log({ healthCheckEndpointURL });
|
|
42
|
+
return healthCheckEndpointURL;
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @summary persist healthcheck endpoint when user make update
|
|
47
|
+
*
|
|
48
|
+
* @function updateHealthCheckEndpoint
|
|
49
|
+
* @param {Object} newHealthCheckEndpoint - user confirmed healthcheck object
|
|
50
|
+
* @param {Object} healthCheckEndpoint - existing healthcheck object
|
|
51
|
+
* @param {Object} healthcheck - ./entities/.system/action.json object
|
|
52
|
+
*/
|
|
53
|
+
updateHealthCheckEndpoint: (newHealthCheckEndpoint, healthCheckEndpoint, healthcheck) => {
|
|
54
|
+
if (newHealthCheckEndpoint.healthCheckEndpoint !== healthCheckEndpoint.healthCheckEndpoint) {
|
|
55
|
+
const p = healthcheck.actions[1].entitypath;
|
|
56
|
+
const newEntitypath = p.slice(0, 21) + newHealthCheckEndpoint.healthCheckEndpoint + p.slice(p.length - 8);
|
|
57
|
+
const updatedHealthcheck = JSON.parse(JSON.stringify(healthcheck));
|
|
58
|
+
updatedHealthcheck.actions[1].entitypath = newEntitypath;
|
|
59
|
+
console.log('updating healthcheck setting');
|
|
60
|
+
fs.writeFileSync('./entities/.system/action.json', JSON.stringify(updatedHealthcheck, null, 2));
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @summary update authentication property given new input value from user
|
|
66
|
+
* compare values from auth and newAuth, if there's difference
|
|
67
|
+
* update adapter config
|
|
68
|
+
* @function updateAuth
|
|
69
|
+
* @param {Object} newAuth - user confirmed authentication object
|
|
70
|
+
* @param {Object} auth - existing authentication object
|
|
71
|
+
* @param {Object} config - adaper configuration object required by IAP
|
|
72
|
+
*/
|
|
73
|
+
updateAuth: (newAuth, auth, config) => {
|
|
74
|
+
const updatedConfig = JSON.parse(JSON.stringify(config));
|
|
75
|
+
if (Object.keys(newAuth).every((key) => newAuth[key] === auth[key])) {
|
|
76
|
+
return config;
|
|
77
|
+
}
|
|
78
|
+
Object.keys(newAuth).forEach((key) => {
|
|
79
|
+
updatedConfig.properties.properties.authentication[key] = newAuth[key];
|
|
80
|
+
});
|
|
81
|
+
console.log(updatedConfig.properties.properties.authentication);
|
|
82
|
+
return updatedConfig;
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @summary add mark current auth_method with `(current)`
|
|
87
|
+
*
|
|
88
|
+
* @function getDisplayAuthOptions
|
|
89
|
+
* @param {String} currentAuth - current auth method in adapter config
|
|
90
|
+
* @param {Array} authOptions - available auth method
|
|
91
|
+
*/
|
|
92
|
+
getDisplayAuthOptions: (currentAuth, authOptions) => {
|
|
93
|
+
const displayAuthOptions = JSON.parse(JSON.stringify(authOptions));
|
|
94
|
+
displayAuthOptions[authOptions.indexOf(currentAuth)] += ' (current)';
|
|
95
|
+
return displayAuthOptions;
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @summary decrypt IAP properties
|
|
100
|
+
* code from pronghorn-core/migration_scripts/installService.js
|
|
101
|
+
*
|
|
102
|
+
* @function decryptProperties
|
|
103
|
+
*/
|
|
104
|
+
decryptProperties: (props, iapDir, discovery) => {
|
|
105
|
+
const propertyEncryptionClassPath = path.join(iapDir, 'node_modules/@itential/pronghorn-core/core/PropertyEncryption.js');
|
|
106
|
+
const isEncrypted = props.pathProps.encrypted;
|
|
107
|
+
const PropertyEncryption = discovery.require(propertyEncryptionClassPath, isEncrypted);
|
|
108
|
+
const propertyEncryption = new PropertyEncryption({
|
|
109
|
+
algorithm: 'aes-256-ctr',
|
|
110
|
+
key: 'TG9uZ0Rpc3RhbmNlUnVubmVyUHJvbmdob3JuCg==',
|
|
111
|
+
encoding: 'utf-8'
|
|
112
|
+
});
|
|
113
|
+
return propertyEncryption.decryptProps(props);
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @summary create connection object for verification
|
|
118
|
+
*
|
|
119
|
+
* @function getConnection
|
|
120
|
+
* @param {Object} props - adapter config.properties
|
|
121
|
+
*/
|
|
122
|
+
getConnection: (props) => {
|
|
123
|
+
const connection = {
|
|
124
|
+
host: props.properties.host,
|
|
125
|
+
base_path: props.properties.base_path,
|
|
126
|
+
protocol: props.properties.protocol,
|
|
127
|
+
version: props.properties.version,
|
|
128
|
+
port: props.properties.port
|
|
129
|
+
};
|
|
130
|
+
return connection;
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @summary update connection properties based on user answer
|
|
135
|
+
*
|
|
136
|
+
* @function getNewProps
|
|
137
|
+
* @param {Array} answers - values collected from CLI
|
|
138
|
+
* @param {Object} connection - connection property verified by user
|
|
139
|
+
*/
|
|
140
|
+
getNewProps: (answers, connection) => {
|
|
141
|
+
if (answers.every((answer) => answer === '')) {
|
|
142
|
+
return connection;
|
|
143
|
+
}
|
|
144
|
+
const newConnection = {};
|
|
145
|
+
const properties = Object.keys(connection);
|
|
146
|
+
for (let i = 0; i < answers.length; i += 1) {
|
|
147
|
+
if (answers[i]) {
|
|
148
|
+
newConnection[properties[i]] = Number.isNaN(Number(answers[i])) ? answers[i] : Number(answers[i]);
|
|
149
|
+
} else {
|
|
150
|
+
newConnection[properties[i]] = connection[properties[i]];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return newConnection;
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* @summary extract endpoint string from healthcheck object
|
|
158
|
+
*
|
|
159
|
+
* @function getHealthCheckEndpoint
|
|
160
|
+
* @param {Object} healthcheck - {Object} healthcheck - ./entities/.system/action.json object
|
|
161
|
+
*/
|
|
162
|
+
getHealthCheckEndpoint: (healthcheck) => {
|
|
163
|
+
const endpoint = healthcheck.actions[1].entitypath.slice(21,
|
|
164
|
+
healthcheck.actions[1].entitypath.length - 8);
|
|
165
|
+
return { healthCheckEndpoint: endpoint };
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* @summary Verify that the adapter is in the correct directory
|
|
170
|
+
* - Within IAP
|
|
171
|
+
* - In node_modules/@ namespace
|
|
172
|
+
* verify the adapter is installed under node_modules/
|
|
173
|
+
* and is consistent with the name property of package.json
|
|
174
|
+
* and the node_modules/ is in the correct path within IAP
|
|
175
|
+
* @param {String} dirname - current path
|
|
176
|
+
* @param {String} name - name property from package.json
|
|
177
|
+
*/
|
|
178
|
+
verifyInstallationDir: (dirname, name) => {
|
|
179
|
+
const pathArray = dirname.split(path.sep);
|
|
180
|
+
const expectedPath = `node_modules/${name}`;
|
|
181
|
+
const currentPath = pathArray.slice(pathArray.length - 3, pathArray.length).join('/');
|
|
182
|
+
if (currentPath.trim() !== expectedPath.trim()) {
|
|
183
|
+
throw new Error(`adapter should be installed under ${expectedPath} but is installed under ${currentPath}`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const serverFile = path.join(dirname, '../../../', 'server.js');
|
|
187
|
+
if (!fs.existsSync(serverFile)) {
|
|
188
|
+
throw new Error(`adapter should be installed under IAP/${expectedPath}`);
|
|
189
|
+
}
|
|
190
|
+
console.log(`adapter correctly installed at ${currentPath}`);
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* @summary execute command and preserve the output the same as run command in shell
|
|
195
|
+
*
|
|
196
|
+
* @function systemSync
|
|
197
|
+
* @param {String} cmd - Command to execute
|
|
198
|
+
* @param {boolean} process - Whether stdout should be processed and returned
|
|
199
|
+
*/
|
|
200
|
+
systemSync: function systemSync(cmd, process) {
|
|
201
|
+
if (process) {
|
|
202
|
+
let stdout;
|
|
203
|
+
try {
|
|
204
|
+
stdout = cp.execSync(cmd).toString();
|
|
205
|
+
} catch (error) {
|
|
206
|
+
stdout = error.stdout.toString();
|
|
207
|
+
}
|
|
208
|
+
const output = this.getTestCount(stdout);
|
|
209
|
+
output.stdout = stdout;
|
|
210
|
+
return output;
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
return cp.execSync(cmd, { stdio: 'inherit' });
|
|
214
|
+
} catch (error) {
|
|
215
|
+
return console.error(error.stdout);
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* @summary parses a string and returns the number parsed from startIndex backwards
|
|
221
|
+
*
|
|
222
|
+
* @function parseNum
|
|
223
|
+
* @param {String} inputStr - Any String
|
|
224
|
+
* @param {Number} startIndex - Index to begin parsing
|
|
225
|
+
*/
|
|
226
|
+
parseNum: function parseNum(inputStr, startIndex) {
|
|
227
|
+
let count = '';
|
|
228
|
+
let currChar;
|
|
229
|
+
let start = startIndex;
|
|
230
|
+
while (currChar !== ' ') {
|
|
231
|
+
currChar = inputStr.charAt(start);
|
|
232
|
+
count = currChar + count;
|
|
233
|
+
start -= 1;
|
|
234
|
+
}
|
|
235
|
+
return parseInt(count, 10);
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* @summary Parses a mocha test result and returns the count of passing and failing tests
|
|
240
|
+
*
|
|
241
|
+
* @function getTestCount
|
|
242
|
+
* @param {String} testStr - Output from mocha test
|
|
243
|
+
*/
|
|
244
|
+
getTestCount: function getTestCount(testStr) {
|
|
245
|
+
const passIndex = testStr.search('passing');
|
|
246
|
+
const failIndex = testStr.search('failing');
|
|
247
|
+
const passCount = passIndex >= 0 ? this.parseNum(testStr, passIndex - 2) : 0;
|
|
248
|
+
const failCount = failIndex >= 0 ? this.parseNum(testStr, failIndex - 2) : 0;
|
|
249
|
+
return { passCount, failCount };
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* @summary remove package-lock.json and node_modules directory if exists
|
|
254
|
+
* run npm install and print result to stdout
|
|
255
|
+
*/
|
|
256
|
+
npmInstall: function npmInstall() {
|
|
257
|
+
fs.removeSync('../package-lock.json');
|
|
258
|
+
fs.removeSync('../node_modules/');
|
|
259
|
+
console.log('Run npm install ...');
|
|
260
|
+
this.systemSync('npm install');
|
|
261
|
+
},
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* @summary run lint, unit test and integration test
|
|
265
|
+
* print result to stdout
|
|
266
|
+
*/
|
|
267
|
+
runTest: function runTest() {
|
|
268
|
+
this.systemSync('npm run lint:errors');
|
|
269
|
+
this.systemSync('npm run test:unit');
|
|
270
|
+
this.systemSync('npm run test:integration');
|
|
271
|
+
},
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* @summary run basicget with mocha
|
|
275
|
+
* @param {boolean} scriptFlag - whether the function is ran from a script
|
|
276
|
+
* print result to stdout
|
|
277
|
+
* returns mocha test results otherwise
|
|
278
|
+
*/
|
|
279
|
+
runBasicGet: function runBasicGet(scriptFlag) {
|
|
280
|
+
const testPath = path.resolve(__dirname, '..', 'test/integration/adapterTestBasicGet.js');
|
|
281
|
+
return this.systemSync(`mocha ${testPath} --exit`, !scriptFlag);
|
|
282
|
+
},
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* @summary run connectivity with mocha
|
|
286
|
+
* @param {String} host - Host url to run healthcheck
|
|
287
|
+
* @param {boolean} scriptFlag - Whether the function is ran from a script
|
|
288
|
+
* print result to stdout if ran from script
|
|
289
|
+
* returns mocha test results otherwise
|
|
290
|
+
*/
|
|
291
|
+
runConnectivity: function runConnectivity(host, scriptFlag) {
|
|
292
|
+
let testPath = 'test/integration/adapterTestConnectivity.js';
|
|
293
|
+
if (!scriptFlag) {
|
|
294
|
+
testPath = path.resolve(__dirname, '..', testPath);
|
|
295
|
+
}
|
|
296
|
+
return this.systemSync(`mocha ${testPath} --HOST=${host} --timeout 10000 --exit`, !scriptFlag);
|
|
297
|
+
},
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* @summary create Adapter property
|
|
301
|
+
*
|
|
302
|
+
* @function createAdapter
|
|
303
|
+
* @param {Object} pronghornProps - decrypted 'properties.json' from IAP root directory
|
|
304
|
+
* @param {Object} profileItem - pronghorn props saved in database
|
|
305
|
+
* @param {Object} adapterPronghorn - ./pronghorn.json in adapter dir
|
|
306
|
+
* @param {Object} sampleProperties - './sampleProperties.json' in adapter dir
|
|
307
|
+
*/
|
|
308
|
+
createAdapter: function createAdapter(pronghornProps, profileItem, sampleProperties, adapterPronghorn) {
|
|
309
|
+
const iapDir = this.getIAPHome();
|
|
310
|
+
const packageFile = path.join(iapDir, 'package.json');
|
|
311
|
+
const info = JSON.parse(fs.readFileSync(packageFile));
|
|
312
|
+
const version = parseInt(info.version.split('.')[0], 10);
|
|
313
|
+
|
|
314
|
+
let adapter = {};
|
|
315
|
+
if (version >= 2020) {
|
|
316
|
+
adapter = {
|
|
317
|
+
isEncrypted: pronghornProps.pathProps.encrypted,
|
|
318
|
+
model: adapterPronghorn.id,
|
|
319
|
+
name: sampleProperties.id,
|
|
320
|
+
type: adapterPronghorn.type,
|
|
321
|
+
properties: sampleProperties,
|
|
322
|
+
loggerProps: profileItem.loggerProps
|
|
323
|
+
};
|
|
324
|
+
} else {
|
|
325
|
+
adapter = {
|
|
326
|
+
mongoProps: pronghornProps.mongoProps,
|
|
327
|
+
isEncrypted: pronghornProps.pathProps.encrypted,
|
|
328
|
+
model: adapterPronghorn.id,
|
|
329
|
+
name: sampleProperties.id,
|
|
330
|
+
type: adapterPronghorn.type,
|
|
331
|
+
properties: sampleProperties,
|
|
332
|
+
redisProps: profileItem.redisProps,
|
|
333
|
+
loggerProps: profileItem.loggerProps,
|
|
334
|
+
rabbitmq: profileItem.rabbitmq
|
|
335
|
+
};
|
|
336
|
+
adapter.mongoProps.pdb = true;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
adapter.loggerProps.log_filename = `adapter-${adapter.name}.log`;
|
|
340
|
+
return adapter;
|
|
341
|
+
},
|
|
342
|
+
|
|
343
|
+
getPronghornProps: function getPronghornProps(iapDir) {
|
|
344
|
+
console.log('Retrieving properties.json file...');
|
|
345
|
+
const rawProps = require(path.join(iapDir, 'properties.json'));
|
|
346
|
+
console.log('Decrypting properties...');
|
|
347
|
+
const { Discovery } = require(path.join(iapDir, 'node_modules/@itential/itential-utils'));
|
|
348
|
+
const discovery = new Discovery();
|
|
349
|
+
const pronghornProps = this.decryptProperties(rawProps, iapDir, discovery);
|
|
350
|
+
console.log('Found properties.\n');
|
|
351
|
+
return pronghornProps;
|
|
352
|
+
},
|
|
353
|
+
|
|
354
|
+
// get database connection and existing adapter config
|
|
355
|
+
getAdapterConfig: async function getAdapterConfig() {
|
|
356
|
+
const iapDir = this.getIAPHome();
|
|
357
|
+
const pronghornProps = this.getPronghornProps(iapDir);
|
|
358
|
+
console.log('Connecting to Database...');
|
|
359
|
+
const database = await this.connect(iapDir, pronghornProps);
|
|
360
|
+
console.log('Connection established.');
|
|
361
|
+
const { name } = require(path.join(__dirname, '..', 'package.json'));
|
|
362
|
+
const serviceItem = await database.collection(this.SERVICE_CONFIGS_COLLECTION).findOne(
|
|
363
|
+
{ model: name }
|
|
364
|
+
);
|
|
365
|
+
return { database, serviceItem, pronghornProps };
|
|
366
|
+
},
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* @summary return async healthcheck result as a Promise
|
|
370
|
+
*
|
|
371
|
+
* @function request
|
|
372
|
+
* @param {Adapter} a - Adapter instance
|
|
373
|
+
*/
|
|
374
|
+
request: function request(a) {
|
|
375
|
+
return new Promise((resolve, reject) => {
|
|
376
|
+
a.healthCheck(null, (data) => {
|
|
377
|
+
if (!data) reject(new Error('healthCheckEndpoint failed'));
|
|
378
|
+
resolve(data);
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
},
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* @summary deal with healthcheck response returned from adapter instace
|
|
385
|
+
*
|
|
386
|
+
* @function healthCheck
|
|
387
|
+
* @param {Adapter} a - Adapter instance
|
|
388
|
+
*/
|
|
389
|
+
healthCheck: async function healthCheck(a) {
|
|
390
|
+
const result = await this.request(a)
|
|
391
|
+
.then((res) => {
|
|
392
|
+
console.log('healthCheckEndpoint OK');
|
|
393
|
+
return res;
|
|
394
|
+
})
|
|
395
|
+
.catch((error) => {
|
|
396
|
+
console.error(error.message);
|
|
397
|
+
return false;
|
|
398
|
+
});
|
|
399
|
+
return result;
|
|
400
|
+
},
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* @summary Obtain the IAP installation directory depending on how adapter is used:
|
|
404
|
+
* by IAP, or by npm run CLI interface
|
|
405
|
+
* @returns IAP installation directory or null if adapter running without IAP
|
|
406
|
+
* @function getIAPHome
|
|
407
|
+
*/
|
|
408
|
+
getIAPHome: function getIAPHome() {
|
|
409
|
+
let IAPHomePath = null;
|
|
410
|
+
// check if adapter started via IAP, use path injected by core
|
|
411
|
+
if (process.env.iap_home) IAPHomePath = process.env.iap_home;
|
|
412
|
+
// check if adapter started via CLI `npm run <command>` so we have to be located under
|
|
413
|
+
// <IAP_HOME>/node_modules/@itentialopensource/<adapter_name>/ directory
|
|
414
|
+
const currentExecutionPath = this.getCurrentExecutionPath();
|
|
415
|
+
if (currentExecutionPath.indexOf('/node_modules') >= 0) {
|
|
416
|
+
[IAPHomePath] = currentExecutionPath.split('/node_modules');
|
|
417
|
+
}
|
|
418
|
+
return IAPHomePath;
|
|
419
|
+
},
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* @summary get current execution path without resolving symbolic links,
|
|
423
|
+
* use `pwd` command wihout '-P' option (resolving symlinks) https://linux.die.net/man/1/pwd
|
|
424
|
+
* @returns
|
|
425
|
+
* @function getCurrentExecutionPAth
|
|
426
|
+
*/
|
|
427
|
+
getCurrentExecutionPath: function getCurrentExecutionPAth() {
|
|
428
|
+
const { stdout } = this.systemSync('pwd', true);
|
|
429
|
+
return stdout.trim();
|
|
430
|
+
},
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* @summary checks if command executed from <IAP_HOME>/node_modules/@itentialopensource/<adapter_name>/ location
|
|
434
|
+
* @returns true if command executed under <IAP_HOME>/node_modules/@itentialopensource/<adapter_name>/ path
|
|
435
|
+
* @function areWeUnderIAPinstallationDirectory
|
|
436
|
+
*/
|
|
437
|
+
areWeUnderIAPinstallationDirectory: function areWeUnderIAPinstallationDirectory() {
|
|
438
|
+
return path.join(this.getCurrentExecutionPath(), '../../..') === this.getIAPHome();
|
|
439
|
+
},
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* @summary connect to mongodb
|
|
443
|
+
*
|
|
444
|
+
* @function connect
|
|
445
|
+
* @param {Object} properties - pronghornProps
|
|
446
|
+
*/
|
|
447
|
+
connect: async function connect(iapDir, properties) {
|
|
448
|
+
let dbConnectionProperties = {};
|
|
449
|
+
if (properties.mongoProps) {
|
|
450
|
+
dbConnectionProperties = properties.mongoProps;
|
|
451
|
+
} else if (properties.mongo) {
|
|
452
|
+
if (properties.mongo.url) {
|
|
453
|
+
dbConnectionProperties.url = properties.mongo.url;
|
|
454
|
+
} else {
|
|
455
|
+
dbConnectionProperties.url = `mongodb://${properties.mongo.host}:${properties.mongo.port}`;
|
|
456
|
+
}
|
|
457
|
+
dbConnectionProperties.db = properties.mongo.database;
|
|
458
|
+
}
|
|
459
|
+
if (!dbConnectionProperties.url || !dbConnectionProperties.db) {
|
|
460
|
+
throw new Error('Mongo properties are not specified in IAP configuration!');
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
const { MongoDBConnection } = require(path.join(iapDir, 'node_modules/@itential/database'));
|
|
464
|
+
const connection = new MongoDBConnection(dbConnectionProperties);
|
|
465
|
+
const database = await connection.connect(true);
|
|
466
|
+
return database;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
};
|