@itentialopensource/adapter-meraki 1.0.3 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. package/AUTH.md +14 -18
  2. package/CALLS.md +4264 -0
  3. package/CHANGELOG.md +16 -0
  4. package/CONTRIBUTING.md +1 -160
  5. package/ENHANCE.md +2 -2
  6. package/README.md +23 -18
  7. package/SYSTEMINFO.md +15 -2
  8. package/adapter.js +164 -335
  9. package/adapterBase.js +411 -920
  10. package/changelogs/changelog.md +198 -0
  11. package/metadata.json +61 -0
  12. package/package.json +24 -24
  13. package/pronghorn.json +470 -138
  14. package/propertiesSchema.json +358 -31
  15. package/refs?service=git-upload-pack +0 -0
  16. package/report/adapterInfo.json +8 -8
  17. package/report/updateReport1690417926405.json +119 -0
  18. package/sampleProperties.json +74 -27
  19. package/test/integration/adapterTestBasicGet.js +2 -4
  20. package/test/integration/adapterTestConnectivity.js +91 -42
  21. package/test/integration/adapterTestIntegration.js +130 -2
  22. package/test/unit/adapterBaseTestUnit.js +388 -313
  23. package/test/unit/adapterTestUnit.js +332 -112
  24. package/utils/adapterInfo.js +1 -1
  25. package/utils/addAuth.js +1 -1
  26. package/utils/artifactize.js +1 -1
  27. package/utils/checkMigrate.js +1 -1
  28. package/utils/entitiesToDB.js +2 -2
  29. package/utils/findPath.js +1 -1
  30. package/utils/methodDocumentor.js +225 -0
  31. package/utils/modify.js +13 -15
  32. package/utils/packModificationScript.js +1 -1
  33. package/utils/pre-commit.sh +2 -0
  34. package/utils/taskMover.js +309 -0
  35. package/utils/tbScript.js +89 -34
  36. package/utils/tbUtils.js +41 -21
  37. package/utils/testRunner.js +1 -1
  38. package/utils/troubleshootingAdapter.js +9 -6
  39. package/versions.json +0 -542
  40. package/workflows/README.md +0 -3
package/adapterBase.js CHANGED
@@ -11,29 +11,29 @@
11
11
  /* eslint prefer-destructuring: warn */
12
12
 
13
13
  /* Required libraries. */
14
- const fs = require('fs-extra');
15
14
  const path = require('path');
16
- const jsonQuery = require('json-query');
17
- const EventEmitterCl = require('events').EventEmitter;
18
15
  const { execSync } = require('child_process');
16
+ const { spawnSync } = require('child_process');
17
+ const EventEmitterCl = require('events').EventEmitter;
18
+ const fs = require('fs-extra');
19
+ const jsonQuery = require('json-query');
19
20
 
20
21
  const sampleProperties = require(`${__dirname}/sampleProperties.json`).properties;
21
22
 
22
23
  /* The schema validator */
23
24
  const AjvCl = require('ajv');
25
+ const { Test } = require('mocha');
24
26
 
25
27
  /* Fetch in the other needed components for the this Adaptor */
26
28
  const PropUtilCl = require('@itentialopensource/adapter-utils').PropertyUtility;
27
29
  const RequestHandlerCl = require('@itentialopensource/adapter-utils').RequestHandler;
28
30
 
29
- const TransUtilCl = require(path.join(__dirname, 'node_modules/@itentialopensource/adapter-utils/lib/translatorUtil.js'));
30
-
31
31
  const entitiesToDB = require(path.join(__dirname, 'utils/entitiesToDB'));
32
32
  const troubleshootingAdapter = require(path.join(__dirname, 'utils/troubleshootingAdapter'));
33
33
  const tbUtils = require(path.join(__dirname, 'utils/tbUtils'));
34
+ const taskMover = require(path.join(__dirname, 'utils/taskMover'));
34
35
 
35
36
  let propUtil = null;
36
- let transUtil = null;
37
37
  let choosepath = null;
38
38
 
39
39
  /*
@@ -155,49 +155,6 @@ function updatePackage(changes) {
155
155
  return null;
156
156
  }
157
157
 
158
- /*
159
- * INTERNAL FUNCTION: get data from source(s) - nested
160
- */
161
- function getDataFromSources(loopField, sources) {
162
- let fieldValue = loopField;
163
-
164
- // go through the sources to find the field
165
- for (let s = 0; s < sources.length; s += 1) {
166
- // find the field value using jsonquery
167
- const nestedValue = jsonQuery(loopField, { data: sources[s] }).value;
168
-
169
- // if we found in source - set and no need to check other sources
170
- if (nestedValue) {
171
- fieldValue = nestedValue;
172
- break;
173
- }
174
- }
175
-
176
- return fieldValue;
177
- }
178
-
179
- /*
180
- * INTERNAL FUNCTION: update allprops device broker array with service config and sample props
181
- */
182
- function getDeviceBrokerArray(sampleProps, allProps) {
183
- const brokerCallsArr = ['getDevice', 'getDevicesFiltered', 'isAlive', 'getConfig', 'getCount'];
184
- const deviceBroker = allProps.devicebroker;
185
- for (let i = 0; i < brokerCallsArr.length; i += 1) {
186
- if (!allProps.devicebroker || !allProps.devicebroker[brokerCallsArr[i]] || allProps.devicebroker[brokerCallsArr[i]].length === 0 || !allProps.devicebroker[brokerCallsArr[i]][0].path) {
187
- // if not in service config check sample props
188
- if (!sampleProps.devicebroker || !sampleProps.devicebroker[brokerCallsArr[i]] || sampleProps.devicebroker[brokerCallsArr[i]].length === 0 || !sampleProps.devicebroker[brokerCallsArr[i]][0].path) {
189
- deviceBroker[brokerCallsArr[i]] = [];
190
- } else {
191
- log.info('Updating device broker with sample props');
192
- deviceBroker[brokerCallsArr[i]] = sampleProps.devicebroker[brokerCallsArr[i]];
193
- }
194
- }
195
- }
196
-
197
- log.info('Device broker array', JSON.stringify(deviceBroker, null, 3));
198
- return deviceBroker;
199
- }
200
-
201
158
  /* GENERAL ADAPTER FUNCTIONS THESE SHOULD NOT BE DIRECTLY MODIFIED */
202
159
  /* IF YOU NEED MODIFICATIONS, REDEFINE THEM IN adapter.js!!! */
