Getting Started
Python SDK for Graphiant NaaS.
Docs: https://github.com/Graphiant-Inc/graphiant-sdk-python/tree/main/docs
Source code: https://github.com/Graphiant-Inc/graphiant-sdk-python
Package: https://pypi.org/project/graphiant-sdk/
Topology
Installing Graphiant SDK Python Package
To Install Graphiant SDK Python package, Please refer to https://github.com/Graphiant-Inc/graphiant-sdk-python/blob/main/README.md
Creating Graphiant Portal Client
Import graphiant_sdk python package and define GraphiantPortalClient object.
import graphiant_sdk
from graphiant_sdk.exceptions import (ApiException, BadRequestException,
UnauthorizedException, ForbiddenException,
NotFoundException, ServiceException)
import time
from libs.logger import setup_logger
LOG = setup_logger()
class GraphiantPortalClient():
def __init__(self, base_url=None, username=None, password=None):
self.config = graphiant_sdk.Configuration(host=base_url,
username=username, password=password)
self.api_client = graphiant_sdk.ApiClient(self.config)
self.api = graphiant_sdk.DefaultApi(self.api_client)
self.bearer_token = None
def set_bearer_token(self):
v1_auth_login_post_request = graphiant_sdk.V1AuthLoginPostRequest(username=self.config.username,
password=self.config.password)
v1_auth_login_post_response = None
try:
v1_auth_login_post_response = self.api.v1_auth_login_post(
v1_auth_login_post_request=v1_auth_login_post_request)
except BadRequestException as e:
LOG.error(f"v1_auth_login_post: Got BadRequestException. Please verify payload is correct. {e}")
except (UnauthorizedException, ServiceException) as e:
LOG.error(f"v1_auth_login_post: Got Exception. Please verify crendentials are correct. {e}")
LOG.debug(f"GraphiantPortalClient Bearer token : {v1_auth_login_post_response.token}")
self.bearer_token = f'Bearer {v1_auth_login_post_response.token}'
Instantiate GraphiantPortalClient object
self.gsdk = GraphiantPortalClient(base_url=base_url, username=username, password=password)
self.gsdk.set_bearer_token()
Using Graphiant Portal Client
Once Graphiant portal client object is instated and bearer token is retrieved, user can perform CRUD operations using Graphiant APIs.
Refer API Documentation here: https://github.com/Graphiant-Inc/graphiant-sdk-python/blob/main/docs/DefaultApi.md
Getting Device Summary
E.g. Request to retrieve edges summary
edges_summary_response = self.api.v1_edges_summary_get(authorization=self.bearer_token)
v1_edges_summary_get returns object of type V1EdgesSummaryGet200Response
https://github.com/Graphiant-Inc/graphiant-sdk-python/blob/main/docs/V1EdgesSummaryGet200Response.md
device_name = 'edge-1-sdktest'
edge_summary = None
edges_summary_response = self.api.v1_edges_summary_get(authorization=self.bearer_token)
for device_summary in edges_summary_response.edges_summary:
if device_summary.hostname == device_name:
edge_summary = device_summary
break
if edge_summary:
LOG.info(f'{device_name} edge summary is {edge_summary.to_str()}')
2025-06-18 11:32:43,374 - Graphiant_playbook - INFO - edge-1-sdktest edge summary is {'assignedOn': None,
'deviceId': 30000051803,
'discoveredLocation': 'Tower Hamlets, Greater London, United Kingdom',
'enterpriseId': 10000000288,
'enterpriseName': None,
'firstAppearedOn': {'nanos': 314421000, 'seconds': 1750202765},
'hostname': 'edge-1-sdktest',
'ipDetected': '62.89.143.70',
'isHardware': None,
'isNew': True,
'isRequested': None,
'lastBootedAt': {'nanos': 537864000, 'seconds': 1750202669},
'location': {'addressLine1': '',
'addressLine2': '',
'city': 'tower hamlets',
'country': 'united kingdom',
'countryCode': '',
'latitude': None,
'longitude': None,
'notes': None,
'provinceCode': '',
'state': 'greater london',
'stateCode': ''},
'model': 'QEMU-Q35',
'overrideRegion': 'us-west-2 (San Jose)',
'parentEnterpriseName': None,
'portalStatus': 'Ready',
'region': 'eu-west-1 (London)',
'role': 'cpe',
'serialNum': '5020cf30-fcee-4f02-93af-8a5ba61f1f0b',
'site': 'San Jose-sdktest',
'siteId': 4716,
'stale': None,
'status': 'active',
'swName': '25.6.1',
'swVersion': '2506.202506021956',
'ttConnCount': 2,
'upgradeSummary': None}
Updating Device configuration
Prerequisite before configuration push to device
Before updating a device (edge/gateway/core) configuration, it is required to make sure that the device’s Portal Sync status is in InSync state (a.k.a Ready state). It is also required to make sure that device has connectivity to the Graphiant portal via Graphiant tunnel terminators. These two pieces of information can be found from v1/edges/summary API
def get_edges_summary(self, device_id=None):
"""
Get all edges summary from GCS.
Args:
device_id (int, optional): The device ID to filter edges.
If not provided, returns all edges.
Returns:
edges_summary: Optional[List[V1EdgesHardwareAssignedGet200ResponseEdgesSummaryInner]]:
A list of all edges summary info if no device_id is provided,
(or)
edge_info: V1EdgesHardwareAssignedGet200ResponseEdgesSummaryInner
A single edge's summary information if a device_id is provided.
"""
response = self.api.v1_edges_summary_get(authorization=self.bearer_token)
if device_id:
for edge_info in response.edges_summary:
if edge_info.device_id == device_id:
return edge_info
return response.edges_summary
def verify_device_portal_status(self, device_id: int):
"""
Verifies device portal sync Ready status (InSync) and
also verifies device connections to tunnel terminators status.
"""
edge_summary = self.get_edges_summary(device_id=device_id)
if edge_summary.portal_status == "Ready":
if edge_summary.tt_conn_count and edge_summary.tt_conn_count == 2:
return
else:
LOG.info(f"verify_device_portal_status: {device_id} tunnel terminitor conn count: "
f"{edge_summary.tt_conn_count} Expected: tt_conn_count=2. Retrying..")
assert False, (f"verify_device_portal_status: {device_id} tunnel terminitor conn count: "
f"{edge_summary.tt_conn_count} Expected: tt_conn_count=2. Retry")
else:
LOG.info(f"verify_device_portal_status: {device_id} Portal Status: "
f"{edge_summary.portal_status} Expected: Ready. Retrying..")
assert False, (f"verify_device_portal_status: {device_id} Portal Status: "
f"{edge_summary.portal_status} Expected: Ready. Retrying..")
Configuring interface and subinterfaces of an edge device
Device configuration push is achieved using API PUT v1/devices/<deviceid>/config. The corresponding method in the Graphiant python sdk is v1_devices_device_id_config_put which has parameter v1_devices_device_id_config_put_request: V1DevicesDeviceIdConfigPutRequest to pass the config request payload to configure edge/gateway V1DevicesDeviceIdConfigPutRequestEdge or core V1DevicesDeviceIdConfigPutRequestCore devices.
Refer V1DevicesDeviceIdConfigPutRequestEdge and V1DevicesDeviceIdConfigPutRequest model documentation
E.g Request to configure edge’s circuit, interface and add a subinterface
Create payload object V1DevicesDeviceIdConfigPutRequest for config push.
# V1DevicesDeviceIdConfigPutRequestEdgeCircuitsValue can be in dict instead of creating object explicitly.
circuits = {
"c-gigabitethernet5-0-0": {
"name": "c-gigabitethernet5-0-0",
"description": "c-gigabitethernet5-0-0",
"linkUpSpeedMbps": 50,
"linkDownSpeedMbps": 100,
"connectionType": "internet_dia",
"label": "internet_dia_4",
"qosProfile": "gold25",
"qosProfileType": "balanced",
"diaEnabled": false,
"lastResort": false,
"patAddresses": {},
"staticRoutes": {}
}
}
# V1DevicesDeviceIdConfigPutRequestEdgeInterfacesValue can be in dict instead of creating object explicitly. Object will be created when assigned.
interfaces = {"GigabitEthernet5/0/0": {"interface": {"adminStatus": true, "maxTransmissionUnit": 1500, "circuit": "c-gigabitethernet5-0-0", "description": "wan_1", "alias": "primary_wan", "ipv4": {"dhcp": {"dhcpClient": true}}, "ipv6": {"dhcp": {"dhcpClient": true}}}}, "GigabitEthernet8/0/0": {"interface": {"subinterfaces": {"18": {"interface": {"lan": "lan-7-test", "vlan": 18, "description": "lan-7", "alias": "non_production", "adminStatus": true, "ipv4": {"address": {"address": "10.2.7.1/24"}}, "ipv6": {"address": {"address": "2001:10:2:7::1/64"}}}}}}}}
# Edge configuration payload V1DevicesDeviceIdConfigPutRequestEdge
device_config_put_request_edge = V1DevicesDeviceIdConfigPutRequestEdge(circuits=circuits,
interfaces=interfaces)
# Payload V1DevicesDeviceIdConfigPutRequest for v1_devices_device_id_config_put method.
device_config_put_request = V1DevicesDeviceIdConfigPutRequest(edge=device_config_put_request_edge)
Push the configuration to the device after verifying device portal sync status and device-portal connections
try:
# Verify device portal status and connection status.
self.verify_device_portal_status(device_id=device_id)
# Push the configuration (V1DevicesDeviceIdConfigPutRequest)
LOG.info(f"put_device_config : config to be pushed for {device_id}: \n{device_config_put_request}")
response = self.api.v1_devices_device_id_config_put(
authorization=self.bearer_token, device_id=device_id,
v1_devices_device_id_config_put_request=device_config_put_request)
return response
except ForbiddenException as e:
LOG.error(f"put_device_config : Got ForbiddenException while config push to {device_id}. "
f"User {self.config.username} does not have permissions to perform the requested operation "
f"(v1_devices_device_id_config_put).")
except ApiException as e:
LOG.warning(f"put_device_config : Exception while config push {e}")
Value of device_config_put_request: V1DevicesDeviceIdConfigPutRequest in the log file. NOTE: Dict value is automatically translated to corresponding objects. Optionally you create objects and build the payload.
2025-06-17 17:00:29,868 - Graphiant_playbook - INFO - put_device_config : config to be pushed for 30000051803:
configuration_metadata=None core=None description=None edge=V1DevicesDeviceIdConfigPutRequestEdge(bgp_enabled=None, bgp_instance=None, circuits={'c-gigabitethernet5-0-0': V1DevicesDeviceIdConfigPutRequestEdgeCircuitsValue(bgp_aggregations=None, bgp_multipath=None, bgp_neighbors=None, bgp_redistribution=None, carrier=None, circuit_type=None, connection_type='internet_dia', description='c-gigabitethernet5-0-0', dia_enabled=False, drop_mechanism=None, label='internet_dia_4', last_resort=False, link_down_speed_mbps=100, link_up_speed_mbps=50, loopback=None, name='c-gigabitethernet5-0-0', pat_addresses=V1DevicesDeviceIdConfigPutRequestEdgeCircuitsValuePatAddresses(addresses=None), qos_profile='gold25', qos_profile_type='balanced', static_routes={})}, dhcp_server_enabled=None, dns=None, interfaces={'GigabitEthernet5/0/0': V1DevicesDeviceIdConfigPutRequestEdgeInterfacesValue(interface=V1DevicesDeviceIdConfigPutRequestEdgeInterfacesValueInterface(admin_status=True, alias='primary_wan', circuit='c-gigabitethernet5-0-0', description='wan_1', ipsec=None, ipv4=V1DevicesDeviceIdConfigPutRequestCoreInterfacesValueInterfaceGwGw(address=None, dhcp=V1DevicesDeviceIdConfigPutRequestCoreInterfacesValueInterfaceGwGwDhcp(dhcp_client=True, dhcp_relay=None), vrrp=None), ipv6=V1DevicesDeviceIdConfigPutRequestCoreInterfacesValueInterfaceGwGw(address=None, dhcp=V1DevicesDeviceIdConfigPutRequestCoreInterfacesValueInterfaceGwGwDhcp(dhcp_client=True, dhcp_relay=None), vrrp=None), lan=None, lldp_enabled=None, loopback=None, max_transmission_unit=1500, security_zone=None, subinterfaces=None, tcp_mss=None, tcp_mss_v4=None, tcp_mss_v6=None, v4_tcp_mss=None, v6_tcp_mss=None)), 'GigabitEthernet8/0/0': V1DevicesDeviceIdConfigPutRequestEdgeInterfacesValue(interface=V1DevicesDeviceIdConfigPutRequestEdgeInterfacesValueInterface(admin_status=None, alias=None, circuit=None, description=None, ipsec=None, ipv4=None, ipv6=None, lan=None, lldp_enabled=None, loopback=None, max_transmission_unit=None, security_zone=None, subinterfaces={'18': V1DevicesDeviceIdConfigPutRequestEdgeInterfacesValueInterfaceSubinterfacesValue(interface=V1DevicesDeviceIdConfigPutRequestEdgeInterfacesValueInterfaceSubinterfacesValueInterface(admin_status=True, alias='non_production', circuit=None, description='lan-7', ipv4=V1DevicesDeviceIdConfigPutRequestCoreInterfacesValueInterfaceGwGw(address=V1GlobalConfigPatchRequestSnmpsValueConfigEngineEndpointsValueEngineEndpointAddressesValue(address='10.2.7.1/24'), dhcp=None, vrrp=None), ipv6=V1DevicesDeviceIdConfigPutRequestCoreInterfacesValueInterfaceGwGw(address=V1GlobalConfigPatchRequestSnmpsValueConfigEngineEndpointsValueEngineEndpointAddressesValue(address='2001:10:2:7::1/64'), dhcp=None, vrrp=None), lan='lan-7-test', lldp_enabled=None, max_transmission_unit=None, security_zone=None, tcp_mss=None, tcp_mss_v4=None, tcp_mss_v6=None, v4_tcp_mss=None, v6_tcp_mss=None, vlan=18, vrrp=None))}, tcp_mss=None, tcp_mss_v4=None, tcp_mss_v6=None, v4_tcp_mss=None, v6_tcp_mss=None))}, ipfix_enabled=None, ipfix_exporters=None, lldp_enabled=None, local_route_tag=None, local_web_server_password=None, location=None, maintenance_mode=None, name=None, nat_policy=None, ospfv2_enabled=None, ospfv3_enabled=None, prefix_sets=None, region=None, region_name=None, route_policies=None, segments=None, site=None, site_to_site_vpn=None, snmp=None, snmp_global_object=None, static_routes_enabled=None, traffic_policy=None, vrrp_enabled=None) local_web_server_password=None replace=None
The response (V1DevicesDeviceIdConfigPut202Response) of the request (V1DevicesDeviceIdConfigPutRequest) will contain job_id which can be used to monitor the success and progress of the device update configuration.