@itentialopensource/adapter-meraki 0.8.0 → 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
package/adapterBase.js CHANGED
@@ -8,6 +8,7 @@
8
8
  /* eslint no-cond-assign: warn */
9
9
  /* eslint global-require: warn */
10
10
  /* eslint no-unused-vars: warn */
11
+ /* eslint prefer-destructuring: warn */
11
12
 
12
13
  /* Required libraries. */
13
14
  const fs = require('fs-extra');
@@ -143,6 +144,44 @@ function updatePackage(changes) {
143
144
  return null;
144
145
  }
145
146
 
147
+ /*
148
+ * INTERNAL FUNCTION: get data from source(s) - nested
149
+ */
150
+ function getDataFromSources(loopField, sources) {
151
+ const loopArray = loopField.split('.');
152
+ let fieldValue = loopField;
153
+
154
+ // go through the sources to find the field
155
+ for (let s = 0; s < sources.length; s += 1) {
156
+ let nestedValue = sources[s];
157
+ let found = false;
158
+
159
+ // loops through incase the field is nested
160
+ for (let i = 0; i < loopArray.length; i += 1) {
161
+ // if not nested finds it first pass - otherwise set to new level and loop
162
+ if (Object.hasOwnProperty.call(nestedValue, loopArray[i])) {
163
+ nestedValue = nestedValue[loopArray[i]];
164
+
165
+ // set found if we are at the leaf (going to stop looping)
166
+ if (i + 1 === loopArray.length) {
167
+ found = true;
168
+ }
169
+ } else {
170
+ // not found in source - check next one
171
+ break;
172
+ }
173
+ }
174
+
175
+ // if we found in source - set and no need to check other sources
176
+ if (found) {
177
+ fieldValue = nestedValue;
178
+ break;
179
+ }
180
+ }
181
+
182
+ return fieldValue;
183
+ }
184
+
146
185
  /* GENERAL ADAPTER FUNCTIONS THESE SHOULD NOT BE DIRECTLY MODIFIED */
147
186
  /* IF YOU NEED MODIFICATIONS, REDEFINE THEM IN adapter.js!!! */