203
160
  class AdapterBase extends EventEmitterCl {
@@ -217,10 +174,6 @@ class AdapterBase extends EventEmitterCl {
217
174
  this.id = prongid;
218
175
  this.propUtilInst = new PropUtilCl(prongid, __dirname);
219
176
  propUtil = this.propUtilInst;
220
- this.transUtilInst = new TransUtilCl(prongid, this.propUtilInst);
221
- transUtil = this.transUtilInst;
222
- this.transUtilInst = new TransUtilCl(prongid, this.propUtilInst);
223
- transUtil = this.transUtilInst;
224
177
  this.initProps = properties;
225
178
  this.alive = false;
226
179
  this.healthy = false;
@@ -233,8 +186,6 @@ class AdapterBase extends EventEmitterCl {
233
186
 
234
187
  // set up the properties I care about
235
188
  this.refreshProperties(properties);
236
- // update deviceBroker based on service config and sample props
237
- this.allProps.devicebroker = getDeviceBrokerArray(sampleProperties, this.allProps);
238
189
 
239
190
  // Instantiate the other components for this Adapter
240
191
  this.requestHandlerInst = new RequestHandlerCl(this.id, this.allProps, __dirname);
@@ -293,7 +244,7 @@ class AdapterBase extends EventEmitterCl {
293
244
  this.allProps = this.propUtilInst.mergeProperties(properties, defProps);
294
245
 
295
246
  // validate the entity against the schema
296
- const ajvInst = new AjvCl();
247
+ const ajvInst = new AjvCl({ strictSchema: false, allowUnionTypes: true });
297
248
  const validate = ajvInst.compile(propertiesSchema);
298
249
  const result = validate(this.allProps);
299
250
 
@@ -471,6 +422,40 @@ class AdapterBase extends EventEmitterCl {
471
422
  return myfunctions;
472
423
  }
473
424
 
425
+ /**
426
+ * iapGetAdapterWorkflowFunctions is used to get all of the workflow function in the adapter
427
+ * @param {array} ignoreThese - additional methods to ignore (optional)
428
+ *
429
+ * @function iapGetAdapterWorkflowFunctions
430
+ */
431
+ iapGetAdapterWorkflowFunctions(ignoreThese) {
432
+ const myfunctions = this.getAllFunctions();
433
+ const wffunctions = [];
434
+
435
+ // remove the functions that should not be in a Workflow
436
+ for (let m = 0; m < myfunctions.length; m += 1) {
437
+ if (myfunctions[m] === 'checkActionFiles') {
438
+ // got to the second tier (adapterBase)
439
+ break;
440
+ }
441
+ if (!(myfunctions[m].endsWith('Emit') || myfunctions[m].match(/Emit__v[0-9]+/))) {
442
+ let found = false;
443
+ if (ignoreThese && Array.isArray(ignoreThese)) {
444
+ for (let i = 0; i < ignoreThese.length; i += 1) {
445
+ if (myfunctions[m].toUpperCase() === ignoreThese[i].toUpperCase()) {
446
+ found = true;
447
+ }
448
+ }
449
+ }
450
+ if (!found) {
451
+ wffunctions.push(myfunctions[m]);
452
+ }
453
+ }
454
+ }
455
+
456
+ return wffunctions;
457
+ }
458
+
474
459
  /**
475
460
  * checkActionFiles is used to update the validation of the action files.
476
461
  *
@@ -526,40 +511,6 @@ class AdapterBase extends EventEmitterCl {
526
511
  return this.requestHandlerInst.encryptProperty(property, technique, callback);
527
512
  }
528
513
 
529
- /**
530
- * iapGetAdapterWorkflowFunctions is used to get all of the workflow function in the adapter
531
- * @param {array} ignoreThese - additional methods to ignore (optional)
532
- *
533
- * @function iapGetAdapterWorkflowFunctions
534
- */
535
- iapGetAdapterWorkflowFunctions(ignoreThese) {
536
- const myfunctions = this.getAllFunctions();
537
- const wffunctions = [];
538
-
539
- // remove the functions that should not be in a Workflow
540
- for (let m = 0; m < myfunctions.length; m += 1) {
541
- if (myfunctions[m] === 'addEntityCache') {
542
- // got to the second tier (adapterBase)
543
- break;
544
- }
545
- if (!(myfunctions[m].endsWith('Emit') || myfunctions[m].match(/Emit__v[0-9]+/))) {
546
- let found = false;
547
- if (ignoreThese && Array.isArray(ignoreThese)) {
548
- for (let i = 0; i < ignoreThese.length; i += 1) {
549
- if (myfunctions[m].toUpperCase() === ignoreThese[i].toUpperCase()) {
550
- found = true;
551
- }
552
- }
553
- }
554
- if (!found) {
555
- wffunctions.push(myfunctions[m]);
556
- }
557
- }
558
- }
559
-
560
- return wffunctions;
561
- }
562
-
563
514
  /**
564
515
  * iapUpdateAdapterConfiguration is used to update any of the adapter configuration files. This
565
516
  * allows customers to make changes to adapter configuration without having to be on the
@@ -690,6 +641,86 @@ class AdapterBase extends EventEmitterCl {
690
641
  return callback(null, errorObj);
691
642
  }
692
643
 
644
+ /**
645
+ * @summary Suspends the adapter
646
+ * @param {Callback} callback - The adapater suspension status
647
+ * @function iapSuspendAdapter
648
+ */
649
+ iapSuspendAdapter(mode, callback) {
650
+ const origin = `${this.id}-adapterBase-iapSuspendAdapter`;
651
+ if (this.suspended) {
652
+ throw new Error(`${origin}: Adapter is already suspended`);
653
+ }
654
+ try {
655
+ this.suspended = true;
656
+ this.suspendMode = mode;
657
+ if (this.suspendMode === 'pause') {
658
+ const props = JSON.parse(JSON.stringify(this.initProps));
659
+ // To suspend adapter, enable throttling and set concurrent max to 0
660
+ props.throttle.throttle_enabled = true;
661
+ props.throttle.concurrent_max = 0;
662
+ this.refreshProperties(props);
663
+ }
664
+ return callback({ suspended: true });
665
+ } catch (error) {
666
+ return callback(null, error);
667
+ }
668
+ }
669
+
670
+ /**
671
+ * @summary Unsuspends the adapter
672
+ * @param {Callback} callback - The adapater suspension status
673
+ *
674
+ * @function iapUnsuspendAdapter
675
+ */
676
+ iapUnsuspendAdapter(callback) {
677
+ const origin = `${this.id}-adapterBase-iapUnsuspendAdapter`;
678
+ if (!this.suspended) {
679
+ throw new Error(`${origin}: Adapter is not suspended`);
680
+ }
681
+ if (this.suspendMode === 'pause') {
682
+ const props = JSON.parse(JSON.stringify(this.initProps));
683
+ // To unsuspend adapter, keep throttling enabled and begin processing queued requests in order
684
+ props.throttle.throttle_enabled = true;
685
+ props.throttle.concurrent_max = 1;
686
+ this.refreshProperties(props);
687
+ setTimeout(() => {
688
+ this.getQueue((q, error) => {
689
+ // console.log("Items in queue: " + String(q.length))
690
+ if (q.length === 0) {
691
+ // if queue is empty, return to initial properties state
692
+ this.refreshProperties(this.initProps);
693
+ this.suspended = false;
694
+ return callback({ suspended: false });
695
+ }
696
+ // recursive call to check queue again every second
697
+ return this.iapUnsuspendAdapter(callback);
698
+ });
699
+ }, 1000);
700
+ } else {
701
+ this.suspended = false;
702
+ callback({ suspend: false });
703
+ }
704
+ }
705
+
706
+ /**
707
+ * iapGetAdapterQueue is used to get information for all of the requests currently in the queue.
708
+ *
709
+ * @function iapGetAdapterQueue
710
+ * @param {Callback} callback - a callback function to return the result (Queue) or the error
711
+ */
712
+ iapGetAdapterQueue(callback) {
713
+ const origin = `${this.id}-adapterBase-iapGetAdapterQueue`;
714
+ log.trace(origin);
715
+
716
+ return this.requestHandlerInst.getQueue(callback);
717
+ }
718
+
719
+ /* ********************************************** */
720
+ /* */
721
+ /* EXPOSES ADAPTER SCRIPTS */
722
+ /* */
723
+ /* ********************************************** */
693
724
  /**
694
725
  * See if the API path provided is found in this adapter
695
726
  *
@@ -795,81 +826,6 @@ class AdapterBase extends EventEmitterCl {
795
826
  return callback(result, null);
796
827
  }
797
828
 
798
- /**
799
- * @summary Suspends the adapter
800
- * @param {Callback} callback - The adapater suspension status
801
- * @function iapSuspendAdapter
802
- */
803
- iapSuspendAdapter(mode, callback) {
804
- const origin = `${this.id}-adapterBase-iapSuspendAdapter`;
805
- if (this.suspended) {
806
- throw new Error(`${origin}: Adapter is already suspended`);
807
- }
808
- try {
809
- this.suspended = true;
810
- this.suspendMode = mode;
811
- if (this.suspendMode === 'pause') {
812
- const props = JSON.parse(JSON.stringify(this.initProps));
813
- // To suspend adapter, enable throttling and set concurrent max to 0
814
- props.throttle.throttle_enabled = true;
815
- props.throttle.concurrent_max = 0;
816
- this.refreshProperties(props);
817
- }
818
- return callback({ suspended: true });
819
- } catch (error) {
820
- return callback(null, error);
821
- }
822
- }
823
-
824
- /**
825
- * @summary Unsuspends the adapter
826
- * @param {Callback} callback - The adapater suspension status
827
- *
828
- * @function iapUnsuspendAdapter
829
- */
830
- iapUnsuspendAdapter(callback) {
831
- const origin = `${this.id}-adapterBase-iapUnsuspendAdapter`;
832
- if (!this.suspended) {
833
- throw new Error(`${origin}: Adapter is not suspended`);
834
- }
835
- if (this.suspendMode === 'pause') {
836
- const props = JSON.parse(JSON.stringify(this.initProps));
837
- // To unsuspend adapter, keep throttling enabled and begin processing queued requests in order
838
- props.throttle.throttle_enabled = true;
839
- props.throttle.concurrent_max = 1;
840
- this.refreshProperties(props);
841
- setTimeout(() => {
842
- this.getQueue((q, error) => {
843
- // console.log("Items in queue: " + String(q.length))
844
- if (q.length === 0) {
845
- // if queue is empty, return to initial properties state
846
- this.refreshProperties(this.initProps);
847
- this.suspended = false;
848
- return callback({ suspended: false });
849
- }
850
- // recursive call to check queue again every second
851
- return this.iapUnsuspendAdapter(callback);
852
- });
853
- }, 1000);
854
- } else {
855
- this.suspended = false;
856
- callback({ suspend: false });
857
- }
858
- }
859
-
860
- /**
861
- * iapGetAdapterQueue is used to get information for all of the requests currently in the queue.
862
- *
863
- * @function iapGetAdapterQueue
864
- * @param {Callback} callback - a callback function to return the result (Queue) or the error
865
- */
866
- iapGetAdapterQueue(callback) {
867
- const origin = `${this.id}-adapterBase-iapGetAdapterQueue`;
868
- log.trace(origin);
869
-
870
- return this.requestHandlerInst.getQueue(callback);
871
- }
872
-
873
829
  /**
874
830
  * @summary runs troubleshoot scripts for adapter
875
831
  *
@@ -971,156 +927,89 @@ class AdapterBase extends EventEmitterCl {
971
927
  }
972
928
 
973
929
  /**
974
- * @summary take the entities and add them to the cache
930
+ * @function iapDeactivateTasks
975
931
  *
976
- * @function addEntityCache
977
- * @param {String} entityType - the type of the entities
978
- * @param {Array} data - the list of entities
979
- * @param {String} key - unique key for the entities
980
- *
981
- * @param {Callback} callback - An array of whether the adapter can has the
982
- * desired capability or an error
932
+ * @param {Array} tasks - List of tasks to deactivate
933
+ * @param {Callback} callback
983
934
  */
984
- addEntityCache(entityType, entities, key, callback) {
985
- const meth = 'adapterBase-addEntityCache';
935
+ iapDeactivateTasks(tasks, callback) {
936
+ const meth = 'adapterBase-iapDeactivateTasks';
986
937
  const origin = `${this.id}-${meth}`;
987
938
  log.trace(origin);
988
-
989
- // list containing the items to add to the cache
990
- const entityIds = [];
991
-
992
- if (entities && Object.hasOwnProperty.call(entities, 'response')
993
- && Array.isArray(entities.response)) {
994
- for (let e = 0; e < entities.response.length; e += 1) {
995
- entityIds.push(entities.response[e][key]);
996
- }
939
+ let data;
940
+ try {
941
+ data = taskMover.deactivateTasks(__dirname, tasks);
942
+ } catch (ex) {
943
+ taskMover.rollbackChanges(__dirname);
944
+ taskMover.deleteBackups(__dirname);
945
+ return callback(null, ex);
997
946
  }
998
-
999
- // add the entities to the cache
1000
- return this.requestHandlerInst.addEntityCache(entityType, entityIds, (loaded, error) => {
1001
- if (error) {
1002
- return callback(null, error);
1003
- }
1004
- if (!loaded) {
1005
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Entity Cache Not Loading', [entityType], null, null, null);
1006
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1007
- return callback(null, errorObj);
1008
- }
1009
-
1010
- return callback(loaded);
1011
- });
947
+ taskMover.deleteBackups(__dirname);
948
+ return callback(data, null);
1012
949
  }
1013
950
 
1014
951
  /**
1015
- * @summary sees if the entity is in the entity list or not
952
+ * @function iapActivateTasks
1016
953
  *
1017
- * @function entityInList
1018
- * @param {String/Array} entityId - the specific entity we are looking for
1019
- * @param {Array} data - the list of entities
1020
- *
1021
- * @param {Callback} callback - An array of whether the adapter can has the
1022
- * desired capability or an error
954
+ * @param {Array} tasks - List of tasks to deactivate
955
+ * @param {Callback} callback
1023
956
  */
1024
- entityInList(entityId, data) {
1025
- const origin = `${this.id}-adapterBase-entityInList`;
957
+ iapActivateTasks(tasks, callback) {
958
+ const meth = 'adapterBase-iapActivateTasks';
959
+ const origin = `${this.id}-${meth}`;
1026
960
  log.trace(origin);
1027
-
1028
- // need to check on the entities that were passed in
1029
- if (Array.isArray(entityId)) {
1030
- const resEntity = [];
1031
-
1032
- for (let e = 0; e < entityId.length; e += 1) {
1033
- if (data.includes(entityId[e])) {
1034
- resEntity.push(true);
1035
- } else {
1036
- resEntity.push(false);
1037
- }
1038
- }
1039
-
1040
- return resEntity;
961
+ let data;
962
+ try {
963
+ data = taskMover.activateTasks(__dirname, tasks);
964
+ } catch (ex) {
965
+ taskMover.rollbackChanges(__dirname);
966
+ taskMover.deleteBackups(__dirname);
967
+ return callback(null, ex);
1041
968
  }
1042
-
1043
- // does the entity list include the specific entity
1044
- return [data.includes(entityId)];
969
+ taskMover.deleteBackups(__dirname);
970
+ return callback(data, null);
1045
971
  }
1046
972
 
973
+ /* ********************************************** */
974
+ /* */
975
+ /* EXPOSES CACHE CALLS */
976
+ /* */
977
+ /* ********************************************** */
1047
978
  /**
1048
- * @summary prepare results for verify capability so they are true/false
1049
- *
1050
- * @function capabilityResults
1051
- * @param {Array} results - the results from the capability check
979
+ * @summary Populate the cache for the given entities
1052
980
  *
1053
- * @param {Callback} callback - An array of whether the adapter can has the
1054
- * desired capability or an error
981
+ * @function iapPopulateEntityCache
982
+ * @param {String/Array of Strings} entityType - the entity type(s) to populate
983
+ * @param {Callback} callback - whether the cache was updated or not for each entity type
984
+ * @returns return of the callback
1055
985
  */
1056
- capabilityResults(results, callback) {
1057
- const meth = 'adapterBase-capabilityResults';
1058
- const origin = `${this.id}-${meth}`;
986
+ iapPopulateEntityCache(entityTypes, callback) {
987
+ const origin = `${this.myid}-adapterBase-iapPopulateEntityCache`;
1059
988
  log.trace(origin);
1060
- let locResults = results;
1061
-
1062
- if (locResults && locResults[0] === 'needupdate') {
1063
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Entity Cache Not Loading', ['unknown'], null, null, null);
1064
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1065
- this.repeatCacheCount += 1;
1066
- return callback(null, errorObj);
1067
- }
1068
989
 
1069
- // if an error occured, return the error
1070
- if (locResults && locResults[0] === 'error') {
1071
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Error Verifying Entity Cache', null, null, null, null);
1072
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1073
- return callback(null, errorObj);
1074
- }
1075
-
1076
- // go through the response and change to true/false
1077
- if (locResults) {
1078
- // if not an array, just convert the return
1079
- if (!Array.isArray(locResults)) {
1080
- if (locResults === 'found') {
1081
- locResults = [true];
1082
- } else {
1083
- locResults = [false];
1084
- }
1085
- } else {
1086
- const temp = [];
1087
-
1088
- // go through each element in the array to convert
1089
- for (let r = 0; r < locResults.length; r += 1) {
1090
- if (locResults[r] === 'found') {
1091
- temp.push(true);
1092
- } else {
1093
- temp.push(false);
1094
- }
1095
- }
1096
- locResults = temp;
1097
- }
1098
- }
1099
-
1100
- // return the results
1101
- return callback(locResults);
990
+ return this.requestHandlerInst.populateEntityCache(entityTypes, callback);
1102
991
  }
1103
992
 
1104
993
  /**
1105
- * @summary Provides a way for the adapter to tell north bound integrations
1106
- * all of the capabilities for the current adapter
1107
- *
1108
- * @function getAllCapabilities
994
+ * @summary Retrieves data from cache for specified entity type
1109
995
  *
1110
- * @return {Array} - containing the entities and the actions available on each entity
996
+ * @function iapRetrieveEntitiesCache
997
+ * @param {String} entityType - entity of which to retrieve
998
+ * @param {Object} options - settings of which data to return and how to return it
999
+ * @param {Callback} callback - the data if it was retrieved
1111
1000
  */
1112
- getAllCapabilities() {
1113
- const origin = `${this.id}-adapterBase-getAllCapabilities`;
1001
+ iapRetrieveEntitiesCache(entityType, options, callback) {
1002
+ const origin = `${this.myid}-adapterBase-iapRetrieveEntitiesCache`;
1114
1003
  log.trace(origin);
1115
1004
 
1116
- // validate the capabilities for the adapter
1117
- try {
1118
- return this.requestHandlerInst.getAllCapabilities();
1119
- } catch (e) {
1120
- return [];
1121
- }
1005
+ return this.requestHandlerInst.retrieveEntitiesCache(entityType, options, callback);
1122
1006
  }
1123
1007
 
1008
+ /* ********************************************** */
1009
+ /* */
1010
+ /* EXPOSES BROKER CALLS */
1011
+ /* */
1012
+ /* ********************************************** */
1124
1013
  /**
1125
1014
  * @summary Determines if this adapter supports any in a list of entities
1126
1015
  *
@@ -1132,720 +1021,322 @@ class AdapterBase extends EventEmitterCl {
1132
1021
  * value is true or false
1133
1022
  */
1134
1023
  hasEntities(entityType, entityList, callback) {
1135
- const origin = `${this.id}-adapter-hasEntities`;
1024
+ const origin = `${this.id}-adapterBase-hasEntities`;
1136
1025
  log.trace(origin);
1137
1026
 
1138
- switch (entityType) {
1139
- case 'Device':
1140
- return this.hasDevices(entityList, callback);
1141
- default:
1142
- return callback(null, `${this.id} does not support entity ${entityType}`);
1143
- }
1027
+ return this.requestHandlerInst.hasEntities(entityType, entityList, callback);
1144
1028
  }
1145
1029
 
1146
1030
  /**
1147
- * @summary Helper method for hasEntities for the specific device case
1031
+ * @summary Get Appliance that match the deviceName
1148
1032
  *
1149
- * @param {Array} deviceList - array of unique device identifiers
1150
- * @param {Callback} callback - A map where the device is the key and the
1151
- * value is true or false
1033
+ * @function getDevice
1034
+ * @param {String} deviceName - the deviceName to find (required)
1035
+ *
1036
+ * @param {getCallback} callback - a callback function to return the result
1037
+ * (appliance) or the error
1152
1038
  */
1153
- hasDevices(deviceList, callback) {
1154
- const origin = `${this.id}-adapter-hasDevices`;
1039
+ getDevice(deviceName, callback) {
1040
+ const origin = `${this.id}-adapterBase-getDevice`;
1155
1041
  log.trace(origin);
1156
1042
 
1157
- const findings = deviceList.reduce((map, device) => {
1158
- // eslint-disable-next-line no-param-reassign
1159
- map[device] = false;
1160
- log.debug(`In reduce: ${JSON.stringify(map)}`);
1161
- return map;
1162
- }, {});
1163
- const apiCalls = deviceList.map((device) => new Promise((resolve) => {
1164
- this.getDevice(device, (result, error) => {
1165
- if (error) {
1166
- log.debug(`In map error: ${JSON.stringify(device)}`);
1167
- return resolve({ name: device, found: false });
1168
- }
1169
- log.debug(`In map: ${JSON.stringify(device)}`);
1170
- return resolve({ name: device, found: true });
1171
- });
1172
- }));
1173
- Promise.all(apiCalls).then((results) => {
1174
- results.forEach((device) => {
1175
- findings[device.name] = device.found;
1176
- });
1177
- log.debug(`FINDINGS: ${JSON.stringify(findings)}`);
1178
- return callback(findings);
1179
- }).catch((errors) => {
1180
- log.error('Unable to do device lookup.');
1181
- return callback(null, { code: 503, message: 'Unable to do device lookup.', error: errors });
1182
- });
1043
+ return this.requestHandlerInst.getDevice(deviceName, callback);
1183
1044
  }
1184
1045
 
1185
1046
  /**
1186
- * @summary Make one of the needed Broker calls - could be one of many
1047
+ * @summary Get Appliances that match the filter
1187
1048
  *
1188
- * @function iapMakeBrokerCall
1189
- * @param {string} brokCall - the name of the broker call (required)
1190
- * @param {object} callProps - the proeprties for the broker call (required)
1191
- * @param {object} devResp - the device details to extract needed inputs (required)
1192
- * @param {string} filterName - any filter to search on (required)
1049
+ * @function getDevicesFiltered
1050
+ * @param {Object} options - the data to use to filter the appliances (optional)
1193
1051
  *
1194
- * @param {getCallback} callback - a callback function to return the result of the call
1052
+ * @param {getCallback} callback - a callback function to return the result
1053
+ * (appliances) or the error
1195
1054
  */
1196
- iapMakeBrokerCall(brokCall, callProps, devResp, filterName, callback) {
1197
- const meth = 'adapterBase-iapMakeBrokerCall';
1198
- const origin = `${this.id}-${meth}`;
1055
+ getDevicesFiltered(options, callback) {
1056
+ const origin = `${this.id}-adapterBase-getDevicesFiltered`;
1199
1057
  log.trace(origin);
1200
1058
 
1201
- try {
1202
- let uriPath = '';
1203
- let uriMethod = 'GET';
1204
- let callQuery = {};
1205
- let callBody = {};
1206
- let callHeaders = {};
1207
- let handleFail = 'fail';
1208
- let ostypePrefix = '';
1209
- let statusValue = 'true';
1210
- if (callProps.path) {
1211
- uriPath = `${callProps.path}`;
1212
-
1213
- // make any necessary changes to the path
1214
- if (devResp !== null && callProps.requestFields && Object.keys(callProps.requestFields).length > 0) {
1215
- const rqKeys = Object.keys(callProps.requestFields);
1216
-
1217
- // get the field from the provided device
1218
- for (let rq = 0; rq < rqKeys.length; rq += 1) {
1219
- const fieldValue = getDataFromSources(callProps.requestFields[rqKeys[rq]], devResp);
1220
-
1221
- // put the value into the path - if it has been specified in the path
1222
- uriPath = uriPath.replace(`{${rqKeys[rq]}}`, fieldValue);
1223
- }
1224
- }
1225
- }
1226
- if (callProps.method) {
1227
- uriMethod = callProps.method;
1228
- }
1229
- if (callProps.query) {
1230
- callQuery = { ...callProps.query };
1231
- // go through the query params to check for variable values
1232
- const cpKeys = Object.keys(callQuery);
1233
- for (let cp = 0; cp < cpKeys.length; cp += 1) {
1234
- // if (callQuery[cpKeys[cp]].startsWith('{') && callQuery[cpKeys[cp]].endsWith('}')) {
1235
- // make any necessary changes to the query params
1236
- if (devResp !== null && callProps.requestFields && Object.keys(callProps.requestFields).length > 0) {
1237
- const rqKeys = Object.keys(callProps.requestFields);
1238
-
1239
- // get the field from the provided device
1240
- for (let rq = 0; rq < rqKeys.length; rq += 1) {
1241
- if (callQuery[cpKeys[cp]] === rqKeys[rq]) {
1242
- const fieldValue = getDataFromSources(callProps.requestFields[rqKeys[rq]], devResp);
1243
- // put the value into the query - if it has been specified in the query
1244
- callQuery[cpKeys[cp]] = fieldValue;
1245
- }
1246
- }
1247
- }
1248
- // }
1249
- }
1250
- }
1251
- if (callProps.body) {
1252
- callBody = { ...callProps.body };
1253
-
1254
- // go through the body fields to check for variable values
1255
- const cbKeys = Object.keys(callBody);
1256
- for (let cb = 0; cb < cbKeys.length; cb += 1) {
1257
- // if (callBody[cbKeys[cb]].startsWith('{') && callBody[cbKeys[cb]].endsWith('}')) {
1258
- // make any necessary changes to the query params
1259
- if (devResp !== null && callProps.requestFields && Object.keys(callProps.requestFields).length > 0) {
1260
- const rqKeys = Object.keys(callProps.requestFields);
1261
-
1262
- // get the field from the provided device
1263
- for (let rq = 0; rq < rqKeys.length; rq += 1) {
1264
- if (callBody[cbKeys[cb]] === rqKeys[rq]) {
1265
- const fieldValue = getDataFromSources(callProps.requestFields[rqKeys[rq]], devResp);
1266
-
1267
- // put the value into the query - if it has been specified in the query
1268
- callBody[cbKeys[cb]] = fieldValue;
1269
- }
1270
- }
1271
- }
1272
- // }
1273
- }
1274
- }
1275
- if (callProps.headers) {
1276
- callHeaders = { ...callProps.headers };
1277
-
1278
- // go through the body fields to check for variable values
1279
- const chKeys = Object.keys(callHeaders);
1280
- for (let ch = 0; ch < chKeys.length; ch += 1) {
1281
- // if (callHeaders[chKeys[ch]].startsWith('{') && callHeaders[chKeys[ch]].endsWith('}')) {
1282
- // make any necessary changes to the query params
1283
- if (devResp !== null && callProps.requestFields && Object.keys(callProps.requestFields).length > 0) {
1284
- const rqKeys = Object.keys(callProps.requestFields);
1285
-
1286
- // get the field from the provided device
1287
- for (let rq = 0; rq < rqKeys.length; rq += 1) {
1288
- if (callHeaders[chKeys[ch]] === rqKeys[rq]) {
1289
- const fieldValue = getDataFromSources(callProps.requestFields[rqKeys[rq]], devResp);
1290
-
1291
- // put the value into the query - if it has been specified in the query
1292
- callHeaders[chKeys[ch]] = fieldValue;
1293
- }
1294
- }
1295
- }
1296
- // }
1297
- }
1298
- }
1299
- if (callProps.handleFailure) {
1300
- handleFail = callProps.handleFailure;
1301
- }
1302
- if (callProps.responseFields && callProps.responseFields.ostypePrefix) {
1303
- ostypePrefix = callProps.responseFields.ostypePrefix;
1304
- }
1305
- if (callProps.responseFields && callProps.responseFields.statusValue) {
1306
- statusValue = callProps.responseFields.statusValue;
1307
- }
1308
-
1309
- // !! using Generic makes it easier on the Adapter Builder (just need to change the path)
1310
- // !! you can also replace with a specific call if that is easier
1311
- return this.genericAdapterRequest(uriPath, uriMethod, callQuery, callBody, callHeaders, (result, error) => {
1312
- // if we received an error or their is no response on the results return an error
1313
- if (error) {
1314
- if (handleFail === 'fail') {
1315
- return callback(null, error);
1316
- }
1317
- return callback({}, null);
1318
- }
1319
- if (!result.response) {
1320
- if (handleFail === 'fail') {
1321
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Invalid Response', [brokCall], null, null, null);
1322
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1323
- return callback(null, errorObj);
1324
- }
1325
- return callback({}, null);
1326
- }
1327
-
1328
- // get the response piece we care about from the response
1329
- const myResult = result;
1330
- if (callProps.responseDatakey) {
1331
- myResult.response = jsonQuery(callProps.responseDatakey, { data: myResult.response }).value;
1332
- }
1333
-
1334
- // get the keys for the response fields
1335
- let rfKeys = [];
1336
- if (callProps.responseFields && Object.keys(callProps.responseFields).length > 0) {
1337
- rfKeys = Object.keys(callProps.responseFields);
1338
- }
1339
-
1340
- // if we got an array returned (e.g. getDevicesFitered)
1341
- if (Array.isArray(myResult.response)) {
1342
- const listDevices = [];
1343
- for (let a = 0; a < myResult.response.length; a += 1) {
1344
- const thisDevice = myResult.response[a];
1345
- for (let rf = 0; rf < rfKeys.length; rf += 1) {
1346
- if (rfKeys[rf] !== 'ostypePrefix') {
1347
- let fieldValue = getDataFromSources(callProps.responseFields[rfKeys[rf]], [thisDevice, devResp, callProps.requestFields]);
1348
-
1349
- // if the field is ostype - need to add prefix
1350
- if (rfKeys[rf] === 'ostype' && typeof fieldValue === 'string') {
1351
- fieldValue = ostypePrefix + fieldValue;
1352
- }
1353
- // if there is a status to set, set it
1354
- if (rfKeys[rf] === 'status') {
1355
- // if really looking for just a good response
1356
- if (callProps.responseFields[rfKeys[rf]] === 'return2xx' && myResult.icode === statusValue.toString()) {
1357
- thisDevice.isAlive = true;
1358
- } else if (fieldValue.toString() === statusValue.toString()) {
1359
- thisDevice.isAlive = true;
1360
- } else {
1361
- thisDevice.isAlive = false;
1362
- }
1363
- }
1364
- // if we found a good value
1365
- thisDevice[rfKeys[rf]] = fieldValue;
1366
- }
1367
- }
1368
-
1369
- // if there is no filter - add the device to the list
1370
- if (!filterName || filterName.length === 0) {
1371
- listDevices.push(thisDevice);
1372
- } else {
1373
- // if we have to match a filter
1374
- let found = false;
1375
- for (let f = 0; f < filterName.length; f += 1) {
1376
- if (thisDevice.name.indexOf(filterName[f]) >= 0) {
1377
- found = true;
1378
- break;
1379
- }
1380
- }
1381
- // matching device
1382
- if (found) {
1383
- listDevices.push(thisDevice);
1384
- }
1385
- }
1386
- }
1387
-
1388
- // return the array of devices
1389
- return callback(listDevices, null);
1390
- }
1391
-
1392
- // if this is not an array - just about everything else, just handle as a single object
1393
- let thisDevice = myResult.response;
1394
- for (let rf = 0; rf < rfKeys.length; rf += 1) {
1395
- // skip ostypePrefix since it is not a field
1396
- if (rfKeys[rf] !== 'ostypePrefix') {
1397
- let fieldValue = getDataFromSources(callProps.responseFields[rfKeys[rf]], [thisDevice, devResp, callProps.requestFields]);
1398
-
1399
- // if the field is ostype - need to add prefix
1400
- if (rfKeys[rf] === 'ostype' && typeof fieldValue === 'string') {
1401
- fieldValue = ostypePrefix + fieldValue;
1402
- }
1403
- // if there is a status to set, set it
1404
- if (rfKeys[rf] === 'status') {
1405
- // if really looking for just a good response
1406
- if (callProps.responseFields[rfKeys[rf]] === 'return2xx' && myResult.icode === statusValue.toString()) {
1407
- thisDevice.isAlive = true;
1408
- } else if (fieldValue.toString() === statusValue.toString()) {
1409
- thisDevice.isAlive = true;
1410
- } else {
1411
- thisDevice.isAlive = false;
1412
- }
1413
- }
1414
- // if we found a good value
1415
- thisDevice[rfKeys[rf]] = fieldValue;
1416
- }
1417
- }
1418
-
1419
- // if there is a filter - check the device is in the list
1420
- if (filterName && filterName.length > 0) {
1421
- let found = false;
1422
- for (let f = 0; f < filterName.length; f += 1) {
1423
- if (thisDevice.name.indexOf(filterName[f]) >= 0) {
1424
- found = true;
1425
- break;
1426
- }
1427
- }
1428
- // no matching device - clear the device
1429
- if (!found) {
1430
- thisDevice = {};
1431
- }
1432
- }
1433
-
1434
- return callback(thisDevice, null);
1435
- });
1436
- } catch (e) {
1437
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, e);
1438
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1439
- return callback(null, errorObj);
1440
- }
1059
+ return this.requestHandlerInst.getDevicesFiltered(options, callback);
1441
1060
  }
1442
1061
 
1443
1062
  /**
1444
- * @summary Get Appliance that match the deviceName
1063
+ * @summary Gets the status for the provided appliance
1445
1064
  *
1446
- * @function getDevice
1447
- * @param {String} deviceName - the deviceName to find (required)
1065
+ * @function isAlive
1066
+ * @param {String} deviceName - the deviceName of the appliance. (required)
1448
1067
  *
1449
- * @param {getCallback} callback - a callback function to return the result
1450
- * (appliance) or the error
1068
+ * @param {configCallback} callback - callback function to return the result
1069
+ * (appliance isAlive) or the error
1451
1070
  */
1452
- getDevice(deviceName, callback) {
1453
- const meth = 'adapterBase-getDevice';
1454
- const origin = `${this.id}-${meth}`;
1071
+ isAlive(deviceName, callback) {
1072
+ const origin = `${this.id}-adapterBase-isAlive`;
1455
1073
  log.trace(origin);
1456
1074
 
1457
- // make sure we are set up for device broker getDevice
1458
- if (!this.allProps.devicebroker || !this.allProps.devicebroker.getDevice || this.allProps.devicebroker.getDevice.length === 0 || !this.allProps.devicebroker.getDevice[0].path) {
1459
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Properties', ['devicebroker.getDevice.path'], null, null, null);
1460
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1461
- return callback(null, errorObj);
1462
- }
1463
-
1464
- /* HERE IS WHERE YOU VALIDATE DATA */
1465
- if (deviceName === undefined || deviceName === null || deviceName === '' || deviceName.length === 0) {
1466
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['deviceName'], null, null, null);
1467
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1468
- return callback(null, errorObj);
1469
- }
1470
-
1471
- try {
1472
- // need to get the device so we can convert the deviceName to an id
1473
- // !! if we can do a lookup by name the getDevicesFiltered may not be necessary
1474
- const opts = {
1475
- filter: {
1476
- name: deviceName
1477
- }
1478
- };
1479
- return this.getDevicesFiltered(opts, (devs, ferr) => {
1480
- // if we received an error or their is no response on the results return an error
1481
- if (ferr) {
1482
- return callback(null, ferr);
1483
- }
1484
- if (devs.list.length < 1) {
1485
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Did Not Find Device ${deviceName}`, [], null, null, null);
1486
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1487
- return callback(null, errorObj);
1488
- }
1489
-
1490
- const callPromises = [];
1491
- for (let i = 0; i < this.allProps.devicebroker.getDevice.length; i += 1) {
1492
- // Perform component calls here.
1493
- callPromises.push(
1494
- new Promise((resolve, reject) => {
1495
- this.iapMakeBrokerCall('getDevice', this.allProps.devicebroker.getDevice[i], [devs.list[0]], [deviceName], (callRet, callErr) => {
1496
- // return an error
1497
- if (callErr) {
1498
- reject(callErr);
1499
- } else {
1500
- // return the data
1501
- resolve(callRet);
1502
- }
1503
- });
1504
- })
1505
- );
1506
- }
1075
+ return this.requestHandlerInst.isAlive(deviceName, callback);
1076
+ }
1507
1077
 
1508
- // return an array of repsonses
1509
- return Promise.all(callPromises).then((results) => {
1510
- let myResult = {};
1511
- results.forEach((result) => {
1512
- myResult = { ...myResult, ...result };
1513
- });
1078
+ /**
1079
+ * @summary Gets a config for the provided Appliance
1080
+ *
1081
+ * @function getConfig
1082
+ * @param {String} deviceName - the deviceName of the appliance. (required)
1083
+ * @param {String} format - the desired format of the config. (optional)
1084
+ *
1085
+ * @param {configCallback} callback - callback function to return the result
1086
+ * (appliance config) or the error
1087
+ */
1088
+ getConfig(deviceName, format, callback) {
1089
+ const origin = `${this.id}-adapterBase-getConfig`;
1090
+ log.trace(origin);
1514
1091
 
1515
- return callback(myResult, null);
1516
- });
1517
- });
1518
- } catch (ex) {
1519
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
1520
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1521
- return callback(null, errorObj);
1522
- }
1092
+ return this.requestHandlerInst.getConfig(deviceName, format, callback);
1523
1093
  }
1524
1094
 
1525
1095
  /**
1526
- * @summary Get Appliances that match the filter
1096
+ * @summary Gets the device count from the system
1527
1097
  *
1528
- * @function getDevicesFiltered
1529
- * @param {Object} options - the data to use to filter the appliances (optional)
1098
+ * @function iapGetDeviceCount
1530
1099
  *
1531
- * @param {getCallback} callback - a callback function to return the result
1532
- * (appliances) or the error
1100
+ * @param {getCallback} callback - callback function to return the result
1101
+ * (count) or the error
1533
1102
  */
1534
- getDevicesFiltered(options, callback) {
1535
- const meth = 'adapterBase-getDevicesFiltered';
1536
- const origin = `${this.id}-${meth}`;
1103
+ iapGetDeviceCount(callback) {
1104
+ const origin = `${this.id}-adapterBase-iapGetDeviceCount`;
1537
1105
  log.trace(origin);
1538
1106
 
1539
- // make sure we are set up for device broker getDevicesFiltered
1540
- if (!this.allProps.devicebroker || !this.allProps.devicebroker.getDevicesFiltered || this.allProps.devicebroker.getDevicesFiltered.length === 0 || !this.allProps.devicebroker.getDevicesFiltered[0].path) {
1541
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Properties', ['devicebroker.getDevicesFiltered.path'], null, null, null);
1542
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1543
- return callback(null, errorObj);
1544
- }
1107
+ return this.requestHandlerInst.iapGetDeviceCount(callback);
1108
+ }
1545
1109
 
1546
- // verify the required fields have been provided
1547
- if (options === undefined || options === null || options === '' || options.length === 0) {
1548
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['options'], null, null, null);
1549
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1550
- return callback(null, errorObj);
1551
- }
1552
- log.debug(`Device Filter Options: ${JSON.stringify(options)}`);
1110
+ /* ********************************************** */
1111
+ /* */
1112
+ /* EXPOSES GENERIC HANDLER */
1113
+ /* */
1114
+ /* ********************************************** */
1115
+ /**
1116
+ * Makes the requested generic call
1117
+ *
1118
+ * @function iapExpandedGenericAdapterRequest
1119
+ * @param {Object} metadata - metadata for the call (optional).
1120
+ * Can be a stringified Object.
1121
+ * @param {String} uriPath - the path of the api call - do not include the host, port, base path or version (optional)
1122
+ * @param {String} restMethod - the rest method (GET, POST, PUT, PATCH, DELETE) (optional)
1123
+ * @param {Object} pathVars - the parameters to be put within the url path (optional).
1124
+ * Can be a stringified Object.
1125
+ * @param {Object} queryData - the parameters to be put on the url (optional).
1126
+ * Can be a stringified Object.
1127
+ * @param {Object} requestBody - the body to add to the request (optional).
1128
+ * Can be a stringified Object.
1129
+ * @param {Object} addlHeaders - additional headers to be put on the call (optional).
1130
+ * Can be a stringified Object.
1131
+ * @param {getCallback} callback - a callback function to return the result (Generics)
1132
+ * or the error
1133
+ */
1134
+ iapExpandedGenericAdapterRequest(metadata, uriPath, restMethod, pathVars, queryData, requestBody, addlHeaders, callback) {
1135
+ const origin = `${this.myid}-adapterBase-iapExpandedGenericAdapterRequest`;
1136
+ log.trace(origin);
1553
1137
 
1554
- try {
1555
- // TODO - get pagination working
1556
- // const nextToken = options.start;
1557
- // const maxResults = options.limit;
1558
-
1559
- // set up the filter of Device Names
1560
- let filterName = [];
1561
- if (options && options.filter && options.filter.name) {
1562
- // when this hack is removed, remove the lint ignore above
1563
- if (Array.isArray(options.filter.name)) {
1564
- // eslint-disable-next-line prefer-destructuring
1565
- filterName = options.filter.name;
1566
- } else {
1567
- filterName = [options.filter.name];
1568
- }
1569
- }
1138
+ return this.requestHandlerInst.expandedGenericAdapterRequest(metadata, uriPath, restMethod, pathVars, queryData, requestBody, addlHeaders, callback);
1139
+ }
1570
1140
 
1571
- // TODO - get sort and order working
1572
- /*
1573
- if (options && options.sort) {
1574
- reqObj.uriOptions.sort = JSON.stringify(options.sort);
1575
- }
1576
- if (options && options.order) {
1577
- reqObj.uriOptions.order = options.order;
1578
- }
1579
- */
1580
- const callPromises = [];
1581
- for (let i = 0; i < this.allProps.devicebroker.getDevicesFiltered.length; i += 1) {
1582
- // Perform component calls here.
1583
- callPromises.push(
1584
- new Promise((resolve, reject) => {
1585
- this.iapMakeBrokerCall('getDevicesFiltered', this.allProps.devicebroker.getDevicesFiltered[i], [{ fake: 'fakedata' }], filterName, (callRet, callErr) => {
1586
- // return an error
1587
- if (callErr) {
1588
- reject(callErr);
1589
- } else {
1590
- // return the data
1591
- resolve(callRet);
1592
- }
1593
- });
1594
- })
1595
- );
1596
- }
1141
+ /**
1142
+ * Makes the requested generic call
1143
+ *
1144
+ * @function genericAdapterRequest
1145
+ * @param {String} uriPath - the path of the api call - do not include the host, port, base path or version (required)
1146
+ * @param {String} restMethod - the rest method (GET, POST, PUT, PATCH, DELETE) (required)
1147
+ * @param {Object} queryData - the parameters to be put on the url (optional).
1148
+ * Can be a stringified Object.
1149
+ * @param {Object} requestBody - the body to add to the request (optional).
1150
+ * Can be a stringified Object.
1151
+ * @param {Object} addlHeaders - additional headers to be put on the call (optional).
1152
+ * Can be a stringified Object.
1153
+ * @param {getCallback} callback - a callback function to return the result (Generics)
1154
+ * or the error
1155
+ */
1156
+ genericAdapterRequest(uriPath, restMethod, queryData, requestBody, addlHeaders, callback) {
1157
+ const origin = `${this.myid}-adapterBase-genericAdapterRequest`;
1158
+ log.trace(origin);
1597
1159
 
1598
- // return an array of repsonses
1599
- return Promise.all(callPromises).then((results) => {
1600
- let myResult = [];
1601
- results.forEach((result) => {
1602
- if (Array.isArray(result)) {
1603
- myResult = [...myResult, ...result];
1604
- } else if (Object.keys(result).length > 0) {
1605
- myResult.push(result);
1606
- }
1607
- });
1160
+ return this.requestHandlerInst.genericAdapterRequest(uriPath, restMethod, queryData, requestBody, addlHeaders, callback);
1161
+ }
1608
1162
 
1609
- log.debug(`${origin}: Found #${myResult.length} devices.`);
1610
- log.debug(`Devices: ${JSON.stringify(myResult)}`);
1611
- return callback({ total: myResult.length, list: myResult });
1612
- });
1613
- } catch (ex) {
1614
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
1615
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1616
- return callback(null, errorObj);
1617
- }
1163
+ /**
1164
+ * Makes the requested generic call with no base path or version
1165
+ *
1166
+ * @function genericAdapterRequestNoBasePath
1167
+ * @param {String} uriPath - the path of the api call - do not include the host, port, base path or version (required)
1168
+ * @param {String} restMethod - the rest method (GET, POST, PUT, PATCH, DELETE) (required)
1169
+ * @param {Object} queryData - the parameters to be put on the url (optional).
1170
+ * Can be a stringified Object.
1171
+ * @param {Object} requestBody - the body to add to the request (optional).
1172
+ * Can be a stringified Object.
1173
+ * @param {Object} addlHeaders - additional headers to be put on the call (optional).
1174
+ * Can be a stringified Object.
1175
+ * @param {getCallback} callback - a callback function to return the result (Generics)
1176
+ * or the error
1177
+ */
1178
+ genericAdapterRequestNoBasePath(uriPath, restMethod, queryData, requestBody, addlHeaders, callback) {
1179
+ const origin = `${this.myid}-adapterBase-genericAdapterRequestNoBasePath`;
1180
+ log.trace(origin);
1181
+
1182
+ return this.requestHandlerInst.genericAdapterRequestNoBasePath(uriPath, restMethod, queryData, requestBody, addlHeaders, callback);
1618
1183
  }
1619
1184
 
1185
+ /* ********************************************** */
1186
+ /* */
1187
+ /* EXPOSES INVENTORY CALLS */
1188
+ /* */
1189
+ /* ********************************************** */
1620
1190
  /**
1621
- * @summary Gets the status for the provided appliance
1191
+ * @summary run the adapter lint script to return the results.
1622
1192
  *
1623
- * @function isAlive
1624
- * @param {String} deviceName - the deviceName of the appliance. (required)
1193
+ * @function iapRunAdapterLint
1625
1194
  *
1626
- * @param {configCallback} callback - callback function to return the result
1627
- * (appliance isAlive) or the error
1195
+ * @return {Object} - containing the results of the lint call.
1628
1196
  */
1629
- isAlive(deviceName, callback) {
1630
- const meth = 'adapterBase-isAlive';
1197
+ iapRunAdapterLint(callback) {
1198
+ const meth = 'adapterBase-iapRunAdapterLint';
1631
1199
  const origin = `${this.id}-${meth}`;
1632
1200
  log.trace(origin);
1201
+ let command = null;
1633
1202
 
1634
- // make sure we are set up for device broker isAlive
1635
- if (!this.allProps.devicebroker || !this.allProps.devicebroker.isAlive || this.allProps.devicebroker.isAlive.length === 0 || !this.allProps.devicebroker.isAlive[0].path) {
1636
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Properties', ['devicebroker.isAlive.path'], null, null, null);
1637
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1638
- return callback(null, errorObj);
1639
- }
1203
+ if (fs.existsSync('package.json')) {
1204
+ const packageData = require('./package.json');
1640
1205
 
1641
- // verify the required fields have been provided
1642
- if (deviceName === undefined || deviceName === null || deviceName === '' || deviceName.length === 0) {
1643
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['deviceName'], null, null, null);
1644
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1645
- return callback(null, errorObj);
1646
- }
1647
-
1648
- try {
1649
- // need to get the device so we can convert the deviceName to an id
1650
- // !! if we can do a lookup by name the getDevicesFiltered may not be necessary
1651
- const opts = {
1652
- filter: {
1653
- name: deviceName
1654
- }
1655
- };
1656
- return this.getDevicesFiltered(opts, (devs, ferr) => {
1657
- // if we received an error or their is no response on the results return an error
1658
- if (ferr) {
1659
- return callback(null, ferr);
1660
- }
1661
- if (devs.list.length < 1) {
1662
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Did Not Find Device ${deviceName}`, [], null, null, null);
1663
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1664
- return callback(null, errorObj);
1665
- }
1666
-
1667
- const callPromises = [];
1668
- for (let i = 0; i < this.allProps.devicebroker.isAlive.length; i += 1) {
1669
- // Perform component calls here.
1670
- callPromises.push(
1671
- new Promise((resolve, reject) => {
1672
- this.iapMakeBrokerCall('isAlive', this.allProps.devicebroker.isAlive[i], [devs.list[0]], null, (callRet, callErr) => {
1673
- // return an error
1674
- if (callErr) {
1675
- reject(callErr);
1676
- } else {
1677
- // return the data
1678
- resolve(callRet);
1679
- }
1680
- });
1681
- })
1682
- );
1683
- }
1206
+ // check if 'test', 'test:unit', 'test:integration' exists in package.json file
1207
+ if (!packageData.scripts || !packageData.scripts['lint:errors']) {
1208
+ log.error('The required script does not exist in the package.json file');
1209
+ return callback(null, 'The required script does not exist in the package.json file');
1210
+ }
1684
1211
 
1685
- // return an array of repsonses
1686
- return Promise.all(callPromises).then((results) => {
1687
- let myResult = {};
1688
- results.forEach((result) => {
1689
- myResult = { ...myResult, ...result };
1690
- });
1212
+ // execute 'npm run lint:errors' command
1213
+ command = spawnSync('npm', ['run', 'lint:errors'], { cwd: __dirname, encoding: 'utf-8' });
1691
1214
 
1692
- let response = true;
1693
- if (myResult.isAlive !== null && myResult.isAlive !== undefined && myResult.isAlive === false) {
1694
- response = false;
1695
- }
1696
- return callback(response);
1697
- });
1698
- });
1699
- } catch (ex) {
1700
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
1701
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1702
- return callback(null, errorObj);
1215
+ // analyze and format the response
1216
+ const result = {
1217
+ status: 'SUCCESS'
1218
+ };
1219
+ if (command.status !== 0) {
1220
+ result.status = 'FAILED';
1221
+ result.output = command.stdout;
1222
+ }
1223
+ return callback(result);
1703
1224
  }
1225
+
1226
+ log.error('Package Not Found');
1227
+ return callback(null, 'Package Not Found');
1704
1228
  }
1705
1229
 
1706
1230
  /**
1707
- * @summary Gets a config for the provided Appliance
1231
+ * @summary run the adapter test scripts (baseunit and unit) to return the results.
1232
+ * can not run integration as there can be implications with that.
1708
1233
  *
1709
- * @function getConfig
1710
- * @param {String} deviceName - the deviceName of the appliance. (required)
1711
- * @param {String} format - the desired format of the config. (optional)
1234
+ * @function iapRunAdapterTests
1712
1235
  *
1713
- * @param {configCallback} callback - callback function to return the result
1714
- * (appliance config) or the error
1236
+ * @return {Object} - containing the results of the baseunit and unit tests.
1715
1237
  */
1716
- getConfig(deviceName, format, callback) {
1717
- const meth = 'adapterBase-getConfig';
1238
+ iapRunAdapterTests(callback) {
1239
+ const meth = 'adapterBase-iapRunAdapterTests';
1718
1240
  const origin = `${this.id}-${meth}`;
1719
1241
  log.trace(origin);
1242
+ let basecommand = null;
1243
+ let command = null;
1720
1244
 
1721
- // make sure we are set up for device broker getConfig
1722
- if (!this.allProps.devicebroker || !this.allProps.devicebroker.getConfig || this.allProps.devicebroker.getConfig.length === 0 || !this.allProps.devicebroker.getConfig[0].path) {
1723
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Properties', ['devicebroker.getConfig.path'], null, null, null);
1724
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1725
- return callback(null, errorObj);
1726
- }
1245
+ if (fs.existsSync('package.json')) {
1246
+ const packageData = require('./package.json');
1727
1247
 
1728
- // verify the required fields have been provided
1729
- if (deviceName === undefined || deviceName === null || deviceName === '' || deviceName.length === 0) {
1730
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['deviceName'], null, null, null);
1731
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1732
- return callback(null, errorObj);
1733
- }
1248
+ // check if 'test', 'test:unit', 'test:integration' exists in package.json file
1249
+ if (!packageData.scripts || !packageData.scripts['test:baseunit'] || !packageData.scripts['test:unit']) {
1250
+ log.error('The required scripts do not exist in the package.json file');
1251
+ return callback(null, 'The required scripts do not exist in the package.json file');
1252
+ }
1734
1253
 
1735
- try {
1736
- // need to get the device so we can convert the deviceName to an id
1737
- // !! if we can do a lookup by name the getDevicesFiltered may not be necessary
1738
- const opts = {
1739
- filter: {
1740
- name: deviceName
1741
- }
1254
+ // run baseunit test
1255
+ basecommand = spawnSync('npm', ['run', 'test:baseunit'], { cwd: __dirname, encoding: 'utf-8' });
1256
+
1257
+ // analyze and format the response to baseunit
1258
+ const baseresult = {
1259
+ status: 'SUCCESS'
1742
1260
  };
1743
- return this.getDevicesFiltered(opts, (devs, ferr) => {
1744
- // if we received an error or their is no response on the results return an error
1745
- if (ferr) {
1746
- return callback(null, ferr);
1747
- }
1748
- if (devs.list.length < 1) {
1749
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Did Not Find Device ${deviceName}`, [], null, null, null);
1750
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1751
- return callback(null, errorObj);
1752
- }
1261
+ if (basecommand.status !== 0) {
1262
+ baseresult.status = 'FAILED';
1263
+ baseresult.output = basecommand.stdout;
1264
+ }
1753
1265
 
1754
- const callPromises = [];
1755
- for (let i = 0; i < this.allProps.devicebroker.getConfig.length; i += 1) {
1756
- // Perform component calls here.
1757
- callPromises.push(
1758
- new Promise((resolve, reject) => {
1759
- this.iapMakeBrokerCall('getConfig', this.allProps.devicebroker.getConfig[i], [devs.list[0]], null, (callRet, callErr) => {
1760
- // return an error
1761
- if (callErr) {
1762
- reject(callErr);
1763
- } else {
1764
- // return the data
1765
- resolve(callRet);
1766
- }
1767
- });
1768
- })
1769
- );
1770
- }
1266
+ // run unit test
1267
+ command = spawnSync('npm', ['run', 'test:unit'], { cwd: __dirname, encoding: 'utf-8' });
1771
1268
 
1772
- // return an array of repsonses
1773
- return Promise.all(callPromises).then((results) => {
1774
- let myResult = {};
1775
- results.forEach((result) => {
1776
- if (typeof result === 'string') {
1777
- myResult = { ...myResult, result };
1778
- } else if (Array.isArray(result)) {
1779
- myResult = result[0];
1780
- } else {
1781
- myResult = { ...myResult, ...result };
1782
- }
1783
- });
1269
+ // analyze and format the response to unit
1270
+ const unitresult = {
1271
+ status: 'SUCCESS'
1272
+ };
1273
+ if (command.status !== 0) {
1274
+ unitresult.status = 'FAILED';
1275
+ unitresult.output = command.stdout;
1276
+ }
1784
1277
 
1785
- // return the result
1786
- const newResponse = {
1787
- response: JSON.stringify(myResult, null, 2)
1788
- };
1789
- return callback(newResponse, null);
1790
- });
1791
- });
1792
- } catch (ex) {
1793
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
1794
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1795
- return callback(null, errorObj);
1278
+ // format the response and return it
1279
+ const result = {
1280
+ base: baseresult,
1281
+ unit: unitresult
1282
+ };
1283
+ return callback(result);
1796
1284
  }
1285
+
1286
+ log.error('Package Not Found');
1287
+ return callback(null, 'Package Not Found');
1797
1288
  }
1798
1289
 
1799
1290
  /**
1800
- * @summary Gets the device count from the system
1291
+ * @summary provide inventory information abbout the adapter
1801
1292
  *
1802
- * @function iapGetDeviceCount
1293
+ * @function iapGetAdapterInventory
1803
1294
  *
1804
- * @param {getCallback} callback - callback function to return the result
1805
- * (count) or the error
1295
+ * @return {Object} - containing the adapter inventory information
1806
1296
  */
1807
- iapGetDeviceCount(callback) {
1808
- const meth = 'adapterBase-iapGetDeviceCount';
1297
+ iapGetAdapterInventory(callback) {
1298
+ const meth = 'adapterBase-iapGetAdapterInventory';
1809
1299
  const origin = `${this.id}-${meth}`;
1810
1300
  log.trace(origin);
1811
1301
 
1812
- // make sure we are set up for device broker getCount
1813
- if (!this.allProps.devicebroker || !this.allProps.devicebroker.getCount || this.allProps.devicebroker.getCount.length === 0 || !this.allProps.devicebroker.getCount[0].path) {
1814
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Properties', ['devicebroker.getCount.path'], null, null, null);
1815
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1816
- return callback(null, errorObj);
1817
- }
1818
-
1819
- // verify the required fields have been provided
1820
-
1821
1302
  try {
1822
- const callPromises = [];
1823
- for (let i = 0; i < this.allProps.devicebroker.getCount.length; i += 1) {
1824
- // Perform component calls here.
1825
- callPromises.push(
1826
- new Promise((resolve, reject) => {
1827
- this.iapMakeBrokerCall('getCount', this.allProps.devicebroker.getCount[i], [{ fake: 'fakedata' }], null, (callRet, callErr) => {
1828
- // return an error
1829
- if (callErr) {
1830
- reject(callErr);
1831
- } else {
1832
- // return the data
1833
- resolve(callRet);
1834
- }
1835
- });
1836
- })
1837
- );
1838
- }
1303
+ // call to the adapter utils to get inventory
1304
+ return this.requestHandlerInst.getAdapterInventory((res, error) => {
1305
+ const adapterInv = res;
1306
+
1307
+ // get all of the tasks
1308
+ const allTasks = this.getAllFunctions();
1309
+ adapterInv.totalTasks = allTasks.length;
1310
+
1311
+ // get all of the possible workflow tasks
1312
+ const myIgnore = [
1313
+ 'healthCheck',
1314
+ 'iapGetAdapterWorkflowFunctions',
1315
+ 'hasEntities'
1316
+ ];
1317
+ adapterInv.totalWorkflowTasks = this.iapGetAdapterWorkflowFunctions(myIgnore).length;
1318
+
1319
+ // TODO: CACHE
1320
+ // CONFIRM CACHE
1321
+ // GET CACHE ENTITIES
1322
+
1323
+ // get the Device Count
1324
+ return this.iapGetDeviceCount((devres, deverror) => {
1325
+ // if call failed assume not broker integrated
1326
+ if (deverror) {
1327
+ adapterInv.brokerDefined = false;
1328
+ adapterInv.deviceCount = -1;
1329
+ } else {
1330
+ // broker confirmed
1331
+ adapterInv.brokerDefined = true;
1332
+ adapterInv.deviceCount = 0;
1333
+ if (devres && devres.count) {
1334
+ adapterInv.deviceCount = devres.count;
1335
+ }
1336
+ }
1839
1337
 
1840
- // return an array of repsonses
1841
- return Promise.all(callPromises).then((results) => {
1842
- let myResult = {};
1843
- results.forEach((result) => {
1844
- myResult = { ...myResult, ...result };
1338
+ return callback(adapterInv);
1845
1339
  });
1846
-
1847
- // return the result
1848
- return callback({ count: Object.keys(myResult).length });
1849
1340
  });
1850
1341
  } catch (ex) {
1851
1342
  const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);