Intro
The Cisco Panoptica REST API has endpoints to perform all activities that can be performed on the console UI, including endpoints to create environments and clusters, create policies, add images and registries.
The REST API uses Escher authentication—described below—which uses a Python library provided by Cisco.
Prerequisites
- Python, version 3
- Python libraries (pip) - decorator (4.3.0), requests (2.18.4), warrant (0.6.1)
- Cisco Panoptica authentication library, _escherauth.py _from here
- A Panoptica account. See Getting Started
Base URL
The base URL for the REST API is - appsecurity.cisco.com/api
You need to be logged into the Panoptica server to access the APIs.
API Reference
Click _API _on the Panoptica home page to open the API reference, in Swagger. This shows details of each endpoint and method.
Authentication
The REST API uses Escher authentication. This method uses a unique token for each request. The token is a hash generated from fixed Access and Secret keys (obtained from Panoptica), the request URL, and the request time.
Access & Secret keys
Generate unique Access and Secret keys from the Panoptica console. These will be used for each request.
- Navigate to the System _page, and select _MANAGE USERS.
- Click New User _and select _Service User.
- Enter a name for the user. Leave the status as 'Active'.
- Click FINISH to receive the Token window.
- Copy the values of Access Key and Secret Key, for use in the Escher authentication.
Escher Authentication
To generate the Escher authentication, download the Panoptica authentication module: escherauth.py
It uses these parameters:
- the Access & Secret Keys, copied from the token generated when creating the Service User (above)
- the request URL - see sample below for format
- the current date & time - see sample below for format
response = requests.get(full_url,
headers={'X-Escher-Date': date_string,
'host': 'securecn.cisco.com',
'content-type': 'application/json'},
auth=EscherRequestsAuth("global/services/portshift_request",
{'current_time': date},
{'api_key': access_key, 'api_secret': secret_key}))
date_format = '%Y%m%dT%H%M%SZ'
date_string = datetime.datetime.utcnow().strftime(date_format)
date = datetime.datetime.strptime(date_string, date_format)
Use example (Python)
The example below generates a request for the _Get Image Layers _endpoint.
# coding=utf-8
import datetime
import json
import decorator
import os
import sys
import traceback
import requests
from escherauth import EscherRequestsAuth
def main():
access_key = "the 'access key' from a 'SERVICE USER' in https://securecn.cisco.com/system/manageUsers"
secret_key = "the 'secret key' from a 'SERVICE USER' in https://securecn.cisco.com/system/manageUsers"
image_id = "some id" # you need to take the id of the image
response = get_image_layers(
access_key,
secret_key,
"https://securecn.cisco.com",
image_id)
print(response)
@verify
def get_image_layers(access_key, secret_key, url, image_id):
full_url = url + '/api/api/images/' + image_id + '/imageLayers'
print("full_url = " + full_url)
if not access_key:
access_key = os.environ['PORTSHIFT_ACCESS_KEY']
if not secret_key:
secret_key = os.environ['PORTSHIFT_SECRET_KEY']
date_format = '%Y%m%dT%H%M%SZ'
date_string = datetime.datetime.utcnow().strftime(date_format)
date = datetime.datetime.strptime(date_string, date_format)
response = requests.get(full_url,
headers={'X-Escher-Date': date_string,
'host': 'securecn.cisco.com',
'content-type': 'application/json'},
auth=EscherRequestsAuth("global/services/portshift_request",
{'current_time': date},
{'api_key': access_key, 'api_secret': secret_key}))
print("response.status_code = " + str(response.status_code))
if response.status_code not in [200]:
raise Exception("Failed to get image layers for image " + image_id + "." + str(response))
return response
@verify
def add_kubernetes_cluster(name, access_key, secret_key, url, cluster_pod_definition_source='KUBERNETES',
ci_validation='false', should_auth_fail=False):
full_url = url + '/api/api/kubernetesClusters'
print("full_url = " + full_url)
print("should_auth_fail = " + str(should_auth_fail))
if not access_key:
access_key = os.environ['PORTSHIFT_ACCESS_KEY']
if not secret_key:
secret_key = os.environ['PORTSHIFT_SECRET_KEY']
date_format = '%Y%m%dT%H%M%SZ'
date_string = datetime.datetime.utcnow().strftime(date_format)
date = datetime.datetime.strptime(date_string, date_format)
cluster_dict = create_kubernetes_cluster_dict(name, cluster_pod_definition_source, ci_validation)
cluster_json = json.dumps(cluster_dict)
response = requests.post(full_url,
data=cluster_json,
headers={'X-Escher-Date': date_string,
'host': 'securecn.cisco.com',
'content-type': 'application/json'},
auth=EscherRequestsAuth("global/services/portshift_request",
{'current_time': date},
{'api_key': access_key, 'api_secret': secret_key}))
print("response.status_code = " + str(response.status_code))
if response.status_code not in [201, 409]:
raise Exception("Failed to create cluster. " + str(response))
return response
@decorator.decorator
def verify(func, *args, **kwargs):
res = func(*args, **kwargs)
if res.ok is False:
try:
raise Exception(res.json())
except ValueError:
raise Exception("Error code was {} but there was no bodjson. Text was '{}'".format(res.status_code, res.text))
if res.status_code != 204:
try:
return res.json()
except ValueError:
raise Exception("Status code was {} but there was no json. Text was '{}'".format(
res.status_code, res.text))
return 'OK'
def create_kubernetes_cluster_dict(name, clusterPodDefinitionSource, ci_validation):
cluster_dict = \
{
"name": name,
"clusterPodDefinitionSource": clusterPodDefinitionSource,
"ciImageValidation": ci_validation,
"enableConnectionsControl": True
}
return cluster_dict
if __name__ == "__main__":
try:
main()
except Exception as exc:
traceback.print_exc()
sys.exit(1)