To run this code directly, download the .py file.
Using the E2E Controller API¶
This notebook shows a Python example of an external client that reads from / writes to a controller running on TGNMS. The full API docs can be found at your-nms-ip/docs/. First check that you can reach the API. The example here uses a TGNMS instance located at https://labnmsbeta.terragraph.link
, so you should change this to the IP address or hostname of your TGNMS instance.
[1]:
import requests
import json
import random
import urllib.parse
network_name = "F8 IF Rack"
base_url = "https://labnmsbeta.terragraph.link"
api_url = f"{base_url}/api/{urllib.parse.quote(network_name)}/"
# This returns an HTTP 401: Unauthorized since we haven't authenticated with Keycloak yet
response = requests.get(api_url + "api/v2/getTopology")
print(response)
<Response [401]>
Go to your NMS’s Keycloak page and add a client for your application. Visit your-nms-ip/auth and log into Keycloak. The username is root
and the password can be found either in your config.yml
or on the machine running NMS at /opt/terragraph/creds.yml
under keycloak_root_password
.
You will be presented with this page at log in, click “Clients” on the sidebar then “Create” and add your client.
Next change the “Access Type” of your client to “confidential”, enable “Service Accounts”, and add a redirect URL (this can be the IP or hostname of your NMS instance) then copy the secret from the “Credentials” tab. It will be something like cf0c3940-283n-49a5-99f2-affd03de91eb
. Finally, make sure to enable the scopes needed for your application under “Service Account Roles” (for this demo my-test-app
uses all available roles). Now we can curl
for the token like so:
$ curl -L -d 'grant_type=client_credentials' -d 'client_id=my-test-app' -d 'client_secret=cf0c3940-283n-49a5-99f2-affd03de91eb' -H 'Content-Type: application/x-www-form-urlencoded' --noproxy '*' -X POST https://labnmsbeta.terragraph.link/auth/realms/tgnms/protocol/openid-connect/token
{"access_token": "....", ...}
Now we will do this same thing in Python and use the access_token
to request getTopology
.
[2]:
# First, get the token
auth_url = f"{base_url}/auth/realms/tgnms/protocol/openid-connect/token"
# Change the client_id and client_secret to match your Keycloak client
data = {
"grant_type": "client_credentials",
"client_id": "my-test-app",
"client_secret": "cf0c6281-4d2c-49a5-99f2-affd03de91eb",
}
# Make the request
response = requests.post(auth_url, data=data).json()
access_token = response["access_token"]
auth_header = {"Authorization": f"Bearer {access_token}"}
# Now make an authenticated request to the API and see the result
response = requests.get(api_url + "api/v2/getTopology", headers=auth_header)
print(response.content.decode()[:100] + "...")
{"name":"","nodes":[{"name":"pop-if6","node_type":2,"is_primary":true,"mac_addr":"34:ef:b6:51:e5:a8"...
Now that we are connected to the TGNMS E2E controller API, it is possible to use any call listed in the API docs. Those can be found at your-nms-ip/docs/apidoc/. Next in this notebook we will add a network via the bulkAdd
topology API. First we need to prepare the data using the helper functions below so that it will be accepted by the API.
[3]:
def make_site(name):
base_latitude = 37.484596
base_longitude = -122.148646
37.484430, -122.147415
return {
"name": name,
"location": {
"latitude": base_latitude + random.random() / 1000,
"longitude": base_longitude + random.random() / 1000,
"altitude": 30,
"accuracy": 40000000
}
}
def make_node(name, mac, site, is_pop):
return {
"name": name,
"node_type": 2,
"is_primary": True,
"mac_addr": mac,
"wlan_mac_addrs": [],
"pop_node" : is_pop,
"status": 1,
"site_name": site["name"],
"ant_azimuth": 100.0,
"ant_elevation": 999.99
}
def make_link(info):
aName, aMac = info[0]
zName, zMac = info[1]
return {
"name": f"link-{aName}-{zName}",
"a_node_name": aName,
"a_node_mac": aMac,
"z_node_name": zName,
"z_node_mac": zMac,
"is_alive": False,
"linkup_attempts": 0,
"link_type": 1 # wireless link
}
node_info = [
("pop-if6", "34:ef:b6:51:e5:a8"),
("if5", "34:ef:b6:51:e3:ec"),
("if4", "34:ef:b6:51:e4:1c"),
("if3", "34:ef:b6:51:e3:da"),
("if2", "34:ef:b6:51:e3:e0"),
("if1", "34:ef:b6:51:e3:3e"),
]
sites = []
nodes = []
links = []
for node_name, mac in node_info:
site = make_site(f"site-{node_name}")
sites.append(site)
nodes.append(make_node(node_name, mac, site, "pop" in node_name))
link_info = [
(("if1", "04:ce:14:fe:a5:d9"), ("pop-if6", "04:ce:14:fe:a5:a4")),
(("if2", "04:ce:14:fe:a6:03"), ("if3", "04:ce:14:fe:a5:3f")),
(("if2", "04:ce:14:fe:a5:e9"), ("if1", "04:ce:14:fe:a5:dc")),
(("if3", "04:ce:14:fe:a5:40"), ("pop-if6", "04:ce:14:fe:a5:86")),
]
for info in link_info:
links.append(make_link(info))
Now that we have a list of the nodes, sites, and links we want to add we can send them off to the api/bulkAdd
endpoint.
[4]:
data = {
"sites": sites,
"nodes": nodes,
"links": links,
}
response = requests.post(api_url + "api/bulkAdd", json=data, headers=auth_header)
print(response)
<Response [200]>