@itentialopensource/adapter-meraki 0.7.3 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -1,4 +1,12 @@
1
1
 
2
+ ## 0.8.0 [01-21-2022]
3
+
4
+ * migration to the latest foundation and broker ready
5
+
6
+ See merge request itentialopensource/adapters/sd-wan/adapter-meraki!15
7
+
8
+ ---
9
+
2
10
  ## 0.7.3 [06-08-2021]
3
11
 
4
12
  * Update Pronghorn.json and adapter.js for passing body directly to api call
package/README.md CHANGED
@@ -125,7 +125,8 @@ This section defines **all** the properties that are available for the adapter,
125
125
  },
126
126
  "healthcheck": {
127
127
  "type": "startup",
128
- "frequency": 300000
128
+ "frequency": 300000,
129
+ "query_object": {}
129
130
  },
130
131
  "request": {
131
132
  "number_redirects": 0,
@@ -250,6 +251,7 @@ The healthcheck properties defines the API that runs the healthcheck to tell the
250
251
  | ------- | ------- |
251
252
  | type | Required. The type of health check to run. |
252
253
  | frequency | Required if intermittent. Defines how often the health check should run. Measured in milliseconds. Default is 300000.|
254
+ | query_object | Query parameters to be added to the adapter healthcheck call.|
253
255
 
254
256
  ### Request Properties
255
257
 
@@ -398,7 +400,7 @@ There are several node scripts that now accompany the adapter. These scripts are
398
400
  | npm run troubleshoot | Provides a way to troubleshoot the adapter - runs connectivity, healthcheck and basic get.|
399
401
  | npm run connectivity | Provides a connectivity check to the Meraki system.|
400
402
  | npm run healthcheck | Checks whether the configured healthcheck call works to Meraki.|
401
- | npm run basicget | Checks whether the cbasic get calls works to Meraki.|
403
+ | npm run basicget | Checks whether the basic get calls works to Meraki.|
402
404
 
403
405
  ## Installing an Itential Product Adapter
404
406
 
@@ -412,21 +414,21 @@ if the @itentialopensource directory does not exist, create it:
412
414
  mkdir @itentialopensource
413
415
  ```
414
416
 
415
- 1. Clone the adapter into your IAP environment.
417
+ 2. Clone the adapter into your IAP environment.
416
418
 
417
419
  ```bash
418
420
  cd \@itentialopensource
419
421
  git clone git@gitlab.com:\@itentialopensource/adapters/adapter-meraki
420
422
  ```
421
423
 
422
- 1. Run the adapter install script.
424
+ 3. Run the adapter install script.
423
425
 
424
426
  ```bash
425
427
  cd adapter-meraki
426
428
  npm run adapter:install
427
429
  ```
428
430
 
429
- 1. Restart IAP
431
+ 4. Restart IAP
430
432
 
431
433
  ```bash
432
434
  systemctl restart pronghorn
@@ -446,7 +448,7 @@ Depending on where your code is located, this process is different.
446
448
  Adapter should be placed into: /opt/pronghorn/current/node_modules/\@itentialopensource
447
449
  ```
448
450
 
449
- 1. Follow Steps 3-4 (above) to install an Itential adapter to load your properties, dependencies and restart IAP.
451
+ 2. Follow Steps 3-4 (above) to install an Itential adapter to load your properties, dependencies and restart IAP.
450
452
 
451
453
  ## Using this Adapter
452
454
 
@@ -494,7 +496,7 @@ The `verifyCapability` call verifies the adapter can perform the provided action
494
496
  verifyCapability(entityType, actionType, entityId, callback)
495
497
  ```
496
498
 
497
- The `updateEntityCache` call will update the entity cache.
499
+ The `updateEntityCache` call will update the entity cache.
498
500
  ```js
499
501
  updateEntityCache()
500
502
  ```
@@ -548,6 +550,77 @@ getQueue(callback)
548
550
 
549
551
  Specific adapter calls are built based on the API of the Meraki. The Adapter Builder creates the proper method comments for generating JS-DOC for the adapter. This is the best way to get information on the calls.
550
552
 
553
+
554
+ ## Extending/Enhancing the Adapter
555
+
556
+ ### Adding a Second Instance of an Adapter
557
+
558
+ You can add a second instance of this adapter without adding new code on the file system. To do this go into the IAP Admin Essentials and add a new service config for this adapter. The two instances of the adapter should have unique ids. In addition, they should point to different instances of the other system. For example, they should be configured to talk to different hosts.
559
+
560
+ ### Adding Adapter Calls
561
+
562
+ There are multiple ways to add calls to an existing adapter.
563
+
564
+ The easiest way would be to use the Adapter Builder update process. This process takes in a Swagger or OpenAPI document, allows you to select the calls you want to add and then generates a zip file that can be used to update the adapter. Once you have the zip file simple put it in the adapter direcctory and execute `npm run adapter:update`.
565
+
566
+ ```bash
567
+ mv updatePackage.zip adapter-meraki
568
+ cd adapter-meraki
569
+ npm run adapter:update
570
+ ```
571
+
572
+ If you do not have a Swagger or OpenAPI document, you can use a Postman Collection and convert that to an OpenAPI document using APIMatic and then follow the first process.
573
+
574
+ If you want to manually update the adapter that can also be done the key thing is to make sure you update all of the right files. Within the entities directory you will find 1 or more entities. You can create a new entity or add to an existing entity. Each entity has an action.json file, any new call will need to be put in the action.json file. It will also need to be added to the enum for the ph_request_type in the appropriate schema files. Once this configuration is complete you will need to add the call to the adapter.js file and in order to make it available as a workflow task in IAP, it should also be added to the pronghorn.json file. You can optionally add it to the unit and integration test files. There is more information on how to work on each of these files in the Adapter Technical Resources on Dev Site [HERE](https://developer.itential.io/adapters-resources/)
575
+
576
+ ```text
577
+ Files to update
578
+ * entities/<entity>/action.json: add an action
579
+ * entities/<entity>/schema.json (or the schema defined on the action): add action to the enum for ph_request_type
580
+ * adapter.js: add the new method and make sure it calls the proper entity and action
581
+ * pronghorn.json: add the new method
582
+ * test/unit/adapterTestUnit.js (optional but best practice): add unit test(s) - function is there, any required parameters error when not passed in
583
+ * test/integration/adapterTestIntegration.js (optional but best practice): add integration test
584
+ ```
585
+
586
+ ### Adding Adapter Properties
587
+
588
+ While changing adapter properties is done in the service instance configuration section of IAP, adding properties has to be done in the adapter. To add a property you should edit the propertiesSchema.json with the proper information for the property. In addition, you should modify the sampleProperties to have the new property in it.
589
+
590
+ ```text
591
+ Files to update
592
+ * propertiesSchema.json: add the new property and how it is defined
593
+ * sampleProperties: add the new property with a default value
594
+ * test/unit/adapterTestUnit.js (optional but best practice): add the property to the global properties
595
+ * test/integration/adapterTestIntegration.js (optional but best practice): add the property to the global properties
596
+ ```
597
+
598
+ ### Changing Adapter Authentication
599
+
600
+ Often an adapter is built before knowing the authentication and authentication process can also change over time. The adapter supports many different kinds of authentication but it does require configuration. Some forms of authentication can be defined entirely with the adapter properties but others require configuration.
601
+
602
+ ```text
603
+ Files to update
604
+ * entities/<entity>/action.json: change the getToken action as needed
605
+ * entities/<entity>/schemaTokenReq.json: add input parameters (external name is name in other system)
606
+ * entities/<entity>/schemaTokenResp.json: add response parameters (external name is name in other system)
607
+ * propertiesSchema.json: add any new property and how it is defined
608
+ * sampleProperties: add any new property with a default value
609
+ * test/unit/adapterTestUnit.js (optional but best practice): add the property to the global properties
610
+ * test/integration/adapterTestIntegration.js (optional but best practice): add the property to the global properties
611
+ ```
612
+
613
+ ### Enhancing Adapter Integration Tests
614
+
615
+ The adapter integration tests are written to be able to test in either stub (standalone) mode or integrated to the other system. However, if integrating to the other system, you may need to provide better data than what the adapter provides by default as that data is likely to fail for create and update. To provide better data, edit the adapter integration test file. Make sure you do not remove the marker and keep custom code below the marker so you do not impact future migrations. Once the edits are complete, run the integration test as it instructs you to above. When you run integrated to the other system, you can also save mockdata for future use by changing the isSaveMockData flag to true.
616
+
617
+ ```text
618
+ Files to update
619
+ * test/integration/adapterTestIntegration.js: add better data for the create and update calls so that they will not fail.
620
+ ```
621
+
622
+ As mentioned previously, for most of these changes as well as other possible changes, there is more information on how to work on an adapter in the Adapter Technical Resources on Dev Site [HERE](https://developer.itential.io/adapters-resources/)
623
+
551
624
  ## Troubleshooting the Adapter
552
625
 
553
626
  Run `npm run troubleshoot` to start the interactive troubleshooting process. The command allows user to verify and update connection, authentication as well as healthcheck configuration. After that it will test these properties by sending HTTP request to the endpoint. If the tests pass, it will persist these changes into IAP.
@@ -566,26 +639,26 @@ User also have the option to run individual command to perform specific test
566
639
  npm run troubleshoot
567
640
  ```
568
641
 
569
- 1. Verify the adapter properties are set up correctly.
642
+ 2. Verify the adapter properties are set up correctly.
570
643
 
571
644
  ```text
572
645
  Go into the Itential Platform GUI and verify/update the properties
573
646
  ```
574
647
 
575
- 1. Verify there is connectivity between the Itential Platform Server and Meraki Server.
648
+ 3. Verify there is connectivity between the Itential Platform Server and Meraki Server.
576
649
 
577
650
  ```text
578
651
  ping the ip address of Meraki server
579
652
  try telnet to the ip address port of Meraki
580
653
  ```
581
654
 
582
- 1. Verify the credentials provided for Meraki.
655
+ 4. Verify the credentials provided for Meraki.
583
656
 
584
657
  ```text
585
658
  login to Meraki using the provided credentials
586
659
  ```
587
660
 
588
- 1. Verify the API of the call utilized for Meraki Healthcheck.
661
+ 5. Verify the API of the call utilized for Meraki Healthcheck.
589
662
 
590
663
  ```text
591
664
  Go into the Itential Platform GUI and verify/update the properties
package/adapter.js CHANGED
@@ -85,7 +85,7 @@ class Meraki extends AdapterBaseCl {
85
85
  * @getWorkflowFunctions
86
86
  */
87
87
  getWorkflowFunctions(inIgnore) {
88
- let myIgnore = [];
88
+ let myIgnore = ['hasEntities', 'hasDevices'];
89
89
  if (!inIgnore && Array.isArray(inIgnore)) {
90
90
  myIgnore = inIgnore;
91
91
  } else if (!inIgnore && typeof inIgnore === 'string') {
@@ -249,6 +249,24 @@ class Meraki extends AdapterBaseCl {
249
249
  }
250
250
  }
251
251
 
252
+ /**
253
+ * @summary moves entites into Mongo DB
254
+ *
255
+ * @function moveEntitiesToDB
256
+ * @param {getCallback} callback - a callback function to return the result (Generics)
257
+ * or the error
258
+ */
259
+ moveEntitiesToDB(callback) {
260
+ const origin = `${this.id}-adapter-moveEntitiesToDB`;
261
+ log.trace(origin);
262
+ try {
263
+ return super.moveEntitiesToDB(callback);
264
+ } catch (err) {
265
+ log.error(`${origin}: ${err}`);
266
+ return callback(null, err);
267
+ }
268
+ }
269
+
252
270
  /**
253
271
  * @summary Determines if this adapter supports the specific entity
254
272
  *
@@ -528,6 +546,456 @@ class Meraki extends AdapterBaseCl {
528
546
  }
529
547
  }
530
548
 
549
+ /* BROKER CALLS */
550
+ /**
551
+ * @summary Determines if this adapter supports any in a list of entities
552
+ *
553
+ * @function hasEntities
554
+ * @param {String} entityType - the entity type to check for
555
+ * @param {Array} entityList - the list of entities we are looking for
556
+ *
557
+ * @param {Callback} callback - A map where the entity is the key and the
558
+ * value is true or false
559
+ */
560
+ hasEntities(entityType, entityList, callback) {
561
+ const origin = `${this.id}-adapter-hasEntities`;
562
+ log.trace(origin);
563
+
564
+ switch (entityType) {
565
+ case 'Device':
566
+ return this.hasDevices(entityList, callback);
567
+ default:
568
+ return callback(null, `${this.id} does not support entity ${entityType}`);
569
+ }
570
+ }
571
+
572
+ /**
573
+ * @summary Helper method for hasEntities for the specific device case
574
+ *
575
+ * @param {Array} deviceList - array of unique device identifiers
576
+ * @param {Callback} callback - A map where the device is the key and the
577
+ * value is true or false
578
+ */
579
+ hasDevices(deviceList, callback) {
580
+ const origin = `${this.id}-adapter-hasDevices`;
581
+ log.trace(origin);
582
+
583
+ const findings = deviceList.reduce((map, device) => {
584
+ // eslint-disable-next-line no-param-reassign
585
+ map[device] = false;
586
+ log.debug(`In reduce: ${JSON.stringify(map)}`);
587
+ return map;
588
+ }, {});
589
+ const apiCalls = deviceList.map((device) => new Promise((resolve) => {
590
+ this.getDevice(device, (result, error) => {
591
+ if (error) {
592
+ log.debug(`In map error: ${JSON.stringify(device)}`);
593
+ return resolve({ name: device, found: false });
594
+ }
595
+ log.debug(`In map: ${JSON.stringify(device)}`);
596
+ return resolve({ name: device, found: true });
597
+ });
598
+ }));
599
+ Promise.all(apiCalls).then((results) => {
600
+ results.forEach((device) => {
601
+ findings[device.name] = device.found;
602
+ });
603
+ log.debug(`FINDINGS: ${JSON.stringify(findings)}`);
604
+ return callback(findings);
605
+ }).catch((errors) => {
606
+ log.error('Unable to do device lookup.');
607
+ return callback(null, { code: 503, message: 'Unable to do device lookup.', error: errors });
608
+ });
609
+ }
610
+
611
+ /**
612
+ * @summary Get Appliance that match the deviceName
613
+ *
614
+ * @function getDevice
615
+ * @param {String} deviceName - the deviceName to find (required)
616
+ *
617
+ * @param {getCallback} callback - a callback function to return the result
618
+ * (appliance) or the error
619
+ */
620
+ getDevice(deviceName, callback) {
621
+ const meth = 'adapter-getDevice';
622
+ const origin = `${this.id}-${meth}`;
623
+ log.trace(origin);
624
+
625
+ if (this.suspended && this.suspendMode === 'error') {
626
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'AD.600', [], null, null, null);
627
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
628
+ return callback(null, errorObj);
629
+ }
630
+
631
+ /* HERE IS WHERE YOU VALIDATE DATA */
632
+ if (deviceName === undefined || deviceName === null || deviceName === '' || deviceName.length === 0) {
633
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['deviceName'], null, null, null);
634
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
635
+ return callback(null, errorObj);
636
+ }
637
+
638
+ try {
639
+ // need to get the device so we can convert the deviceName to an id
640
+ // !! if we can do a lookup by name the getDevicesFiltered may not be necessary
641
+ const opts = {
642
+ filter: {
643
+ name: deviceName
644
+ }
645
+ };
646
+ return this.getDevicesFiltered(opts, (devs, ferr) => {
647
+ // if we received an error or their is no response on the results return an error
648
+ if (ferr) {
649
+ return callback(null, ferr);
650
+ }
651
+ if (devs.list.length < 1) {
652
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Did Not Find Device ${deviceName}`, [], null, null, null);
653
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
654
+ return callback(null, errorObj);
655
+ }
656
+ // get the uuid from the device
657
+ const { uuid } = devs.list[0];
658
+
659
+ // !! using Generic makes it easier on the Adapter Builder (just need to change the path)
660
+ // !! you can also replace with a specific call if that is easier
661
+ const uriPath = `/call/toget/device/${uuid}`;
662
+ return this.genericAdapterRequest(uriPath, 'GET', {}, {}, {}, (result, error) => {
663
+ // if we received an error or their is no response on the results return an error
664
+ if (error) {
665
+ return callback(null, error);
666
+ }
667
+ if (!result.response || !result.response.applianceMo) {
668
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Invalid Response', ['getDevice'], null, null, null);
669
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
670
+ return callback(null, errorObj);
671
+ }
672
+
673
+ // return the response
674
+ // !! format the data we send back
675
+ // !! these fields are config manager fields you need to map to the data we receive
676
+ const thisDevice = result.response;
677
+ thisDevice.name = thisDevice.systemName;
678
+ thisDevice.ostype = `System-${thisDevice.systemType}`;
679
+ thisDevice.port = thisDevice.systemPort;
680
+ thisDevice.ipaddress = thisDevice.systemIP;
681
+ return callback(thisDevice);
682
+ });
683
+ });
684
+ } catch (ex) {
685
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
686
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
687
+ return callback(null, errorObj);
688
+ }
689
+ }
690
+
691
+ /**
692
+ * @summary Get Appliances that match the filter
693
+ *
694
+ * @function getDevicesFiltered
695
+ * @param {Object} options - the data to use to filter the appliances (optional)
696
+ *
697
+ * @param {getCallback} callback - a callback function to return the result
698
+ * (appliances) or the error
699
+ */
700
+ getDevicesFiltered(options, callback) {
701
+ const meth = 'adapter-getDevicesFiltered';
702
+ const origin = `${this.id}-${meth}`;
703
+ log.trace(origin);
704
+
705
+ // verify the required fields have been provided
706
+ if (options === undefined || options === null || options === '' || options.length === 0) {
707
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['options'], null, null, null);
708
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
709
+ return callback(null, errorObj);
710
+ }
711
+ log.debug(`Device Filter Options: ${JSON.stringify(options)}`);
712
+
713
+ // TODO - get pagination working
714
+ // const nextToken = options.start;
715
+ // const maxResults = options.limit;
716
+
717
+ // set up the filter of Device Names
718
+ let filterName = [];
719
+ if (options && options.filter && options.filter.name) {
720
+ // when this hack is removed, remove the lint ignore above
721
+ if (Array.isArray(options.filter.name)) {
722
+ // eslint-disable-next-line prefer-destructuring
723
+ filterName = options.filter.name;
724
+ } else {
725
+ filterName = [options.filter.name];
726
+ }
727
+ }
728
+
729
+ // TODO - get sort and order working
730
+ /*
731
+ if (options && options.sort) {
732
+ reqObj.uriOptions.sort = JSON.stringify(options.sort);
733
+ }
734
+ if (options && options.order) {
735
+ reqObj.uriOptions.order = options.order;
736
+ }
737
+ */
738
+ try {
739
+ // !! using Generic makes it easier on the Adapter Builder (just need to change the path)
740
+ // !! you can also replace with a specific call if that is easier
741
+ const uriPath = '/call/toget/devices';
742
+ return this.genericAdapterRequest(uriPath, 'GET', {}, {}, {}, (result, error) => {
743
+ // if we received an error or their is no response on the results return an error
744
+ if (error) {
745
+ return callback(null, error);
746
+ }
747
+ if (!result.response) {
748
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Invalid Response', ['getDevicesFiltered'], null, null, null);
749
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
750
+ return callback(null, errorObj);
751
+ }
752
+
753
+ // !! go through the response - may have to look for sub object
754
+ // handle an array of devices
755
+ if (Array.isArray(result.response)) {
756
+ const myDevices = [];
757
+
758
+ for (let d = 0; d < result.response.length; d += 1) {
759
+ // !! format the data we send back
760
+ // !! these fields are config manager fields you need to map to the data we receive
761
+ const thisDevice = result.response;
762
+ thisDevice.name = thisDevice.systemName;
763
+ thisDevice.ostype = `System-${thisDevice.systemType}`;
764
+ thisDevice.port = thisDevice.systemPort;
765
+ thisDevice.ipaddress = thisDevice.systemIP;
766
+
767
+ // if there is no filter - return the device
768
+ if (filterName.length === 0) {
769
+ myDevices.push(thisDevice);
770
+ } else {
771
+ // if we have to match a filter
772
+ let found = false;
773
+ for (let f = 0; f < filterName.length; f += 1) {
774
+ if (thisDevice.name.indexOf(filterName[f]) >= 0) {
775
+ found = true;
776
+ break;
777
+ }
778
+ }
779
+ // matching device
780
+ if (found) {
781
+ myDevices.push(thisDevice);
782
+ }
783
+ }
784
+ }
785
+ log.debug(`${origin}: Found #${myDevices.length} devices.`);
786
+ log.debug(`Devices: ${JSON.stringify(myDevices)}`);
787
+ return callback({ total: myDevices.length, list: myDevices });
788
+ }
789
+ // handle a single device response
790
+ // !! format the data we send back
791
+ // !! these fields are config manager fields you need to map to the data we receive
792
+ const thisDevice = result.response;
793
+ thisDevice.name = thisDevice.systemName;
794
+ thisDevice.ostype = `System-${thisDevice.systemType}`;
795
+ thisDevice.port = thisDevice.systemPort;
796
+ thisDevice.ipaddress = thisDevice.systemIP;
797
+
798
+ // if there is no filter - return the device
799
+ if (filterName.length === 0) {
800
+ log.debug(`${origin}: Found #1 device.`);
801
+ log.debug(`Device: ${JSON.stringify(thisDevice)}`);
802
+ return callback({ total: 1, list: [thisDevice] });
803
+ }
804
+
805
+ // if there is a filter need to check for matching device
806
+ let found = false;
807
+ for (let f = 0; f < filterName.length; f += 1) {
808
+ if (thisDevice.name.indexOf(filterName[f]) >= 0) {
809
+ found = true;
810
+ break;
811
+ }
812
+ }
813
+ // matching device
814
+ if (found) {
815
+ log.debug(`${origin}: Found #1 device.`);
816
+ log.debug(`Device Found: ${JSON.stringify(thisDevice)}`);
817
+ return callback({ total: 1, list: [thisDevice] });
818
+ }
819
+ // not a matching device
820
+ log.debug(`${origin}: No matching device found.`);
821
+ return callback({ total: 0, list: [] });
822
+ });
823
+ } catch (ex) {
824
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
825
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
826
+ return callback(null, errorObj);
827
+ }
828
+ }
829
+
830
+ /**
831
+ * @summary Gets the status for the provided appliance
832
+ *
833
+ * @function isAlive
834
+ * @param {String} deviceName - the deviceName of the appliance. (required)
835
+ *
836
+ * @param {configCallback} callback - callback function to return the result
837
+ * (appliance isAlive) or the error
838
+ */
839
+ isAlive(deviceName, callback) {
840
+ const meth = 'adapter-isAlive';
841
+ const origin = `${this.id}-${meth}`;
842
+ log.trace(origin);
843
+
844
+ // verify the required fields have been provided
845
+ if (deviceName === undefined || deviceName === null || deviceName === '' || deviceName.length === 0) {
846
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['deviceName'], null, null, null);
847
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
848
+ return callback(null, errorObj);
849
+ }
850
+
851
+ try {
852
+ // need to get the device so we can convert the deviceName to an id
853
+ // !! if we can do a lookup by name the getDevicesFiltered may not be necessary
854
+ const opts = {
855
+ filter: {
856
+ name: deviceName
857
+ }
858
+ };
859
+ return this.getDevicesFiltered(opts, (devs, ferr) => {
860
+ // if we received an error or their is no response on the results return an error
861
+ if (ferr) {
862
+ return callback(null, ferr);
863
+ }
864
+ if (devs.list.length < 1) {
865
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Did Not Find Device ${deviceName}`, [], null, null, null);
866
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
867
+ return callback(null, errorObj);
868
+ }
869
+ // get the uuid from the device
870
+ const { uuid } = devs.list[0];
871
+
872
+ // !! using Generic makes it easier on the Adapter Builder (just need to change the path)
873
+ // !! you can also replace with a specific call if that is easier
874
+ const uriPath = `/call/toget/status/${uuid}`;
875
+ return this.genericAdapterRequest(uriPath, 'GET', {}, {}, {}, (result, error) => {
876
+ // if we received an error or their is no response on the results return an error
877
+ if (error) {
878
+ return callback(null, error);
879
+ }
880
+ // !! should update this to make sure we are checking for the appropriate object/field
881
+ if (!result.response || !result.response.returnObj || !Object.hasOwnProperty.call(result.response.returnObj, 'statusField')) {
882
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Invalid Response', ['isAlive'], null, null, null);
883
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
884
+ return callback(null, errorObj);
885
+ }
886
+
887
+ // !! return the response - Update to the appropriate object/field
888
+ return callback(!result.response.returnObj.statusField);
889
+ });
890
+ });
891
+ } catch (ex) {
892
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
893
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
894
+ return callback(null, errorObj);
895
+ }
896
+ }
897
+
898
+ /**
899
+ * @summary Gets a config for the provided Appliance
900
+ *
901
+ * @function getConfig
902
+ * @param {String} deviceName - the deviceName of the appliance. (required)
903
+ * @param {String} format - the desired format of the config. (optional)
904
+ *
905
+ * @param {configCallback} callback - callback function to return the result
906
+ * (appliance config) or the error
907
+ */
908
+ getConfig(deviceName, format, callback) {
909
+ const meth = 'adapter-getConfig';
910
+ const origin = `${this.id}-${meth}`;
911
+ log.trace(origin);
912
+
913
+ // verify the required fields have been provided
914
+ if (deviceName === undefined || deviceName === null || deviceName === '' || deviceName.length === 0) {
915
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['deviceName'], null, null, null);
916
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
917
+ return callback(null, errorObj);
918
+ }
919
+
920
+ try {
921
+ // need to get the device so we can convert the deviceName to an id
922
+ // !! if we can do a lookup by name the getDevicesFiltered may not be necessary
923
+ const opts = {
924
+ filter: {
925
+ name: deviceName
926
+ }
927
+ };
928
+ return this.getDevicesFiltered(opts, (devs, ferr) => {
929
+ // if we received an error or their is no response on the results return an error
930
+ if (ferr) {
931
+ return callback(null, ferr);
932
+ }
933
+ if (devs.list.length < 1) {
934
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Did Not Find Device ${deviceName}`, [], null, null, null);
935
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
936
+ return callback(null, errorObj);
937
+ }
938
+ // get the uuid from the device
939
+ const { uuid } = devs.list[0];
940
+
941
+ // !! using Generic makes it easier on the Adapter Builder (just need to change the path)
942
+ // !! you can also replace with a specific call if that is easier
943
+ const uriPath = `/call/toget/config/${uuid}`;
944
+ return this.genericAdapterRequest(uriPath, 'GET', {}, {}, {}, (result, error) => {
945
+ // if we received an error or their is no response on the results return an error
946
+ if (error) {
947
+ return callback(null, error);
948
+ }
949
+
950
+ // return the result
951
+ const newResponse = {
952
+ response: JSON.stringify(result.response, null, 2)
953
+ };
954
+ return callback(newResponse);
955
+ });
956
+ });
957
+ } catch (ex) {
958
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
959
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
960
+ return callback(null, errorObj);
961
+ }
962
+ }
963
+
964
+ /**
965
+ * @summary Gets the device count from the system
966
+ *
967
+ * @function getCount
968
+ *
969
+ * @param {getCallback} callback - callback function to return the result
970
+ * (count) or the error
971
+ */
972
+ getCount(callback) {
973
+ const meth = 'adapter-getCount';
974
+ const origin = `${this.id}-${meth}`;
975
+ log.trace(origin);
976
+
977
+ // verify the required fields have been provided
978
+
979
+ try {
980
+ // !! using Generic makes it easier on the Adapter Builder (just need to change the path)
981
+ // !! you can also replace with a specific call if that is easier
982
+ const uriPath = '/call/toget/count';
983
+ return this.genericAdapterRequest(uriPath, 'GET', {}, {}, {}, (result, error) => {
984
+ // if we received an error or their is no response on the results return an error
985
+ if (error) {
986
+ return callback(null, error);
987
+ }
988
+
989
+ // return the result
990
+ return callback({ count: result.response });
991
+ });
992
+ } catch (ex) {
993
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
994
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
995
+ return callback(null, errorObj);
996
+ }
997
+ }
998
+
531
999
  /**
532
1000
  * @callback healthCallback
533
1001
  * @param {Object} result - the result of the get request (contains an id and a status)