Cisco Secure Access Network Tunnel Groups API sample script

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.

  1. 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"
    }
    
  2. Serialize the JSON object to a JSON-formatted string.

    json_filter_string = json.dumps(data)
    
  3. Create a params variable set to an object with the filters field. Assign the value of the JSON-formatted string to the filters field.

        params = {
        "filters": json_filter_string
    }
    
  4. Create the /regions API request and set the params variable for the query parameter.

    response = api.Query(deployments, regions_endpoint, GET, params)
    

Run the Script

  1. Copy the script to a local file called main.py. Locate the script in your environment in a directory above the cisco directory.
  2. 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()