cnMaestro Update PMP Device Help

Hey Folks,

I've been playing around with the cnMaestro API today and have been really enjoying it, but I haven't been able to determine the magic incantation to get the Update Device Configuration endpoint working correctly yet.

I sifted through the API documentation and the existing forum posts and wasn't able to pick up anything more than what was in the docs, so I'm hoping someone here can help or at least point me in the right direction.

I am running cnMaestro on-prem v2.2.1-r32 and am attempting to update some basic fields on a test AP to get my sea legs with the API. I have successfully performed actions like onboarding, rebooting, and getting statistics / performance data from this specific AP but am still having troubling updating fields.

I'm using Python3 for interacting currently, and I followed the body format as laid out in the docs like so (apologies for scrubbing the data into stupid numbers - I swear I have real IPs and VLANs in the real deal):

import requests
headers = {
    'Content-Type': "application/json",
    'Accept': "application/json",
    'Authorization': "Bearer GREATTOKENWOW",
}
body = {
	'name': 'TEST_AP_NAME_FIELD',
	'latitude': '41.00000',
	'longitude': '-83.00000',
	'overrides': {
		"auto_set":{
			"network": 'false',
		},
		'dns_server_1': '8.8.8.8',
		'dns_server_2': '1.1.1.1',
		'vlans': [{
			'id': 1111,
			'ip': '12.34.56.246',
			'mask': '12.34.56.224',
			'mode': 'static',
		}],
	},
}

I have tried to submit the HTTP PUT request in both of the following ways with the successive returns:

>>> requests.put('https://cnmaestro.amplex.net/api/v1/devices/0a-00-3e-a0-d4-74', body, headers=headers, verify=False).json()
{'sTime': 1571314999474, 'error': {'message': 'SyntaxError: Unexpected token n in JSON at position 0', 'cause': 'SyntaxError: Unexpected token n in JSON at position 0', 'level': 'error', 'supportUrl': ''}}

