cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
2177
Views
30
Helpful
5
Replies

Cisco ISE 3.1 RESTful API - HTTP PUT for updating NADs is not working

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

 

1 Accepted Solution

Accepted Solutions

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": {}
    }
  }
}

 

 

View solution in original post

5 Replies 5

Mike.Cifelli
VIP Alumni
VIP Alumni

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.  

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": {}
    }
  }
}

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.

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": {}
    }
  }
}

 

 

a.mitsova
Level 1
Level 1

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)