cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
1073
Views
1
Helpful
5
Replies

DNAC API trying to search hostname case insensative

brunop
Level 1
Level 1
Is there a way to do a case-insensitive search using the api?  Desired results would be to return devices named TEST, test, Test, etc
 
Example code:

 

 

import requests
import json

USER = 'REMOVED'
PASSWORD = 'REMOVED'
BASE_URL = 'https://dna.server.com/dna'

AUTH = requests.auth.HTTPBasicAuth(USER, PASSWORD)
AUTH_RESPONSE = requests.post(BASE_URL + '/system/api/v1/auth/token', auth=AUTH, verify=False)

TOKEN = json.loads(AUTH_RESPONSE.text)['Token']

HEADERS = { 'X-Auth-Token': TOKEN }
RESOURCE = '/intent/api/v1/network-device' + '?hostname=.*test.*'

call_response = requests.get(BASE_URL + RESOURCE, headers=HEADERS, verify=False)
devices = json.loads(call_response.text)['response']

for device in devices:
    print('Hostname: {hostname}, Type: {type}, MAC: {mac}, Serial: {serial}'.format(serial=device['serialNumber'],hostname=device['hostname'],type=device['type'],mac=device['macAddress']))

 

 

 
5 Replies 5

yawming
Cisco Employee
Cisco Employee

Python is case sensitive, so search for the "test" won't get the "TEST".
To search TEST, test, and Test may need to do the search 3 times.

I don't think this is correct.  My python code is not doing the comparison, it is the API that is returning results based on the supplied criteria.

In python:  "test".casefold() == "TEST".casefold() is a true statement.

In the DNAC web interface the advanced searches are not case sensitive.  The API should be capable of doing similar.

I can use '.*TEST.*' to search for devices containing the work for example: 'switchTESTdevice' but only if its an exact match.

Sorry that misunderstood you, you are asking for case -INsensitive not sensitive. Which I don't know if we can do it within DNAC API, but if we do the search from the response then we can do that of cause.

Jesus Illescas
Cisco Employee
Cisco Employee

At least on 2.3.3.6-70045 I see the API is not doing a case insensitive match.

I'm thinking of the following options. One could be to use a simpler query like ".*est.* instead of ".*test.* so you can get results from "test" and "Test".

Another option is to calculate the combinations you have available between uppercase and lowercase for the query you want. For example "TEST, test, Test, tesT, ..." and perform an API call for each one. If you are interested in this option, I did this small test.

 

 

import json
import requests
from itertools import product
from typing import List

USER = "USERNAME"
PASSWORD = "PASSWORD"
BASE_URL = "https://DNA/dna"

AUTH = requests.auth.HTTPBasicAuth(USER, PASSWORD)
AUTH_RESPONSE = requests.post(
    BASE_URL + "/system/api/v1/auth/token", auth=AUTH, verify=False
)

TOKEN = json.loads(AUTH_RESPONSE.text)["Token"]
HEADERS = {"X-Auth-Token": TOKEN}

# https://stackoverflow.com/a/69782247/922218
def case_insensitive(pattern: str) -> List[str]:
    result: List = []
    cases = zip(*[pattern, pattern.swapcase()])
    for permutation in product(*cases):
        result.append("".join(permutation))
    return result


devices: List = []
hosts = case_insensitive(pattern="edge")

for host in hosts:
    RESOURCE = f"/intent/api/v1/network-device?hostname=.*{host}.*"
    call_response = requests.get(BASE_URL + RESOURCE, headers=HEADERS, verify=False)
    devices += json.loads(call_response.text)["response"]


for device in devices:
    print(
        "Hostname: {hostname}, Type: {type}, MAC: {mac}, Serial: {serial}".format(
            serial=device["serialNumber"],
            hostname=device["hostname"],
            type=device["type"],
            mac=device["macAddress"],
        )
    )

 

 

However, this is not optimal. For an 4 letter input, you will have a 16 possible combinations, so 16 APIs call. In Big O notation, this will be a O(n²), which is not good. So if you go with this option, be careful with larger inputs.

Probably the best approach is to normalize hostnames, so this situation can be minimized.