Network Tunnel Groups API Guide
This guide provides Python client samples for the Cisco Secure Access Network Tunnel Groups and Regions API.
Note: Your Secure Access API key must have the permissions to read and write on the deployments key scope. For more information about the API key scopes, see Secure Access OAuth 2.0 Scopes.
First get your Secure Access API key, set up your environment, and install the Secure Access API client. For more information, see Samples Overview.
How to Set the Filters Query Parameter with a JSON Object
Several Network Tunnel Groups and Regions API endpoints support query parameters. The /regions GET operation accepts the fields in the Region resource for the filters query parameter. The /networktunnelgroups GET operation accepts the fields in the Network Tunnel Group resource for the filters query parameter.
In this example, we describe the steps to set the filters query parameter with a JSON object on the /regions API request.
You can use the json.dumps method to serialize the JSON object as a string. Then, set the serialized string as the value of filters, and include the query parameter with the API request.
In Python, create a JSON object with the specific fields and values.
data = { "peerIP": "25.123.22.10", "latitude": 39.0299604, "longitude": -77.4771231, "status": "available" }Serialize the JSON object to a JSON-formatted string.
json_filter_string = json.dumps(data)Create a
paramsvariable set to an object with thefiltersfield. Assign the value of the JSON-formatted string to thefiltersfield.params = { "filters": json_filter_string }Create the
/regionsAPI request and set theparamsvariable for the query parameter.response = api.Query(deployments, regions_endpoint, GET, params)
Run the Script
- Copy the script to a local file called
main.py. Locate the script in your environment in a directory above theciscodirectory. - Run
python3 main.py.
main.py
"""
Copyright (c) 2025 Cisco and/or its affiliates.
This software is licensed to you under the terms of the Cisco Sample
Code License, Version 1.1 (the "License"). You may obtain a copy of the
License at
https://developer.cisco.com/docs/licenses
All use of the material herein must be in accordance with the terms of
the License. All rights not expressly granted by the License are
reserved. Unless required by applicable law or agreed to separately in
writing, software distributed under the License is distributed on an "AS
IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied.
"""
import random
import string
import requests
from requests_toolbelt import MultipartEncoder
import json
import os
from dotenv import load_dotenv
from cisco.secure_access import API
from cisco.secure_access import deployments
from cisco.secure_access import GET
from cisco.secure_access import PATCH
from cisco.secure_access import POST
from cisco.secure_access import DELETE
from cisco.secure_access import token_url
from cisco.secure_access import client_id
from cisco.secure_access import client_secret
# Network Tunnel Groups and Regions API endpoints
ntg_endpoint = "networktunnelgroups"
ntg_details_endpoint = ntg_endpoint + "/{}"
ntg_details_state_endpoint = ntg_endpoint + "/{}/state"
ntg_details_state_peers_endpoint = ntg_endpoint + "/{}/peers"
ntg_details_hub_peer_state_endpoint = ntg_endpoint + "/{}/networktunnelhubs/{}/peers/{}/state"
ntg_all_states_endpoint = "networktunnelgroupsstate"
regions_endpoint = "regions"
load_dotenv()
def get_network_tunnel_groups(api):
''' Get Network Tunnel Groups. '''
try:
# Get Network Tunnel Groups in the organization
ntg_endpoint_statuses = ntg_endpoint + "?includeStatuses=true"
response = api.Query(deployments, ntg_endpoint_statuses, GET)
# Check if the API request was successful
if response.status_code == 200:
print(f"Success. GET {ntg_endpoint}, {response.json()}")
return response.json()
else:
print(f"Failed to get the Network Tunnel Groups. Status code: {response.status_code}, Response: {response.text}.")
return None
except requests.exceptions.RequestException as e:
print(f"An error occurred: {e}.")
def post_network_tunnel_group(api, payload=None):
''' Create a Network Tunnel Group. '''
try:
if payload['name'] is None or payload['passphrase'] is None or payload['authIdPrefix'] is None or payload['region'] is None:
raise ValueError("name, passphrase, authIdPrefix, and region are required to create the Network Tunnel Group.")
# Create a Network Tunnel Group
response = api.Query(deployments, ntg_endpoint, POST, payload)
# Check the response status
if response.status_code == 201:
print(f"Success. POST {ntg_endpoint}, {response.json()}")
return response.json()
else:
print(f"Failed to create the Network Tunnel Group. Status code: {response.status_code}, Response: {response.text}.")
return None
except Exception as e:
print(f"An error occurred: {e}.")
def get_network_tunnel_group(api, id):
''' Get the properties of the Network Tunnel Group. '''
try:
if id is None:
raise ValueError("id is required to get the Network Tunnel Group.")
url = ntg_details_endpoint.format(id)
# Get the properties for the Network Tunnel Group
response = api.Query(deployments, url, GET)
# Check if the API request was successful
if response.status_code == 200:
print(f"Success. GET {url}, {response.json()}.")
return response.json()
else:
print(f"Failed to get the Network Tunnel Group {id}. Status code: {response.status_code}, Response: {response.text}.")
return
except Exception as e:
print(f"An error occurred: {e}.")
def patch_network_tunnel_group(api, id, payload=None):
''' Set the properties of the Network Tunnel Group. '''
try:
if id is None:
raise ValueError("id is required to get the Network Tunnel Group.")
url = ntg_details_endpoint.format(id)
# Update the properties for the Network Tunnel Group
response = api.Query(deployments, url, PATCH, payload)
# Check if the API request was successful
if response.status_code == 200:
print(f"Success. PATCH {url}, {response.json()}.")
return response.json()
else:
print(f"Failed to update the Network Tunnel Group {id}. Status code: {response.status_code}, Response: {response.text}.")
return
except Exception as e:
print(f"An error occurred: {e}.")
def delete_network_tunnel_group(api, id):
''' Delete the Network Tunnel Group. '''
try:
if id is None:
raise ValueError("id is required to delete the Network Tunnel Group.")
url = ntg_details_endpoint.format(id)
# Delete the Network Tunnel Group
response = api.Query(deployments, url, DELETE)
# Check if the API request was successful
if response.status_code == 204:
print(f"No Content. DELETE {url}.")
else:
print(f"Failed to delete the Network Tunnel Group {id}. Status code: {response.status_code}, Response: {response.text}.")
except Exception as e:
print(f"An error occurred: {e}.")
def get_network_tunnel_group_state(api, id):
''' Get the state information for the Network Tunnel Group. '''
try:
if id is None:
raise ValueError("id is required to get the Network Tunnel Group.")
url = ntg_details_state_endpoint.format(id)
# Get the state information for the Network Tunnel Group
response = api.Query(deployments, url, GET)
# Check if the API request was successful
if response.status_code == 200:
print(f"Success. GET {url}, {response.json()}.")
return response.json()
else:
print(f"Failed to get the state information for the Network Tunnel Group {id}. Status code: {response.status_code}, Response: {response.text}.")
return
except Exception as e:
print(f"An error occurred: {e}.")
def get_network_tunnel_group_states_peers(api, id):
''' Get the state information for the tunnels (peers) in the Network Tunnel Group. '''
try:
if id is None:
raise ValueError("id of the Network Tunnel Group is required to get the tunnels.")
url = ntg_details_state_peers_endpoint.format(id)
# Get the state information for the peers
response = api.Query(deployments, url, GET)
# Check if the API request was successful
if response.status_code == 200:
print(f"Success. GET {url}, {response.json()}.")
return response.json()
else:
print(f"Failed to get the state information for peers in the Network Tunnel Group {id}. Status code: {response.status_code}, Response: {response.text}.")
return
except Exception as e:
print(f"An error occurred: {e}.")
def get_ntg_hub_peer_state(api, id=None, hub_id=None, peer_id=None):
''' Get state information for a peer in the hub and Network Tunnel Group. '''
try:
# Get state information for a peer in the hub and Network Tunnel Group.
if id is None or hub_id is None or peer_id is None:
raise ValueError("id, hub_id, and peer_id are required to get the state information for hub, peer in the Network Tunnel Group.")
# Format the URL with the network tunnel group id
url = ntg_details_hub_peer_state_endpoint.format(id).format(hub_id).format(peer_id)
response = api.Query(deployments, url, GET)
# Check if the API request was successful
if response.status_code == 200:
print(f"Success. GET {url}, {response.json()}")
return response.json()
else:
print(f"Failed to get the state information for a peer in the hub and Network Tunnel Group. Status code: {response.status_code}, Response: {response.text}.")
return None
except requests.exceptions.RequestException as e:
print(f"An error occurred: {e}.")
def get_states_network_tunnel_groups(api):
''' Get states for the Network Tunnel Groups. '''
try:
# Get states of the Network Tunnel Groups.
response = api.Query(deployments, ntg_all_states_endpoint , GET)
# Check if the API request was successful
if response.status_code == 200:
print(f"Success. GET {ntg_all_states_endpoint}, {response.json()}")
return response.json()
else:
print(f"Failed to get the states for the Network Tunnel Groups. Status code: {response.status_code}, Response: {response.text}.")
return None
except requests.exceptions.RequestException as e:
print(f"An error occurred: {e}.")
def get_regions(api):
''' Get Regions for Network Tunnel Groups. '''
try:
# Get the regions for the Network Tunnel Groups in the organization.
response = api.Query(deployments, regions_endpoint, GET)
# Check if the API request was successful
if response.status_code == 200:
print(f"Success. GET {regions_endpoint}, {response.json()}")
return response.json()
else:
print(f"Failed to get the regions for the Network Tunnel Groups. Status code: {response.status_code}, Response: {response.text}.")
return None
except requests.exceptions.RequestException as e:
print(f"An error occurred: {e}.")
def get_random_string(length):
letters_and_digits = string.ascii_letters + string.digits
return ''.join(random.choice(letters_and_digits) for i in range(length))
def main():
# Exit out if the required client_id or client_secret is not set
for var in ['API_KEY', 'API_SECRET', 'OUTPUT_DIR']:
if os.environ.get(var) == None:
print("Required environment variable: {} not set".format(var))
exit()
# Get an API token
api = API(token_url, client_id, client_secret)
try:
# Get the network tunnel groups in the organization
json_data = get_network_tunnel_groups(api)
# Create a network tunnel group
length = 10
random_string = get_random_string(length)
# Create the data for the request body
request_data = {}
request_data['name'] = "Network Tunnel Group " + random_string
request_data['passphrase'] = "abcdefghijLMNOP1"
request_data['authIdPrefix'] = "test-tunnel-12-24"
request_data['region'] = "us-east-1"
# use default (nat) routing for Network Tunnel Group
json_data = post_network_tunnel_group(api, request_data)
# Read the data from the serialized file for the newly created network tunnel group.
id = None
primary_hub_id = None
secondary_hub_id = None
if 'id' in json_data:
id = json_data['id']
if 'hubs' in json_data:
# get the hub IDs to query for state information
primary_hub_id = json_data['hubs'][0]['id']
secondary_hub_id = json_data['hubs'][1]['id']
print(f"The tunnel group ID: {id}, primary hub ID: {primary_hub_id}, secondary hub ID: {secondary_hub_id}.")
# Get the details for a network tunnel group
json_data = get_network_tunnel_group(api, id)
# Patch the network tunnel group
random_string = get_random_string(length)
request_data = []
data = {}
data['op'] = "replace"
data['path'] = "/name"
data['value'] = "New NTG " + random_string
request_data.append(data)
json_data = patch_network_tunnel_group(api, id, request_data)
# Get state information for specific network tunnel group
json_data = get_network_tunnel_group_state(api, id)
# Get states of the peers (tunnels)
json_data = get_network_tunnel_group_states_peers(api, id)
peer_id = None
if json_data:
peer_id = json_data[0]['peerId']
# Get state information for specific peer, hub, and network tunnel group.
hub_id = primary_hub_id # could use secondary hub
get_ntg_hub_peer_state(api, id, hub_id, peer_id)
# Get states of all network tunnel groups
get_states_network_tunnel_groups(api)
# Get region and bgp information for the organization
get_regions(api, regions_endpoint)
# Delete the network tunnel group
delete_network_tunnel_group(api, id)
except Exception as e:
print(e)
if __name__ == "__main__":
main()