148
187
  class AdapterBase extends EventEmitterCl {
@@ -154,6 +193,9 @@ class AdapterBase extends EventEmitterCl {
154
193
  // Instantiate the EventEmitter super class
155
194
  super();
156
195
 
196
+ // IAP home directory injected by core when running the adapter within IAP
197
+ process.env.iap_home = process.argv[3];
198
+
157
199
  try {
158
200
  // Capture the adapter id
159
201
  this.id = prongid;
@@ -277,129 +319,6 @@ class AdapterBase extends EventEmitterCl {
277
319
  }
278
320
  }
279
321
 
280
- /**
281
- * updateAdapterConfiguration is used to update any of the adapter configuration files. This
282
- * allows customers to make changes to adapter configuration without having to be on the
283
- * file system.
284
- *
285
- * @function updateAdapterConfiguration
286
- * @param {string} configFile - the name of the file being updated (required)
287
- * @param {Object} changes - an object containing all of the changes = formatted like the configuration file (required)
288
- * @param {string} entity - the entity to be changed, if an action, schema or mock data file (optional)
289
- * @param {string} type - the type of entity file to change, (action, schema, mock) (optional)
290
- * @param {string} action - the action to be changed, if an action, schema or mock data file (optional)
291
- * @param {Callback} callback - The results of the call
292
- */
293
- updateAdapterConfiguration(configFile, changes, entity, type, action, callback) {
294
- const meth = 'adapterBase-updateAdapterConfiguration';
295
- const origin = `${this.id}-${meth}`;
296
- log.trace(origin);
297
-
298
- // verify the parameters are valid
299
- if (changes === undefined || changes === null || typeof changes !== 'object'
300
- || Object.keys(changes).length === 0) {
301
- const result = {
302
- response: 'No configuration updates to make'
303
- };
304
- log.info(result.response);
305
- return callback(result, null);
306
- }
307
- if (configFile === undefined || configFile === null || configFile === '') {
308
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['configFile'], null, null, null);
309
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
310
- return callback(null, errorObj);
311
- }
312
-
313
- // take action based on configFile being changed
314
- if (configFile === 'package.json') {
315
- const pres = updatePackage(changes);
316
- if (pres) {
317
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: ${pres}`, [], null, null, null);
318
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
319
- return callback(null, errorObj);
320
- }
321
- const result = {
322
- response: 'Package updates completed - restarting adapter'
323
- };
324
- log.info(result.response);
325
- forceFail(true);
326
- return callback(result, null);
327
- }
328
- if (entity === undefined || entity === null || entity === '') {
329
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Unsupported Configuration Change or Missing Entity', [], null, null, null);
330
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
331
- return callback(null, errorObj);
332
- }
333
-
334
- // this means we are changing an entity file so type is required
335
- if (type === undefined || type === null || type === '') {
336
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['type'], null, null, null);
337
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
338
- return callback(null, errorObj);
339
- }
340
-
341
- // if the entity does not exist - error
342
- const epath = `${__dirname}/entities/${entity}`;
343
- if (!fs.existsSync(epath)) {
344
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: Invalid Entity - ${entity}`, [], null, null, null);
345
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
346
- return callback(null, errorObj);
347
- }
348
-
349
- // take action based on type of file being changed
350
- if (type === 'action') {
351
- // BACKUP???
352
- const ares = updateAction(epath, action, changes);
353
- if (ares) {
354
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: ${ares}`, [], null, null, null);
355
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
356
- return callback(null, errorObj);
357
- }
358
- // AJV CHECK???
359
- // RESTORE IF NEEDED???
360
- const result = {
361
- response: `Action updates completed to entity: ${entity} - ${action}`
362
- };
363
- log.info(result.response);
364
- return callback(result, null);
365
- }
366
- if (type === 'schema') {
367
- const sres = updateSchema(epath, configFile, changes);
368
- if (sres) {
369
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: ${sres}`, [], null, null, null);
370
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
371
- return callback(null, errorObj);
372
- }
373
- const result = {
374
- response: `Schema updates completed to entity: ${entity} - ${configFile}`
375
- };
376
- log.info(result.response);
377
- return callback(result, null);
378
- }
379
- if (type === 'mock') {
380
- // if the mock directory does not exist - error
381
- const mpath = `${__dirname}/entities/${entity}/mockdatafiles`;
382
- if (!fs.existsSync(mpath)) {
383
- fs.mkdirSync(mpath);
384
- }
385
-
386
- const mres = updateMock(mpath, configFile, changes);
387
- if (mres) {
388
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: ${mres}`, [], null, null, null);
389
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
390
- return callback(null, errorObj);
391
- }
392
- const result = {
393
- response: `Mock data updates completed to entity: ${entity} - ${configFile}`
394
- };
395
- log.info(result.response);
396
- return callback(result, null);
397
- }
398
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: Unsupported Type - ${type}`, [], null, null, null);
399
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
400
- return callback(null, errorObj);
401
- }
402
-
403
322
  /**
404
323
  * @summary Connect function is used during Pronghorn startup to provide instantiation feedback.
405
324
  *
@@ -468,7 +387,7 @@ class AdapterBase extends EventEmitterCl {
468
387
  }
469
388
 
470
389
  // call to the healthcheck in connector
471
- return this.requestHandlerInst.identifyHealthcheck(reqObj, (res, error) => {
390
+ return this.requestHandlerInst.identifyHealthcheck(myRequest, (res, error) => {
472
391
  // unhealthy
473
392
  if (error) {
474
393
  // if we were healthy, toggle health
@@ -500,68 +419,6 @@ class AdapterBase extends EventEmitterCl {
500
419
  });
501
420
  }
502
421
 
503
- /**
504
- * @summary Suspends the adapter
505
- * @param {Callback} callback - The adapater suspension status
506
- * @function suspend
507
- */
508
- suspend(mode, callback) {
509
- const origin = `${this.id}-adapterBase-suspend`;
510
- if (this.suspended) {
511
- throw new Error(`${origin}: Adapter is already suspended`);
512
- }
513
- try {
514
- this.suspended = true;
515
- this.suspendMode = mode;
516
- if (this.suspendMode === 'pause') {
517
- const props = JSON.parse(JSON.stringify(this.initProps));
518
- // To suspend adapter, enable throttling and set concurrent max to 0
519
- props.throttle.throttle_enabled = true;
520
- props.throttle.concurrent_max = 0;
521
- this.refreshProperties(props);
522
- }
523
- return callback({ suspended: true });
524
- } catch (error) {
525
- return callback(null, error);
526
- }
527
- }
528
-
529
- /**
530
- * @summary Unsuspends the adapter
531
- * @param {Callback} callback - The adapater suspension status
532
- *
533
- * @function unsuspend
534
- */
535
- unsuspend(callback) {
536
- const origin = `${this.id}-adapterBase-unsuspend`;
537
- if (!this.suspended) {
538
- throw new Error(`${origin}: Adapter is not suspended`);
539
- }
540
- if (this.suspendMode === 'pause') {
541
- const props = JSON.parse(JSON.stringify(this.initProps));
542
- // To unsuspend adapter, keep throttling enabled and begin processing queued requests in order
543
- props.throttle.throttle_enabled = true;
544
- props.throttle.concurrent_max = 1;
545
- this.refreshProperties(props);
546
- setTimeout(() => {
547
- this.getQueue((q, error) => {
548
- // console.log("Items in queue: " + String(q.length))
549
- if (q.length === 0) {
550
- // if queue is empty, return to initial properties state
551
- this.refreshProperties(this.initProps);
552
- this.suspended = false;
553
- return callback({ suspended: false });
554
- }
555
- // recursive call to check queue again every second
556
- return this.unsuspend(callback);
557
- });
558
- }, 1000);
559
- } else {
560
- this.suspended = false;
561
- callback({ suspend: false });
562
- }
563
- }
564
-
565
422
  /**
566
423
  * getAllFunctions is used to get all of the exposed function in the adapter
567
424
  *
@@ -587,12 +444,67 @@ class AdapterBase extends EventEmitterCl {
587
444
  }
588
445
 
589
446
  /**
590
- * getWorkflowFunctions is used to get all of the workflow function in the adapter
447
+ * checkActionFiles is used to update the validation of the action files.
448
+ *
449
+ * @function checkActionFiles
450
+ */
451
+ checkActionFiles() {
452
+ const origin = `${this.id}-adapterBase-checkActionFiles`;
453
+ log.trace(origin);
454
+
455
+ // validate the action files for the adapter
456
+ try {
457
+ return this.requestHandlerInst.checkActionFiles();
458
+ } catch (e) {
459
+ return ['Exception increase log level'];
460
+ }
461
+ }
462
+
463
+ /**
464
+ * checkProperties is used to validate the adapter properties.
465
+ *
466
+ * @function checkProperties
467
+ * @param {Object} properties - an object containing all of the properties
468
+ */
469
+ checkProperties(properties) {
470
+ const origin = `${this.myid}-adapterBase-checkProperties`;
471
+ log.trace(origin);
472
+
473
+ // validate the properties for the adapter
474
+ try {
475
+ return this.requestHandlerInst.checkProperties(properties);
476
+ } catch (e) {
477
+ return { exception: 'Exception increase log level' };
478
+ }
479
+ }
480
+
481
+ /**
482
+ * @summary Takes in property text and an encoding/encryption and returns the resulting
483
+ * encoded/encrypted string
484
+ *
485
+ * @function encryptProperty
486
+ * @param {String} property - the property to encrypt
487
+ * @param {String} technique - the technique to use to encrypt
488
+ *
489
+ * @param {Callback} callback - a callback function to return the result
490
+ * Encrypted String or the Error
491
+ */
492
+ encryptProperty(property, technique, callback) {
493
+ const origin = `${this.id}-adapterBase-encryptProperty`;
494
+ log.trace(origin);
495
+
496
+ // Make the call -
497
+ // encryptProperty(property, technique, callback)
498
+ return this.requestHandlerInst.encryptProperty(property, technique, callback);
499
+ }
500
+
501
+ /**
502
+ * iapGetAdapterWorkflowFunctions is used to get all of the workflow function in the adapter
591
503
  * @param {array} ignoreThese - additional methods to ignore (optional)
592
504
  *
593
- * @function getWorkflowFunctions
505
+ * @function iapGetAdapterWorkflowFunctions
594
506
  */
595
- getWorkflowFunctions(ignoreThese) {
507
+ iapGetAdapterWorkflowFunctions(ignoreThese) {
596
508
  const myfunctions = this.getAllFunctions();
597
509
  const wffunctions = [];
598
510
 
@@ -602,9 +514,7 @@ class AdapterBase extends EventEmitterCl {
602
514
  // got to the second tier (adapterBase)
603
515
  break;
604
516
  }
605
- if (myfunctions[m] !== 'hasEntity' && myfunctions[m] !== 'verifyCapability' && myfunctions[m] !== 'updateEntityCache'
606
- && myfunctions[m] !== 'healthCheck' && myfunctions[m] !== 'getWorkflowFunctions'
607
- && !(myfunctions[m].endsWith('Emit') || myfunctions[m].match(/Emit__v[0-9]+/))) {
517
+ if (!(myfunctions[m].endsWith('Emit') || myfunctions[m].match(/Emit__v[0-9]+/))) {
608
518
  let found = false;
609
519
  if (ignoreThese && Array.isArray(ignoreThese)) {
610
520
  for (let i = 0; i < ignoreThese.length; i += 1) {
@@ -623,30 +533,136 @@ class AdapterBase extends EventEmitterCl {
623
533
  }
624
534
 
625
535
  /**
626
- * checkActionFiles is used to update the validation of the action files.
536
+ * iapUpdateAdapterConfiguration is used to update any of the adapter configuration files. This
537
+ * allows customers to make changes to adapter configuration without having to be on the
538
+ * file system.
627
539
  *
628
- * @function checkActionFiles
540
+ * @function iapUpdateAdapterConfiguration
541
+ * @param {string} configFile - the name of the file being updated (required)
542
+ * @param {Object} changes - an object containing all of the changes = formatted like the configuration file (required)
543
+ * @param {string} entity - the entity to be changed, if an action, schema or mock data file (optional)
544
+ * @param {string} type - the type of entity file to change, (action, schema, mock) (optional)
545
+ * @param {string} action - the action to be changed, if an action, schema or mock data file (optional)
546
+ * @param {Callback} callback - The results of the call
629
547
  */
630
- checkActionFiles() {
631
- const origin = `${this.id}-adapterBase-checkActionFiles`;
548
+ iapUpdateAdapterConfiguration(configFile, changes, entity, type, action, callback) {
549
+ const meth = 'adapterBase-iapUpdateAdapterConfiguration';
550
+ const origin = `${this.id}-${meth}`;
632
551
  log.trace(origin);
633
552
 
634
- // validate the action files for the adapter
635
- try {
636
- return this.requestHandlerInst.checkActionFiles();
637
- } catch (e) {
638
- return ['Exception increase log level'];
553
+ // verify the parameters are valid
554
+ if (changes === undefined || changes === null || typeof changes !== 'object'
555
+ || Object.keys(changes).length === 0) {
556
+ const result = {
557
+ response: 'No configuration updates to make'
558
+ };
559
+ log.info(result.response);
560
+ return callback(result, null);
561
+ }
562
+ if (configFile === undefined || configFile === null || configFile === '') {
563
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['configFile'], null, null, null);
564
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
565
+ return callback(null, errorObj);
566
+ }
567
+
568
+ // take action based on configFile being changed
569
+ if (configFile === 'package.json') {
570
+ const pres = updatePackage(changes);
571
+ if (pres) {
572
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: ${pres}`, [], null, null, null);
573
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
574
+ return callback(null, errorObj);
575
+ }
576
+ const result = {
577
+ response: 'Package updates completed - restarting adapter'
578
+ };
579
+ log.info(result.response);
580
+ forceFail(true);
581
+ return callback(result, null);
582
+ }
583
+ if (entity === undefined || entity === null || entity === '') {
584
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Unsupported Configuration Change or Missing Entity', [], null, null, null);
585
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
586
+ return callback(null, errorObj);
587
+ }
588
+
589
+ // this means we are changing an entity file so type is required
590
+ if (type === undefined || type === null || type === '') {
591
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['type'], null, null, null);
592
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
593
+ return callback(null, errorObj);
594
+ }
595
+
596
+ // if the entity does not exist - error
597
+ const epath = `${__dirname}/entities/${entity}`;
598
+ if (!fs.existsSync(epath)) {
599
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: Invalid Entity - ${entity}`, [], null, null, null);
600
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
601
+ return callback(null, errorObj);
602
+ }
603
+
604
+ // take action based on type of file being changed
605
+ if (type === 'action') {
606
+ // BACKUP???
607
+ const ares = updateAction(epath, action, changes);
608
+ if (ares) {
609
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: ${ares}`, [], null, null, null);
610
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
611
+ return callback(null, errorObj);
612
+ }
613
+ // AJV CHECK???
614
+ // RESTORE IF NEEDED???
615
+ const result = {
616
+ response: `Action updates completed to entity: ${entity} - ${action}`
617
+ };
618
+ log.info(result.response);
619
+ return callback(result, null);
620
+ }
621
+ if (type === 'schema') {
622
+ const sres = updateSchema(epath, configFile, changes);
623
+ if (sres) {
624
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: ${sres}`, [], null, null, null);
625
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
626
+ return callback(null, errorObj);
627
+ }
628
+ const result = {
629
+ response: `Schema updates completed to entity: ${entity} - ${configFile}`
630
+ };
631
+ log.info(result.response);
632
+ return callback(result, null);
633
+ }
634
+ if (type === 'mock') {
635
+ // if the mock directory does not exist - error
636
+ const mpath = `${__dirname}/entities/${entity}/mockdatafiles`;
637
+ if (!fs.existsSync(mpath)) {
638
+ fs.mkdirSync(mpath);
639
+ }
640
+
641
+ const mres = updateMock(mpath, configFile, changes);
642
+ if (mres) {
643
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: ${mres}`, [], null, null, null);
644
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
645
+ return callback(null, errorObj);
646
+ }
647
+ const result = {
648
+ response: `Mock data updates completed to entity: ${entity} - ${configFile}`
649
+ };
650
+ log.info(result.response);
651
+ return callback(result, null);
639
652
  }
653
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Incomplete Configuration Change: Unsupported Type - ${type}`, [], null, null, null);
654
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
655
+ return callback(null, errorObj);
640
656
  }
641
657
 
642
658
  /**
643
659
  * See if the API path provided is found in this adapter
644
660
  *
645
- * @function findPath
661
+ * @function iapFindAdapterPath
646
662
  * @param {string} apiPath - the api path to check on
647
663
  * @param {Callback} callback - The results of the call
648
664
  */
649
- findPath(apiPath, callback) {
665
+ iapFindAdapterPath(apiPath, callback) {
650
666
  const result = {
651
667
  apiPath
652
668
  };
@@ -723,66 +739,90 @@ class AdapterBase extends EventEmitterCl {
723
739
  }
724
740
 
725
741
  /**
726
- * checkProperties is used to validate the adapter properties.
727
- *
728
- * @function checkProperties
729
- * @param {Object} properties - an object containing all of the properties
742
+ * @summary Suspends the adapter
743
+ * @param {Callback} callback - The adapater suspension status
744
+ * @function iapSuspendAdapter
730
745
  */
731
- checkProperties(properties) {
732
- const origin = `${this.myid}-adapterBase-checkProperties`;
733
- log.trace(origin);
734
-
735
- // validate the properties for the adapter
746
+ iapSuspendAdapter(mode, callback) {
747
+ const origin = `${this.id}-adapterBase-iapSuspendAdapter`;
748
+ if (this.suspended) {
749
+ throw new Error(`${origin}: Adapter is already suspended`);
750
+ }
736
751
  try {
737
- return this.requestHandlerInst.checkProperties(properties);
738
- } catch (e) {
739
- return { exception: 'Exception increase log level' };
752
+ this.suspended = true;
753
+ this.suspendMode = mode;
754
+ if (this.suspendMode === 'pause') {
755
+ const props = JSON.parse(JSON.stringify(this.initProps));
756
+ // To suspend adapter, enable throttling and set concurrent max to 0
757
+ props.throttle.throttle_enabled = true;
758
+ props.throttle.concurrent_max = 0;
759
+ this.refreshProperties(props);
760
+ }
761
+ return callback({ suspended: true });
762
+ } catch (error) {
763
+ return callback(null, error);
740
764
  }
741
765
  }
742
766
 
743
767
  /**
744
- * getQueue is used to get information for all of the requests currently in the queue.
768
+ * @summary Unsuspends the adapter
769
+ * @param {Callback} callback - The adapater suspension status
745
770
  *
746
- * @function getQueue
747
- * @param {Callback} callback - a callback function to return the result (Queue) or the error
771
+ * @function iapUnsuspendAdapter
748
772
  */
749
- getQueue(callback) {
750
- const origin = `${this.id}-adapterBase-getQueue`;
751
- log.trace(origin);
752
-
753
- return this.requestHandlerInst.getQueue(callback);
773
+ iapUnsuspendAdapter(callback) {
774
+ const origin = `${this.id}-adapterBase-iapUnsuspendAdapter`;
775
+ if (!this.suspended) {
776
+ throw new Error(`${origin}: Adapter is not suspended`);
777
+ }
778
+ if (this.suspendMode === 'pause') {
779
+ const props = JSON.parse(JSON.stringify(this.initProps));
780
+ // To unsuspend adapter, keep throttling enabled and begin processing queued requests in order
781
+ props.throttle.throttle_enabled = true;
782
+ props.throttle.concurrent_max = 1;
783
+ this.refreshProperties(props);
784
+ setTimeout(() => {
785
+ this.getQueue((q, error) => {
786
+ // console.log("Items in queue: " + String(q.length))
787
+ if (q.length === 0) {
788
+ // if queue is empty, return to initial properties state
789
+ this.refreshProperties(this.initProps);
790
+ this.suspended = false;
791
+ return callback({ suspended: false });
792
+ }
793
+ // recursive call to check queue again every second
794
+ return this.iapUnsuspendAdapter(callback);
795
+ });
796
+ }, 1000);
797
+ } else {
798
+ this.suspended = false;
799
+ callback({ suspend: false });
800
+ }
754
801
  }
755
802
 
756
803
  /**
757
- * @summary Takes in property text and an encoding/encryption and returns the resulting
758
- * encoded/encrypted string
804
+ * iapGetAdapterQueue is used to get information for all of the requests currently in the queue.
759
805
  *
760
- * @function encryptProperty
761
- * @param {String} property - the property to encrypt
762
- * @param {String} technique - the technique to use to encrypt
763
- *
764
- * @param {Callback} callback - a callback function to return the result
765
- * Encrypted String or the Error
806
+ * @function iapGetAdapterQueue
807
+ * @param {Callback} callback - a callback function to return the result (Queue) or the error
766
808
  */
767
- encryptProperty(property, technique, callback) {
768
- const origin = `${this.id}-adapterBase-encryptProperty`;
809
+ iapGetAdapterQueue(callback) {
810
+ const origin = `${this.id}-adapterBase-iapGetAdapterQueue`;
769
811
  log.trace(origin);
770
812
 
771
- // Make the call -
772
- // encryptProperty(property, technique, callback)
773
- return this.requestHandlerInst.encryptProperty(property, technique, callback);
813
+ return this.requestHandlerInst.getQueue(callback);
774
814
  }
775
815
 
776
816
  /**
777
817
  * @summary runs troubleshoot scripts for adapter
778
818
  *
779
- * @function troubleshoot
819
+ * @function iapTroubleshootAdapter
780
820
  * @param {Object} props - the connection, healthcheck and authentication properties
781
821
  * @param {boolean} persistFlag - whether the adapter properties should be updated
782
822
  * @param {Adapter} adapter - adapter instance to troubleshoot
783
823
  * @param {Callback} callback - callback function to return troubleshoot results
784
824
  */
785
- async troubleshoot(props, persistFlag, adapter, callback) {
825
+ async iapTroubleshootAdapter(props, persistFlag, adapter, callback) {
786
826
  try {
787
827
  const result = await troubleshootingAdapter.troubleshoot(props, false, persistFlag, adapter);
788
828
  if (result.healthCheck && result.connectivity.failCount === 0 && result.basicGet.failCount === 0) {
@@ -797,11 +837,11 @@ class AdapterBase extends EventEmitterCl {
797
837
  /**
798
838
  * @summary runs healthcheck script for adapter
799
839
  *
800
- * @function runHealthcheck
840
+ * @function iapRunAdapterHealthcheck
801
841
  * @param {Adapter} adapter - adapter instance to troubleshoot
802
842
  * @param {Callback} callback - callback function to return healthcheck status
803
843
  */
804
- async runHealthcheck(adapter, callback) {
844
+ async iapRunAdapterHealthcheck(adapter, callback) {
805
845
  try {
806
846
  const result = await tbUtils.healthCheck(adapter);
807
847
  if (result) {
@@ -816,11 +856,11 @@ class AdapterBase extends EventEmitterCl {
816
856
  /**
817
857
  * @summary runs connectivity check script for adapter
818
858
  *
819
- * @function runConnectivity
859
+ * @function iapRunAdapterConnectivity
820
860
  * @param {Adapter} adapter - adapter instance to troubleshoot
821
861
  * @param {Callback} callback - callback function to return connectivity status
822
862
  */
823
- async runConnectivity(callback) {
863
+ async iapRunAdapterConnectivity(callback) {
824
864
  try {
825
865
  const { serviceItem } = await tbUtils.getAdapterConfig();
826
866
  const { host } = serviceItem.properties.properties;
@@ -837,10 +877,10 @@ class AdapterBase extends EventEmitterCl {
837
877
  /**
838
878
  * @summary runs basicGet script for adapter
839
879
  *
840
- * @function runBasicGet
880
+ * @function iapRunAdapterBasicGet
841
881
  * @param {Callback} callback - callback function to return basicGet result
842
882
  */
843
- runBasicGet(callback) {
883
+ iapRunAdapterBasicGet(callback) {
844
884
  try {
845
885
  const result = tbUtils.runBasicGet(false);
846
886
  if (result.failCount > 0) {
@@ -852,6 +892,27 @@ class AdapterBase extends EventEmitterCl {
852
892
  }
853
893
  }
854
894
 
895
+ /**
896
+ * @summary moves entities to mongo database
897
+ *
898
+ * @function iapMoveAdapterEntitiesToDB
899
+ *
900
+ * @return {Callback} - containing the response from the mongo transaction
901
+ */
902
+ iapMoveAdapterEntitiesToDB(callback) {
903
+ const meth = 'adapterBase-iapMoveAdapterEntitiesToDB';
904
+ const origin = `${this.id}-${meth}`;
905
+ log.trace(origin);
906
+
907
+ try {
908
+ return callback(entitiesToDB.iapMoveAdapterEntitiesToDB(__dirname, { pronghornProps: this.allProps, id: this.id }), null);
909
+ } catch (err) {
910
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, err);
911
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
912
+ return callback(null, errorObj);
913
+ }
914
+ }
915
+
855
916
  /**
856
917
  * @summary take the entities and add them to the cache
857
918
  *
@@ -1004,21 +1065,681 @@ class AdapterBase extends EventEmitterCl {
1004
1065
  }
1005
1066
 
1006
1067
  /**
1007
- * @summary moves entities to mongo database
1068
+ * @summary Determines if this adapter supports any in a list of entities
1008
1069
  *
1009
- * @function moveEntitiesToDB
1070
+ * @function hasEntities
1071
+ * @param {String} entityType - the entity type to check for
1072
+ * @param {Array} entityList - the list of entities we are looking for
1010
1073
  *
1011
- * @return {Callback} - containing the response from the mongo transaction
1074
+ * @param {Callback} callback - A map where the entity is the key and the
1075
+ * value is true or false
1076
+ */
1077
+ hasEntities(entityType, entityList, callback) {
1078
+ const origin = `${this.id}-adapter-hasEntities`;
1079
+ log.trace(origin);
1080
+
1081
+ switch (entityType) {
1082
+ case 'Device':
1083
+ return this.hasDevices(entityList, callback);
1084
+ default:
1085
+ return callback(null, `${this.id} does not support entity ${entityType}`);
1086
+ }
1087
+ }
1088
+
1089
+ /**
1090
+ * @summary Helper method for hasEntities for the specific device case
1091
+ *
1092
+ * @param {Array} deviceList - array of unique device identifiers
1093
+ * @param {Callback} callback - A map where the device is the key and the
1094
+ * value is true or false
1095
+ */
1096
+ hasDevices(deviceList, callback) {
1097
+ const origin = `${this.id}-adapter-hasDevices`;
1098
+ log.trace(origin);
1099
+
1100
+ const findings = deviceList.reduce((map, device) => {
1101
+ // eslint-disable-next-line no-param-reassign
1102
+ map[device] = false;
1103
+ log.debug(`In reduce: ${JSON.stringify(map)}`);
1104
+ return map;
1105
+ }, {});
1106
+ const apiCalls = deviceList.map((device) => new Promise((resolve) => {
1107
+ this.getDevice(device, (result, error) => {
1108
+ if (error) {
1109
+ log.debug(`In map error: ${JSON.stringify(device)}`);
1110
+ return resolve({ name: device, found: false });
1111
+ }
1112
+ log.debug(`In map: ${JSON.stringify(device)}`);
1113
+ return resolve({ name: device, found: true });
1114
+ });
1115
+ }));
1116
+ Promise.all(apiCalls).then((results) => {
1117
+ results.forEach((device) => {
1118
+ findings[device.name] = device.found;
1119
+ });
1120
+ log.debug(`FINDINGS: ${JSON.stringify(findings)}`);
1121
+ return callback(findings);
1122
+ }).catch((errors) => {
1123
+ log.error('Unable to do device lookup.');
1124
+ return callback(null, { code: 503, message: 'Unable to do device lookup.', error: errors });
1125
+ });
1126
+ }
1127
+
1128
+ /**
1129
+ * @summary Make one of the needed Broker calls - could be one of many
1130
+ *
1131
+ * @function iapMakeBrokerCall
1132
+ * @param {string} brokCall - the name of the broker call (required)
1133
+ * @param {object} callProps - the proeprties for the broker call (required)
1134
+ * @param {object} devResp - the device details to extract needed inputs (required)
1135
+ * @param {string} filterName - any filter to search on (required)
1136
+ *
1137
+ * @param {getCallback} callback - a callback function to return the result of the call
1012
1138
  */
1013
- moveEntitiesToDB(callback) {
1014
- const meth = 'adapterBase-moveEntitiesToDB';
1139
+ iapMakeBrokerCall(brokCall, callProps, devResp, filterName, callback) {
1140
+ const meth = 'adapterBase-iapMakeBrokerCall';
1015
1141
  const origin = `${this.id}-${meth}`;
1016
1142
  log.trace(origin);
1017
1143
 
1018
1144
  try {
1019
- return callback(entitiesToDB.moveEntitiesToDB(__dirname, { pronghornProps: this.allProps, id: this.id }), null);
1020
- } catch (err) {
1021
- const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, err);
1145
+ let uriPath = '';
1146
+ let uriMethod = 'GET';
1147
+ let callQuery = {};
1148
+ let callBody = {};
1149
+ let callHeaders = {};
1150
+ let handleFail = 'fail';
1151
+ let ostypePrefix = '';
1152
+ let statusValue = 'true';
1153
+ if (callProps.path) {
1154
+ uriPath = `${callProps.path}`;
1155
+
1156
+ // make any necessary changes to the path
1157
+ if (devResp !== null && callProps.requestFields && Object.keys(callProps.requestFields).length > 0) {
1158
+ const rqKeys = Object.keys(callProps.requestFields);
1159
+
1160
+ // get the field from the provided device
1161
+ for (let rq = 0; rq < rqKeys.length; rq += 1) {
1162
+ const fieldValue = getDataFromSources(callProps.requestFields[rqKeys[rq]], devResp);
1163
+
1164
+ // put the value into the path - if it has been specified in the path
1165
+ uriPath = uriPath.replace(`{${rqKeys[rq]}}`, fieldValue);
1166
+ }
1167
+ }
1168
+ }
1169
+ if (callProps.method) {
1170
+ uriMethod = callProps.method;
1171
+ }
1172
+ if (callProps.query) {
1173
+ callQuery = callProps.query;
1174
+
1175
+ // go through the query params to check for variable values
1176
+ const cpKeys = Object.keys(callQuery);
1177
+ for (let cp = 0; cp < cpKeys.length; cp += 1) {
1178
+ if (callQuery[cpKeys[cp]].startsWith('{') && callQuery[cpKeys[cp]].endsWith('}')) {
1179
+ // make any necessary changes to the query params
1180
+ if (devResp !== null && callProps.requestFields && Object.keys(callProps.requestFields).length > 0) {
1181
+ const rqKeys = Object.keys(callProps.requestFields);
1182
+
1183
+ // get the field from the provided device
1184
+ for (let rq = 0; rq < rqKeys.length; rq += 1) {
1185
+ if (cpKeys[cp] === rqKeys[rq]) {
1186
+ const fieldValue = getDataFromSources(callProps.requestFields[rqKeys[rq]], devResp);
1187
+
1188
+ // put the value into the query - if it has been specified in the query
1189
+ callQuery[cpKeys[cp]] = fieldValue;
1190
+ }
1191
+ }
1192
+ }
1193
+ }
1194
+ }
1195
+ }
1196
+ if (callProps.body) {
1197
+ callBody = callProps.body;
1198
+ }
1199
+ if (callProps.headers) {
1200
+ callHeaders = callProps.headers;
1201
+ }
1202
+ if (callProps.handleFailure) {
1203
+ handleFail = callProps.handleFailure;
1204
+ }
1205
+ if (callProps.responseFields && callProps.responseFields.ostypePrefix) {
1206
+ ostypePrefix = callProps.responseFields.ostypePrefix;
1207
+ }
1208
+ if (callProps.responseFields && callProps.responseFields.statusValue) {
1209
+ statusValue = callProps.responseFields.statusValue;
1210
+ }
1211
+
1212
+ // !! using Generic makes it easier on the Adapter Builder (just need to change the path)
1213
+ // !! you can also replace with a specific call if that is easier
1214
+ return this.genericAdapterRequest(uriPath, uriMethod, callQuery, callBody, callHeaders, (result, error) => {
1215
+ // if we received an error or their is no response on the results return an error
1216
+ if (error) {
1217
+ if (handleFail === 'fail') {
1218
+ return callback(null, error);
1219
+ }
1220
+ return callback({}, null);
1221
+ }
1222
+ if (!result.response) {
1223
+ if (handleFail === 'fail') {
1224
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Invalid Response', [brokCall], null, null, null);
1225
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1226
+ return callback(null, errorObj);
1227
+ }
1228
+ return callback({}, null);
1229
+ }
1230
+
1231
+ // get the keys for the response fields
1232
+ let rfKeys = [];
1233
+ if (callProps.responseFields && Object.keys(callProps.responseFields).length > 0) {
1234
+ rfKeys = Object.keys(callProps.responseFields);
1235
+ }
1236
+
1237
+ // if we got an array returned (e.g. getDevicesFitered)
1238
+ if (Array.isArray(result.response)) {
1239
+ const listDevices = [];
1240
+ for (let a = 0; a < result.response.length; a += 1) {
1241
+ const thisDevice = result.response[a];
1242
+ for (let rf = 0; rf < rfKeys.length; rf += 1) {
1243
+ if (rfKeys[rf] !== 'ostypePrefix') {
1244
+ let fieldValue = getDataFromSources(callProps.responseFields[rfKeys[rf]], [thisDevice, devResp, callProps.requestFields]);
1245
+
1246
+ // if the field is ostype - need to add prefix
1247
+ if (rfKeys[rf] === 'ostype' && typeof fieldValue === 'string') {
1248
+ fieldValue = ostypePrefix + fieldValue;
1249
+ }
1250
+ // if there is a status to set, set it
1251
+ if (rfKeys[rf] === 'status') {
1252
+ // if really looking for just a good response
1253
+ if (callProps.responseFields[rfKeys[rf]] === 'return2xx' && result.icode === statusValue.toString()) {
1254
+ thisDevice.isAlive = true;
1255
+ } else if (fieldValue.toString() === statusValue.toString()) {
1256
+ thisDevice.isAlive = true;
1257
+ } else {
1258
+ thisDevice.isAlive = false;
1259
+ }
1260
+ }
1261
+ // if we found a good value
1262
+ thisDevice[rfKeys[rf]] = fieldValue;
1263
+ }
1264
+ }
1265
+
1266
+ // if there is no filter - add the device to the list
1267
+ if (!filterName || filterName.length === 0) {
1268
+ listDevices.push(thisDevice);
1269
+ } else {
1270
+ // if we have to match a filter
1271
+ let found = false;
1272
+ for (let f = 0; f < filterName.length; f += 1) {
1273
+ if (thisDevice.name.indexOf(filterName[f]) >= 0) {
1274
+ found = true;
1275
+ break;
1276
+ }
1277
+ }
1278
+ // matching device
1279
+ if (found) {
1280
+ listDevices.push(thisDevice);
1281
+ }
1282
+ }
1283
+ }
1284
+
1285
+ // return the array of devices
1286
+ return callback(listDevices, null);
1287
+ }
1288
+
1289
+ // if this is not an array - just about everything else, just handle as a single object
1290
+ let thisDevice = result.response;
1291
+ for (let rf = 0; rf < rfKeys.length; rf += 1) {
1292
+ // skip ostypePrefix since it is not a field
1293
+ if (rfKeys[rf] !== 'ostypePrefix') {
1294
+ let fieldValue = getDataFromSources(callProps.responseFields[rfKeys[rf]], [thisDevice, devResp, callProps.requestFields]);
1295
+
1296
+ // if the field is ostype - need to add prefix
1297
+ if (rfKeys[rf] === 'ostype' && typeof fieldValue === 'string') {
1298
+ fieldValue = ostypePrefix + fieldValue;
1299
+ }
1300
+ // if there is a status to set, set it
1301
+ if (rfKeys[rf] === 'status') {
1302
+ // if really looking for just a good response
1303
+ if (callProps.responseFields[rfKeys[rf]] === 'return2xx' && result.icode === statusValue.toString()) {
1304
+ thisDevice.isAlive = true;
1305
+ } else if (fieldValue.toString() === statusValue.toString()) {
1306
+ thisDevice.isAlive = true;
1307
+ } else {
1308
+ thisDevice.isAlive = false;
1309
+ }
1310
+ }
1311
+ // if we found a good value
1312
+ thisDevice[rfKeys[rf]] = fieldValue;
1313
+ }
1314
+ }
1315
+
1316
+ // if there is a filter - check the device is in the list
1317
+ if (filterName && filterName.length > 0) {
1318
+ let found = false;
1319
+ for (let f = 0; f < filterName.length; f += 1) {
1320
+ if (thisDevice.name.indexOf(filterName[f]) >= 0) {
1321
+ found = true;
1322
+ break;
1323
+ }
1324
+ }
1325
+ // no matching device - clear the device
1326
+ if (!found) {
1327
+ thisDevice = {};
1328
+ }
1329
+ }
1330
+
1331
+ return callback(thisDevice, null);
1332
+ });
1333
+ } catch (e) {
1334
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, e);
1335
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1336
+ return callback(null, errorObj);
1337
+ }
1338
+ }
1339
+
1340
+ /**
1341
+ * @summary Get Appliance that match the deviceName
1342
+ *
1343
+ * @function getDevice
1344
+ * @param {String} deviceName - the deviceName to find (required)
1345
+ *
1346
+ * @param {getCallback} callback - a callback function to return the result
1347
+ * (appliance) or the error
1348
+ */
1349
+ getDevice(deviceName, callback) {
1350
+ const meth = 'adapterBase-getDevice';
1351
+ const origin = `${this.id}-${meth}`;
1352
+ log.trace(origin);
1353
+
1354
+ // make sure we are set up for device broker getDevice
1355
+ if (!this.allProps.devicebroker || !this.allProps.devicebroker.getDevice || this.allProps.devicebroker.getDevice.length === 0 || !this.allProps.devicebroker.getDevice[0].path) {
1356
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Properties', ['devicebroker.getDevice.path'], null, null, null);
1357
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1358
+ return callback(null, errorObj);
1359
+ }
1360
+
1361
+ /* HERE IS WHERE YOU VALIDATE DATA */
1362
+ if (deviceName === undefined || deviceName === null || deviceName === '' || deviceName.length === 0) {
1363
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['deviceName'], null, null, null);
1364
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1365
+ return callback(null, errorObj);
1366
+ }
1367
+
1368
+ try {
1369
+ // need to get the device so we can convert the deviceName to an id
1370
+ // !! if we can do a lookup by name the getDevicesFiltered may not be necessary
1371
+ const opts = {
1372
+ filter: {
1373
+ name: deviceName
1374
+ }
1375
+ };
1376
+ return this.getDevicesFiltered(opts, (devs, ferr) => {
1377
+ // if we received an error or their is no response on the results return an error
1378
+ if (ferr) {
1379
+ return callback(null, ferr);
1380
+ }
1381
+ if (devs.list.length < 1) {
1382
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Did Not Find Device ${deviceName}`, [], null, null, null);
1383
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1384
+ return callback(null, errorObj);
1385
+ }
1386
+
1387
+ const callPromises = [];
1388
+ for (let i = 0; i < this.allProps.devicebroker.getDevice.length; i += 1) {
1389
+ // Perform component calls here.
1390
+ callPromises.push(
1391
+ new Promise((resolve, reject) => {
1392
+ this.iapMakeBrokerCall('getDevice', this.allProps.devicebroker.getDevice[i], [devs.list[0]], null, (callRet, callErr) => {
1393
+ // return an error
1394
+ if (callErr) {
1395
+ reject(callErr);
1396
+ } else {
1397
+ // return the data
1398
+ resolve(callRet);
1399
+ }
1400
+ });
1401
+ })
1402
+ );
1403
+ }
1404
+
1405
+ // return an array of repsonses
1406
+ return Promise.all(callPromises).then((results) => {
1407
+ let myResult = {};
1408
+ results.forEach((result) => {
1409
+ myResult = { ...myResult, ...result };
1410
+ });
1411
+
1412
+ return callback(myResult, null);
1413
+ });
1414
+ });
1415
+ } catch (ex) {
1416
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
1417
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1418
+ return callback(null, errorObj);
1419
+ }
1420
+ }
1421
+
1422
+ /**
1423
+ * @summary Get Appliances that match the filter
1424
+ *
1425
+ * @function getDevicesFiltered
1426
+ * @param {Object} options - the data to use to filter the appliances (optional)
1427
+ *
1428
+ * @param {getCallback} callback - a callback function to return the result
1429
+ * (appliances) or the error
1430
+ */
1431
+ getDevicesFiltered(options, callback) {
1432
+ const meth = 'adapterBase-getDevicesFiltered';
1433
+ const origin = `${this.id}-${meth}`;
1434
+ log.trace(origin);
1435
+
1436
+ // make sure we are set up for device broker getDevicesFiltered
1437
+ if (!this.allProps.devicebroker || !this.allProps.devicebroker.getDevicesFiltered || this.allProps.devicebroker.getDevicesFiltered.length === 0 || !this.allProps.devicebroker.getDevicesFiltered[0].path) {
1438
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Properties', ['devicebroker.getDevicesFiltered.path'], null, null, null);
1439
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1440
+ return callback(null, errorObj);
1441
+ }
1442
+
1443
+ // verify the required fields have been provided
1444
+ if (options === undefined || options === null || options === '' || options.length === 0) {
1445
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['options'], null, null, null);
1446
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1447
+ return callback(null, errorObj);
1448
+ }
1449
+ log.debug(`Device Filter Options: ${JSON.stringify(options)}`);
1450
+
1451
+ try {
1452
+ // TODO - get pagination working
1453
+ // const nextToken = options.start;
1454
+ // const maxResults = options.limit;
1455
+
1456
+ // set up the filter of Device Names
1457
+ let filterName = [];
1458
+ if (options && options.filter && options.filter.name) {
1459
+ // when this hack is removed, remove the lint ignore above
1460
+ if (Array.isArray(options.filter.name)) {
1461
+ // eslint-disable-next-line prefer-destructuring
1462
+ filterName = options.filter.name;
1463
+ } else {
1464
+ filterName = [options.filter.name];
1465
+ }
1466
+ }
1467
+
1468
+ // TODO - get sort and order working
1469
+ /*
1470
+ if (options && options.sort) {
1471
+ reqObj.uriOptions.sort = JSON.stringify(options.sort);
1472
+ }
1473
+ if (options && options.order) {
1474
+ reqObj.uriOptions.order = options.order;
1475
+ }
1476
+ */
1477
+ const callPromises = [];
1478
+ for (let i = 0; i < this.allProps.devicebroker.getDevicesFiltered.length; i += 1) {
1479
+ // Perform component calls here.
1480
+ callPromises.push(
1481
+ new Promise((resolve, reject) => {
1482
+ this.iapMakeBrokerCall('getDevicesFiltered', this.allProps.devicebroker.getDevicesFiltered[i], [{ fake: 'fakedata' }], filterName, (callRet, callErr) => {
1483
+ // return an error
1484
+ if (callErr) {
1485
+ reject(callErr);
1486
+ } else {
1487
+ // return the data
1488
+ resolve(callRet);
1489
+ }
1490
+ });
1491
+ })
1492
+ );
1493
+ }
1494
+
1495
+ // return an array of repsonses
1496
+ return Promise.all(callPromises).then((results) => {
1497
+ let myResult = [];
1498
+ results.forEach((result) => {
1499
+ if (Array.isArray(result)) {
1500
+ myResult = [...myResult, ...result];
1501
+ } else if (Object.keys(result).length > 0) {
1502
+ myResult.push(result);
1503
+ }
1504
+ });
1505
+
1506
+ log.debug(`${origin}: Found #${myResult.length} devices.`);
1507
+ log.debug(`Devices: ${JSON.stringify(myResult)}`);
1508
+ return callback({ total: myResult.length, list: myResult });
1509
+ });
1510
+ } catch (ex) {
1511
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
1512
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1513
+ return callback(null, errorObj);
1514
+ }
1515
+ }
1516
+
1517
+ /**
1518
+ * @summary Gets the status for the provided appliance
1519
+ *
1520
+ * @function isAlive
1521
+ * @param {String} deviceName - the deviceName of the appliance. (required)
1522
+ *
1523
+ * @param {configCallback} callback - callback function to return the result
1524
+ * (appliance isAlive) or the error
1525
+ */
1526
+ isAlive(deviceName, callback) {
1527
+ const meth = 'adapterBase-isAlive';
1528
+ const origin = `${this.id}-${meth}`;
1529
+ log.trace(origin);
1530
+
1531
+ // make sure we are set up for device broker isAlive
1532
+ if (!this.allProps.devicebroker || !this.allProps.devicebroker.isAlive || this.allProps.devicebroker.isAlive.length === 0 || !this.allProps.devicebroker.isAlive[0].path) {
1533
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Properties', ['devicebroker.isAlive.path'], null, null, null);
1534
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1535
+ return callback(null, errorObj);
1536
+ }
1537
+
1538
+ // verify the required fields have been provided
1539
+ if (deviceName === undefined || deviceName === null || deviceName === '' || deviceName.length === 0) {
1540
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['deviceName'], null, null, null);
1541
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1542
+ return callback(null, errorObj);
1543
+ }
1544
+
1545
+ try {
1546
+ // need to get the device so we can convert the deviceName to an id
1547
+ // !! if we can do a lookup by name the getDevicesFiltered may not be necessary
1548
+ const opts = {
1549
+ filter: {
1550
+ name: deviceName
1551
+ }
1552
+ };
1553
+ return this.getDevicesFiltered(opts, (devs, ferr) => {
1554
+ // if we received an error or their is no response on the results return an error
1555
+ if (ferr) {
1556
+ return callback(null, ferr);
1557
+ }
1558
+ if (devs.list.length < 1) {
1559
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Did Not Find Device ${deviceName}`, [], null, null, null);
1560
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1561
+ return callback(null, errorObj);
1562
+ }
1563
+
1564
+ const callPromises = [];
1565
+ for (let i = 0; i < this.allProps.devicebroker.isAlive.length; i += 1) {
1566
+ // Perform component calls here.
1567
+ callPromises.push(
1568
+ new Promise((resolve, reject) => {
1569
+ this.iapMakeBrokerCall('isAlive', this.allProps.devicebroker.isAlive[i], [devs.list[0]], null, (callRet, callErr) => {
1570
+ // return an error
1571
+ if (callErr) {
1572
+ reject(callErr);
1573
+ } else {
1574
+ // return the data
1575
+ resolve(callRet);
1576
+ }
1577
+ });
1578
+ })
1579
+ );
1580
+ }
1581
+
1582
+ // return an array of repsonses
1583
+ return Promise.all(callPromises).then((results) => {
1584
+ let myResult = {};
1585
+ results.forEach((result) => {
1586
+ myResult = { ...myResult, ...result };
1587
+ });
1588
+
1589
+ let response = true;
1590
+ if (myResult.isAlive !== null && myResult.isAlive !== undefined && myResult.isAlive === false) {
1591
+ response = false;
1592
+ }
1593
+ return callback(response);
1594
+ });
1595
+ });
1596
+ } catch (ex) {
1597
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
1598
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1599
+ return callback(null, errorObj);
1600
+ }
1601
+ }
1602
+
1603
+ /**
1604
+ * @summary Gets a config for the provided Appliance
1605
+ *
1606
+ * @function getConfig
1607
+ * @param {String} deviceName - the deviceName of the appliance. (required)
1608
+ * @param {String} format - the desired format of the config. (optional)
1609
+ *
1610
+ * @param {configCallback} callback - callback function to return the result
1611
+ * (appliance config) or the error
1612
+ */
1613
+ getConfig(deviceName, format, callback) {
1614
+ const meth = 'adapterBase-getConfig';
1615
+ const origin = `${this.id}-${meth}`;
1616
+ log.trace(origin);
1617
+
1618
+ // make sure we are set up for device broker getConfig
1619
+ if (!this.allProps.devicebroker || !this.allProps.devicebroker.getConfig || this.allProps.devicebroker.getConfig.length === 0 || !this.allProps.devicebroker.getConfig[0].path) {
1620
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Properties', ['devicebroker.getConfig.path'], null, null, null);
1621
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1622
+ return callback(null, errorObj);
1623
+ }
1624
+
1625
+ // verify the required fields have been provided
1626
+ if (deviceName === undefined || deviceName === null || deviceName === '' || deviceName.length === 0) {
1627
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['deviceName'], null, null, null);
1628
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1629
+ return callback(null, errorObj);
1630
+ }
1631
+
1632
+ try {
1633
+ // need to get the device so we can convert the deviceName to an id
1634
+ // !! if we can do a lookup by name the getDevicesFiltered may not be necessary
1635
+ const opts = {
1636
+ filter: {
1637
+ name: deviceName
1638
+ }
1639
+ };
1640
+ return this.getDevicesFiltered(opts, (devs, ferr) => {
1641
+ // if we received an error or their is no response on the results return an error
1642
+ if (ferr) {
1643
+ return callback(null, ferr);
1644
+ }
1645
+ if (devs.list.length < 1) {
1646
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Did Not Find Device ${deviceName}`, [], null, null, null);
1647
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1648
+ return callback(null, errorObj);
1649
+ }
1650
+
1651
+ const callPromises = [];
1652
+ for (let i = 0; i < this.allProps.devicebroker.getConfig.length; i += 1) {
1653
+ // Perform component calls here.
1654
+ callPromises.push(
1655
+ new Promise((resolve, reject) => {
1656
+ this.iapMakeBrokerCall('getConfig', this.allProps.devicebroker.getConfig[i], [devs.list[0]], null, (callRet, callErr) => {
1657
+ // return an error
1658
+ if (callErr) {
1659
+ reject(callErr);
1660
+ } else {
1661
+ // return the data
1662
+ resolve(callRet);
1663
+ }
1664
+ });
1665
+ })
1666
+ );
1667
+ }
1668
+
1669
+ // return an array of repsonses
1670
+ return Promise.all(callPromises).then((results) => {
1671
+ let myResult = {};
1672
+ results.forEach((result) => {
1673
+ myResult = { ...myResult, ...result };
1674
+ });
1675
+
1676
+ // return the result
1677
+ const newResponse = {
1678
+ response: JSON.stringify(myResult, null, 2)
1679
+ };
1680
+ return callback(newResponse, null);
1681
+ });
1682
+ });
1683
+ } catch (ex) {
1684
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
1685
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1686
+ return callback(null, errorObj);
1687
+ }
1688
+ }
1689
+
1690
+ /**
1691
+ * @summary Gets the device count from the system
1692
+ *
1693
+ * @function iapGetDeviceCount
1694
+ *
1695
+ * @param {getCallback} callback - callback function to return the result
1696
+ * (count) or the error
1697
+ */
1698
+ iapGetDeviceCount(callback) {
1699
+ const meth = 'adapterBase-iapGetDeviceCount';
1700
+ const origin = `${this.id}-${meth}`;
1701
+ log.trace(origin);
1702
+
1703
+ // make sure we are set up for device broker getCount
1704
+ if (!this.allProps.devicebroker || !this.allProps.devicebroker.getCount || this.allProps.devicebroker.getCount.length === 0 || !this.allProps.devicebroker.getCount[0].path) {
1705
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Properties', ['devicebroker.getCount.path'], null, null, null);
1706
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1707
+ return callback(null, errorObj);
1708
+ }
1709
+
1710
+ // verify the required fields have been provided
1711
+
1712
+ try {
1713
+ const callPromises = [];
1714
+ for (let i = 0; i < this.allProps.devicebroker.getCount.length; i += 1) {
1715
+ // Perform component calls here.
1716
+ callPromises.push(
1717
+ new Promise((resolve, reject) => {
1718
+ this.iapMakeBrokerCall('getCount', this.allProps.devicebroker.getCount[i], null, null, (callRet, callErr) => {
1719
+ // return an error
1720
+ if (callErr) {
1721
+ reject(callErr);
1722
+ } else {
1723
+ // return the data
1724
+ resolve(callRet);
1725
+ }
1726
+ });
1727
+ })
1728
+ );
1729
+ }
1730
+
1731
+ // return an array of repsonses
1732
+ return Promise.all(callPromises).then((results) => {
1733
+ let myResult = {};
1734
+ results.forEach((result) => {
1735
+ myResult = { ...myResult, ...result };
1736
+ });
1737
+
1738
+ // return the result
1739
+ return callback({ count: myResult.length });
1740
+ });
1741
+ } catch (ex) {
1742
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
1022
1743
  log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1023
1744
  return callback(null, errorObj);
1024
1745
  }