Troubleshooting ISE SDK Issues

Overview

When ISE doesn’t behave as expected (like parent groups not nesting properly), the issue is often a mismatch between what netapi sends and what the ciscoisesdk expects.

This guide shows you how to debug these issues yourself.

Common Issue: Parameter Name Mismatch

Symptom

# You create a child group with --parent
netapi ise create-endpoint-group "Linux-Research-Workstations" \
  --description "Child group" \
  --parent "Linux-Workstations"

# ✓ Command succeeds (no error)
# ✗ But in ISE GUI, groups are independent (no hierarchy)

The command doesn’t fail, but the parent relationship is silently ignored.

Root Cause

netapi might be using the wrong parameter name: - netapi sends: parentId (camelCase) - ISE SDK expects: parent_id (snake_case)

ISE ignores unknown parameters, so it creates the group without the parent.

How to Debug This Yourself

Step 1: Inspect the SDK Method Signature

Check what parameters the ciscoisesdk method actually expects:

python3 << 'EOF'
import inspect
from ciscoisesdk import IdentityServicesEngineAPI

# Create dummy client (doesn't need to connect)
client = IdentityServicesEngineAPI(
    username="dummy",
    password="dummy",
    base_url="https://dummy"
)

# Get the method you're debugging
method = client.endpoint_identity_group.create_endpoint_group

# Print the signature
sig = inspect.signature(method)
print("create_endpoint_group parameters:")
for param_name, param in sig.parameters.items():
    print(f"  {param_name}: {param.annotation if param.annotation != inspect.Parameter.empty else 'Any'}")
EOF

Output:

create_endpoint_group parameters:
  description: Any
  name: Any
  system_defined: Any
  parent_id: Any          <-- SNAKE_CASE, not parentId!
  headers: Any
  payload: Any
  active_validation: Any
  query_parameters: Any

Step 2: Check What netapi is Sending

Look at the code in ers_client.py:

# Find the create method
grep -n "def create_endpoint_group" \
  ~/atelier/_projects/personal/netapi/netapi/vendors/cisco/ise/ers_client.py

Read the method (e.g., line 572):

# Read the method implementation
cat -n ~/atelier/_projects/personal/netapi/netapi/vendors/cisco/ise/ers_client.py \
  | sed -n '572,620p'

Look for the line that builds the payload:

# WRONG (camelCase)
payload["parentId"] = parent.get("id")

# CORRECT (snake_case)
payload["parent_id"] = parent.get("id")

Step 3: Fix the Parameter Name

Edit ers_client.py:

cd ~/atelier/_projects/personal/netapi

# Open in your editor
nvim netapi/vendors/cisco/ise/ers_client.py +609

Change:

# Before
payload["parentId"] = parent.get("id")

# After
payload["parent_id"] = parent.get("id")

Step 4: Test the Fix

# Delete old groups
netapi ise delete-endpoint-group "Linux-Research-Workstations"
netapi ise delete-endpoint-group "Linux-Workstations"

# Recreate with parent
netapi ise create-endpoint-group "Linux-Workstations" \
  --description "Parent group"

netapi ise create-endpoint-group "Linux-Research-Workstations" \
  --description "Child group" \
  --parent "Linux-Workstations"

# Verify in ISE GUI - should now show proper hierarchy

Step 5: Commit the Fix

cd ~/atelier/_projects/personal/netapi

git add netapi/vendors/cisco/ise/ers_client.py
git commit -m "[fix] Endpoint group parent - use parent_id not parentId

Bug: parentId (camelCase) was silently ignored by ISE SDK
Fix: Changed to parent_id (snake_case) per ciscoisesdk signature

Location: ers_client.py:609"

Common Parameter Naming Issues

Wrong (ignored by SDK) Correct (SDK expects) Resource

parentId

parent_id

Endpoint Groups

groupId

group_id

Endpoints

dacl

dacl or daclName

Authorization Profiles (depends on API)

vlanId

vlan (name) or tagId (number)

Authorization Profiles

Rule of thumb: ISE SDK uses snake_case for parameters, not camelCase.

Debugging Workflow Summary

# 1. Inspect SDK method signature
python3 -c "
import inspect
from ciscoisesdk import IdentityServicesEngineAPI
client = IdentityServicesEngineAPI(username='x', password='x', base_url='https://x')
method = client.<resource>.<method_name>
print(inspect.signature(method))
"

