03-16-2022 07:42 AM
Hello community,
I'm working on creating an automated way to manage NADs on Cisco ISE via RESTful API in Python.
I'm relying on the requests library, but unfortunately when I try to use the PUT operation to update NAD with new information, I receive a status code of 400 with the following error code:
{ "ERSResponse" : { "operation" : "PUT-update by name-networkdevice", "messages" : [ { "title" : "Resource Initialization Failed: Invalid JSON: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token\n ", "type" : "ERROR", "code" : "Application resource validation exception" } ], "link" : { "rel" : "related", "href" : "https://192.168.100.100:9060/ers/config/networkdevice/name/TEST", "type" : "application/xml" } } }
I didn't see this error message before and I was also unable to find any other reference to this, so I'm relying on you, experts, to help me figure this one out.
I'm using ISE VM version 3.1.0.518 running in eve-ng emulator for testing the solution.
Below is the relevant piece of code that I use to make the PUT operation:
url = f"{self.url_base}/config/networkdevice" nad_url = requests.put(f"{url}/name/{nad_name}", headers=self.headers, auth=self.auth, data=json.dumps(payload, indent=2), verify=False)
The "payload" variable holds the actual content in JSON format for updating the NAD that I've already verified through https://jsonformatter.curiousconcept.com/# as valid.
For a reference, I obtained the output of how the payload actually looks like after Python processes my code:
{ "NetworkDevice": { "id": "65afd750-a4a3-11ec-aa9f-e2a4bd57a766", "name": "TEST", "description": "test123", "authenticationSettings": { "networkProtocol": "RADIUS", "radiusSharedSecret": "Test132*", "enableKeyWrap": false, "dtlsRequired": false, "keyEncryptionKey": "", "messageAuthenticatorCodeKey": "", "keyInputFormat": "ASCII", "enableMultiSecret": false }, "tacacsSettings": { "sharedSecret": "Test124", "connectModeOptions": "ON_LEGACY", "previousSharedSecret": "", "previousSharedSecretExpiry": "" }, "profileName": "Cisco", "coaPort": 1700, "link": { "rel": "self", "href": "https://192.168.100.100:9060/ers/config/networkdevice/name/TEST", "type": "application/json" }, "NetworkDeviceIPList": { "ipaddress": "1.1.1.2", "mask": 32 }, "NetworkDeviceGroupList": [ "Device Type#All Device Types", "IPSEC#Is IPSEC Device#No", "Location#All Locations" ] } }
I've already tried some other HTTP operations with the requests package, such as GET and DELETE. Both of them are working beautifully, so I assume I must be making some mistake in specifying the payload structure for the PUT operation.
To build the JSON structure, I followed https://developer.cisco.com/docs/identity-services-engine/v1/#!networkdevice
Any help/advise would be much appreciated.
Regards,
Tomas
Solved! Go to Solution.
03-16-2022 12:03 PM
Thank you Thomas.
Issue has been resolved. I forgot to wrap the "NetworkDeviceGroupList" in a list, therefore it was screaming at me the invalid JSON format error.
For other people's reference I'm including a sample payload that is working on the latest ISE version 3.1
{ "NetworkDevice": { "id": "65afd750-a4a3-11ec-aa9f-e2a4bd57a766", "name": "TEST", "description": "test123", "profileName": "Cisco", "coaPort": 1700, "modelName": "C4701", "softwareVersion": "16.2.3(S)1", "authenticationSettings": { "networkProtocol": "RADIUS", "radiusSharedSecret": "Test132*", "enableKeyWrap": false, "dtlsRequired": false, "keyEncryptionKey": "", "keyInputFormat": "ASCII", "messageAuthenticatorCodeKey": "", "enableMultiSecret": "false" }, "tacacsSettings": { "sharedSecret": "Test124", "connectModeOptions": "ON_LEGACY", "previousSharedSecret": "test123", "previousSharedSecretExpiry": 0 }, "NetworkDeviceIPList": [ { "ipaddress": "1.1.1.2", "mask": 32 } ], "NetworkDeviceGroupList": [ "Device Type#All Device Types", "IPSEC#Is IPSEC Device#No", "Location#All Locations" ], "snmpsettings": { "linkTrapQuery": false, "macTrapQuery": false, "originatingPolicyServicesNode": "Auto", "pollingInterval": 28800 }, "trustsecsettings": { "deviceAuthenticationSettings": {}, "deviceConfigurationDeployment": {}, "sgaNotificationAndUpdates": {} } } }
03-16-2022 10:15 AM
It seems that your json payload my be missing some required strings. Here is an example of a payload used when updating an existing NAD via API. Note that this was used with older versions of ISE.
API_DATA = {
"NetworkDevice": {
"id": temp2,
"name": "zzyy" + NAD_NAME,
"profileName": "Cisco",
"coaPort": "1700",
"authenticationSettings" : {
},
"snmpsettings" : {
"pollingInterval" : 3600,
"linkTrapQuery" : "false",
"macTrapQuery" : "false",
},
"trustsecsettings" : {
"deviceAuthenticationSettings" : {
},
"sgaNotificationAndUpdates" : {
"downlaodEnvironmentDataEveryXSeconds" : 86400,
"downlaodPeerAuthorizationPolicyEveryXSeconds" : 86400,
"reAuthenticationEveryXSeconds" : 86400,
"downloadSGACLListsEveryXSeconds" : 86400,
"otherSGADevicesToTrustThisDevice" : "true",
"sendConfigurationToDevice" : "true",
"sendConfigurationToDeviceUsing" : "ENABLE_USING_COA",
"coaSourceHost" : "abcdefg"
},
"deviceConfigurationDeployment" : {
"includeWhenDeployingSGTUpdates" : "true",
}
},
"NetworkDeviceIPList": [
{
"ipaddress": IP_ADDR,
"mask": 32,
}
],
"NetworkDeviceGroupList": [
"Location#All Locations#" + LOC,
"Device Type#All Device Types#ZZZZ#" + OWNER,
"IPSEC#Is IPSEC Device#No",
]
}
}
API_DEVICE = "https://<isepan>:9060/ers/config/networkdevice/" + temp2
API_ERS_USER = "user","password"
r = requests.put(url=API_DEVICE, auth=API_ERS_USER, json=API_DATA, verify=True)
Note that there are some variables referenced that will have to be modified to meet your needs, but hopefully this helps you troubleshoot further.
03-16-2022 11:06 AM
Thanks Mike, that's a great advise.
I went through the documentation again and indeed I missed a few required items.
After filling in all the missing required parts, it seems I finally managed to move forward, although the issue is still not resolved.
I think I'm now getting stuck with the "enabled" boolean that is, according to the documentation, required to be specified under "authenticationSettings" list.
If I don't specify it, the error message I get is exactly the same.
When I specify it, it returns a different error with the same status code of 400:
{ "ERSResponse" : { "operation" : "PUT-update by name-networkdevice", "messages" : [ { "title" : "Resource Initialization Failed: Invalid JSON: Unrecognized field \"enabled\" (Class network.AuthenticationSettings), not marked as ignorable\n ", "type" : "ERROR", "code" : "Application resource validation exception" } ], "link" : { "rel" : "related", "href" : "https://192.168.100.100:9060/ers/config/networkdevice/name/TEST", "type" : "application/xml" } } }
This is the current content of the payload after update:
{ "NetworkDevice": { "id": "65afd750-a4a3-11ec-aa9f-e2a4bd57a766", "name": "TEST", "description": "test123", "profileName": "Cisco", "coaPort": 1700, "modelName": "C4701", "softwareVersion": "16.2.3(S)1", "authenticationSettings": { "radiusSharedSecret": "Test132*", "enableKeyWrap": false, "keyEncryptionKey": "", "keyInputFormat": "ASCII", "enabled": true }, "tacacsSettings": { "sharedSecret": "Test124" }, "link": { "rel": "self", "href": "https://192.168.100.100:9060/ers/config/networkdevice/name/TEST", "type": "application/json" }, "NetworkDeviceIPList": { "ipaddress": "1.1.1.2", "mask": 32, "getIpaddressExclude": "" }, "NetworkDeviceGroupList": [ "Device Type#All Device Types", "IPSEC#Is IPSEC Device#No", "Location#All Locations" ], "snmpsettings": { "linkTrapQuery": false, "macTrapQuery": false, "originatingPolicyServicesNode": "Auto", "pollingInterval": 28800 }, "trustsecsettings": { "deviceAuthenticationSettings": {}, "deviceConfigurationDeployment": {}, "sgaNotificationAndUpdates": {} } } }
03-16-2022 11:46 AM
It is not clear what exactly you are changing with the PUT.
Perform a GET on the specific network device you want to change.
Take that JSON output and compare to what you are trying to PUT.
The problem lies in that diff.
The only thing you do not need to include is
"link": { "rel": "self", "href": "https://192.168.100.100:9060/ers/config/networkdevice/name/TEST", "type": "application/json" },
Anything that you leave out will be deleted.
ISE does not yet have a PATCH capability so you must include everything else you want in the resource.
03-16-2022 12:03 PM
Thank you Thomas.
Issue has been resolved. I forgot to wrap the "NetworkDeviceGroupList" in a list, therefore it was screaming at me the invalid JSON format error.
For other people's reference I'm including a sample payload that is working on the latest ISE version 3.1
{ "NetworkDevice": { "id": "65afd750-a4a3-11ec-aa9f-e2a4bd57a766", "name": "TEST", "description": "test123", "profileName": "Cisco", "coaPort": 1700, "modelName": "C4701", "softwareVersion": "16.2.3(S)1", "authenticationSettings": { "networkProtocol": "RADIUS", "radiusSharedSecret": "Test132*", "enableKeyWrap": false, "dtlsRequired": false, "keyEncryptionKey": "", "keyInputFormat": "ASCII", "messageAuthenticatorCodeKey": "", "enableMultiSecret": "false" }, "tacacsSettings": { "sharedSecret": "Test124", "connectModeOptions": "ON_LEGACY", "previousSharedSecret": "test123", "previousSharedSecretExpiry": 0 }, "NetworkDeviceIPList": [ { "ipaddress": "1.1.1.2", "mask": 32 } ], "NetworkDeviceGroupList": [ "Device Type#All Device Types", "IPSEC#Is IPSEC Device#No", "Location#All Locations" ], "snmpsettings": { "linkTrapQuery": false, "macTrapQuery": false, "originatingPolicyServicesNode": "Auto", "pollingInterval": 28800 }, "trustsecsettings": { "deviceAuthenticationSettings": {}, "deviceConfigurationDeployment": {}, "sgaNotificationAndUpdates": {} } } }
09-29-2022 11:06 AM - edited 09-30-2022 02:28 PM
Many, many thanks for this discussion! I was struggling hours on the same problem. Below my python code for a really old ISE version 2.2.0.470 (with patches 2,4,5,9,13). Hopefully it will be useful for other people:
#!/usr/bin/env python3
import requests
from urllib3.exceptions import InsecureRequestWarning
import json
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
url = "https://x.x.x.x:9060/ers/config/networkdevice"
header = {'accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Basic ZXJzLXVzcjI6UGFzc3dvcmQxMjM0',
'Cache-Control': 'no-cache'}
username = 'ers-usr2'
password = 'Password1234'
payload = {
"NetworkDevice": {
"id": "5678",
"name": "TEST-DEVICE2",
"authenticationSettings": {
"networkProtocol": "RADIUS",
"radiusSharedSecret": "cisco1234",
"enableKeyWrap": False,
"keyInputFormat": "ASCII"
},
"tacacsSettings": {
"sharedSecret": "Cisco1234",
"connectModeOptions": "OFF",
"previousSharedSecret": "test123",
"previousSharedSecretExpiry": 0
},
"profileName": "Cisco",
"coaPort": 1700,
"NetworkDeviceIPList": [{
"ipaddress": "192.168.4.5",
"mask": 32
}],
"NetworkDeviceGroupList": ["Device Type#All Device Types#IPC#SWITCH#SLAN", "IPSEC#Is IPSEC Device#No", "Location#All Locations"]
}
}
response = requests.post(url, proxies={'http': None, 'https': None}, data=json.dumps(payload), auth=requests.auth.HTTPBasicAuth(username, password), headers=header, verify=False)
print(response)
Discover and save your favorite ideas. Come back to expert answers, step-by-step guides, recent topics, and more.
New here? Get started with these tips. How to use Community New member guide