>>> requests.put(‘https://cnmaestro.amplex.net/api/v1/devices/0a-00-3e-a0-d4-74’, headers=headers, params=body, verify=False).json()
{‘message’: ‘Input Validation Error for incoming request’, ‘cause’: ‘INTERNAL’}
>>>

I know the direct body payload is technically the documented format, but I figured passing the dictionary in params was worth a shot for giggles since it worked on onboarding.

The documentation states that overrides.auto_set.network must be set to FALSE for the overrides and vlan statements, which it is.  I have also tried setting only overrides.auto_set.network in it's own call for the sake of being thorough and encountered the same errors.

Anyone see where I'm injecting stupid into the procedure?  I'd appreciate any insight anyone can provide.

Thanks!

Jacob

Hi Jacob,

I don't have any easy way of testing this, but have you tried using the json keyword parameter to requests.put? I don't think requests will automatically convert your dictionary to JSON otherwise.

Something like this:

requests.put(url, json=body, headers=headers, verify=False)

Hope that helps,

Simon

1 Like

Thanks for the quick reply and suggestion Simon!  I didn't consider that requests doesn't particularly enjoy sending nested dictionaries without the 'json' keyword directly in the statement.

This got me a little further up the road at least, now I'm seeing

>>> requests.put('https://cnmaestro.amplex.net/api/v1/devices/0a-00-3e-a0-d4-74', json=body, headers=headers, verify=False).json()
{'error': {'cause': 'InvalidInputError', 'message': 'Additional properties not allowed: overrides'}}
I'll bang on it a bit more this afternoon to see if I can get it executing properly; if I can I will post the solution, else I will continue bothering you :)

Hi Jacob,

This Knowledge Base article may help with getting the API to work initially:

http://community.cambiumnetworks.com/t5/cnMaestro/Using-Custom-Configuration-Templates-using-an-API-for-PMP/m-p/104861

Once you get past the 'SyntaxError: Unexpected token n in JSON at position 0' error you'll also need to modify your payload.  I don't think the documentation makes it explictly clear which parameters are for wi-fi vs PMP/ePMP devices.

First you'll want to create a configuration template in the cnMaestro GUI.   Once templates are created in the GUI they will available to push to devices via the API.

This thread goes over some of the basics with templates and using replacement variables.  There is also information in the main user guide.  You'll want to use replacement variables if values need to be unique per device.  If not, you can just set static values in the template that will be used for any device to which you apply the template.

Finally, you'll need to update the API payload to use PMP supported parameters.  Below is a list of what is supported in the payload/body along with a brief description.  In short, you'll need to specify a template to apply and use the "variables" object to set any device-unique values.  I'm guessing for the example you provided this will be the VLAN IP address.  The rest could be set statically in the template if you plan on them being the same for each device.

Payload supported by PMP/ePMP for the device PUT API:

approved:
  description: Pre-approve the device after claim
  type: boolean
description:
  description: Basic information about the device
  type: string
  default: ''
latitude:
  description: Latitude coordinate (in decimal format) of the AP
  type: number
  minimum: -90
  maximum: 90
longitude:
  description: Longitude coordinate (in decimal format) of the AP
  type: number
  minimum: -180
  maximum: 180
name:
  description: Name of the AP
  type: string
  minLength: 2
  maxLength: 64
network:
  description: Name of the network
  type: string
  minLength: 1
template:
  description: The target template name to be applied on the device
  type: string
tower:
  description: Name of the tower
  type: string
  minLength: 1
variables:
  description: User defined variable inside templates
  type: object
  additionalProperties:
    type:
    - string
            - 'null'

Parameters not listed here should not be included in the payload for PMP/ePMP devices.

"variables" is an object of key-value pairs with the key being the replacement variable name defined in the template and the value being the target value for that specific device.  Variables are saved to the database so they can be reused between templates pushes without having to set them every time.  You could even pre-stage values before applying a template.

We are working on improving our API documentation which I think will make it clearer which parameters are for specific device types.

Regards,

Jordan

1 Like

Attemped the query without the overrides and discovered the API expects lat/long as numbers, so I updated the body to:

body = {
	'name': 'TEST_AP_NAME_FIELD',
	'latitude': 41.00000,
	'longitude': -83.00000,
}
This returned an error that the target device did not exist:
{'error': {'message': 'No Device found with MAC: 0a-00-3e-a0-d4-74'}}
However, I can GET the device data a la
requests.get('https://cnmaestro.amplex.net/api/v1/devices/0a-00-3e-a0-d4-74', headers=headers, verify=False).json()
and it returns a nice happy JSON dump of all the device parameters as expected:
>>> {'data': [{'ip': 'xxxxxx, 'maximum_range': 12, 'mac': '0A:00:3E:A0:D4:74', 'config': {'variables': {'LONGITUDE': '-83.32215228050234', 'LATITUDE': '41.38405390913178', 'SRC_MAC': '0A-00-3E-A0-D4-74', 'DISPLAY_NAME': 'xxxxxx'}, 'version': '0'}, 'inactive_software_version': '', 'status': 'online', 'tower': 'xxxxxx', 'location': {'type': 'Point', 'coordinates': ['-83.11111', '+41.11111']}, 'msn': 'xxxxxx', 'managed_account': '', 'type': 'pmp', 'product': 'PMP 450', 'status_time': 12167, 'registration_date': '2017-11-30T13:35:41+00:00', 'software_version': '16.1', 'network': 'Amplex Towers', 'last_reboot_reason': '', 'name': 'xxxxxx', 'hardware_version': 'xxxxxx', 'country': 'United States'}], 'paging': {'limit': 100, 'offset': 0, 'total': 1}}
Is there a different device lookup for update? I don't understand how I can poll live data from the device but when I try to update some of the parameters it's returning a DNE. Thanks again! Jacob

Try providing the MAC address using colon : delimiters instead of hyphens - .

I have logged a bug in our tracking system for this.  The GET and PUT APIs should be consistent in what they allow.

1 Like

Hey Jordan,

Thank you very much for the detailed reply, I do appreciate the clarification provided regarding platform-specific variables.  I will review this in depth after lunch and expore the configuration avenues laid out with templates for the future; that was always the ultimate design goal, my attempts here are an initial discovery process.

Thanks!

Jacob

1 Like

Hello Again!

I have been through the templating documentation and have just a very simple bit of JSON in a template in our cnMaestro instance, but am still running into an issue finding the MAC address of the device I'm trying to update when attempting to execute the PUT verb via the cnMaestro API.

I have attached a screenshot of the template for your reference as well as one of the AP in cnMaestro simply to help confirm that they do actually exist and to allow you to review them for any possible complications.

Again, I'm seeing an ability to communicate with the API normally for this device except in the case of the PUT verb, regardless of the delimited status of the MAC address:

>>> headers = {
...     'Content-Type': "application/json",
...     'Accept': "application/json",
...     'Authorization': "Bearer xxxxxxxxx",
... }
>>> requests.get('https://cnmaestro.amplex.net/api/v1/devices/0a:00:3e:a0:d4:74', headers=headers,).json()
{'paging': {'total': 1, 'offset': 0, 'limit': 100}, 'data': [{'mac': '0A:00:3E:A0:D4:74', 'tower': 'xxxxxxx', 'network': 'Amplex Towers', 'status': 'online', 'managed_account': '', 'hardware_version': '060419', 'country': 'United States', 'location': {'type': 'Point', 'coordinates': ['-83.539148', '+41.556998']}, 'software_version': '16.1', 'inactive_software_version': '', 'type': 'pmp', 'name': 'lab-raysrepeater-ap-57-000', 'status_time': 62549, 'maximum_range': 12, 'last_reboot_reason': '', 'product': 'PMP 450', 'config': {'variables': {'DISPLAY_NAME': 'xxxxxx', 'SRC_MAC': '0A-00-3E-A0-D4-74', 'LONGITUDE': '-83.32215228050234', 'LATITUDE': '41.38405390913178'}, 'version': '0'}, 'registration_date': '2017-11-30T13:35:41+00:00', 'ip': 'xxxxxx', 'msn': 'xxxxxx'}]}

attempting to exercise the update action

>>> body = {“template”: “Test-PMP-57-450”}
>>> requests.put(‘https://cnmaestro.amplex.net/api/v1/devices/0a-00-3e-a0-d4-74’, json=body, headers=headers).json()
{‘error’: {‘message’: ‘No Device found with MAC: 0a-00-3e-a0-d4-74’}}
>>> requests.put(‘https://cnmaestro.amplex.net/api/v1/devices/0a:00:3e:a0:d4:74’, json=body, headers=headers).json()
{‘error’: {‘message’: ‘No Device found with MAC: 0a:00:3e:a0:d4:74’}}
>>> requests.put(‘https://cnmaestro.amplex.net/api/v1/devices/0a003ea0d474’, json=body, headers=headers).json()
{‘error’: {‘message’: ‘Invalid MAC Address 0A003EA0D474’, ‘cause’: ‘Invalid MAC’, ‘level’: ‘error’}}

Am I still fundamentally missing something when configuring on the cnMaestro side or my query, or is there something else happening here?

Thanks again for your help and insight!

Jacob

Hi Jacob,

The PUT API might be case sensitive.  Are you able to perform a PUT using "0A:00:3E:A0:D4:74"?

1 Like

Hey Jordan,

That did the trick!  This appears to be the only PMP endpoint with sensitivity to delimiter and character case; thank you very much for the suggestion :)

The job was scheduled and ran successfully as expected this time around: I confirmed the AP recieved the JSON payload, applied the parameter changes, and rebooted.

Thanks again for your help and patience!

Jacob

1 Like

Glad you got it working and thanks for the confirmation.  I updated our bug ticket to also get the upper case/lower case MAC issue fixed.

1 Like

This has been fixed in release 3.1.1 to allow colon or hyphen delimiters for /devices PUT requests. The MAC address is no longer case sensitive.

1 Like

when is 3.1.1 onprem coming?