# 2. Find netapi implementation
grep -n "def <method_name>" \
  ~/atelier/_projects/personal/netapi/netapi/vendors/cisco/ise/ers_client.py

# 3. Read the code
cat -n ~/atelier/_projects/personal/netapi/netapi/vendors/cisco/ise/ers_client.py \
  | sed -n '<line_start>,<line_end>p'

# 4. Fix parameter name mismatch
# Edit ers_client.py and change camelCase to snake_case

# 5. Test
netapi ise <command> <args>

# 6. Commit
git add netapi/vendors/cisco/ise/ers_client.py
git commit -m "[fix] <description>"

Other Debugging Techniques

Enable SDK Debug Logging

Set debug logging to see raw API calls:

import logging
logging.basicConfig(level=logging.DEBUG)

# Then run your netapi command
# You'll see HTTP requests/responses in the logs

Check ISE ERS API Documentation

Official Cisco ISE ERS API reference shows exact field names:

# ISE GUI: Administration > System > Settings > ERS Settings > SDK Download
# Or: https://<ISE_PAN>:9060/ers/sdk

Compare the JSON schema in the docs to what netapi is sending.

Use ISE API Inspector

ISE has built-in API logging:

  1. Enable ERS API logging: Administration > System > Logging > Debug Log Configuration

  2. Set level: ers component to DEBUG

  3. Watch logs: Operations > Troubleshoot > Debug Logs > Download Logs

  4. Search for: Your API calls and see what payload ISE received

Test with curl

Bypass netapi and test the API directly:

# Get credentials
eval "$(dsec source d000 dev/ise)"

# Test endpoint group creation with parent_id
curl -k -u "${ISE_API_USER}:${ISE_API_PASS}" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -X POST "https://${ISE_PAN_IP}:9060/ers/config/endpointgroup" \
  -d '{
    "EndpointGroup": {
      "name": "Test-Child-Group",
      "description": "Testing parent_id",
      "parent_id": "<parent-group-uuid>"
    }
  }'

If curl works but netapi doesn’t, the issue is in netapi’s code.

Real-World Example: Endpoint Group Parent

Problem: Groups created with --parent were independent, not nested.

Investigation:

# 1. Check SDK signature
python3 -c "
import inspect
from ciscoisesdk import IdentityServicesEngineAPI
client = IdentityServicesEngineAPI(username='x', password='x', base_url='https://x')
print(inspect.signature(client.endpoint_identity_group.create_endpoint_group))
"

# Output showed: parent_id (not parentId)

Code Review:

# ers_client.py:609 (WRONG)
payload["parentId"] = parent.get("id")

# Should be (CORRECT)
payload["parent_id"] = parent.get("id")

Fix:

# Changed parentId → parent_id
# Committed with git commit
# Tested - groups now nest properly

Quick Reference: Inspecting Other Methods

Check Authorization Profile Parameters

python3 << 'EOF'
import inspect
from ciscoisesdk import IdentityServicesEngineAPI

client = IdentityServicesEngineAPI(username="x", password="x", base_url="https://x")
method = client.authorization_profile.create_authorization_profile

sig = inspect.signature(method)
print("create_authorization_profile parameters:")
for param_name in sig.parameters.keys():
    print(f"  {param_name}")
EOF

Check Network Device Parameters

python3 << 'EOF'
import inspect
from ciscoisesdk import IdentityServicesEngineAPI

client = IdentityServicesEngineAPI(username="x", password="x", base_url="https://x")
method = client.network_device.create_network_device

sig = inspect.signature(method)
print("create_network_device parameters:")
for param_name in sig.parameters.keys():
    print(f"  {param_name}")
EOF

Check SGT Parameters

python3 << 'EOF'
import inspect
from ciscoisesdk import IdentityServicesEngineAPI

client = IdentityServicesEngineAPI(username="x", password="x", base_url="https://x")
method = client.security_groups.create_security_group

sig = inspect.signature(method)
print("create_security_group parameters:")
for param_name in sig.parameters.keys():
    print(f"  {param_name}")
EOF

Prevention: Check Before Implementing

When adding a new netapi command:

# 1. Always check SDK signature first
python3 -c "
import inspect
from ciscoisesdk import IdentityServicesEngineAPI
client = IdentityServicesEngineAPI(username='x', password='x', base_url='https://x')
print(inspect.signature(client.<resource>.<method>))
"

# 2. Match parameter names exactly (use snake_case)
# 3. Test with a simple case
# 4. Verify in ISE GUI that the result is correct