Jump to content
Welcome to our new Citrix community!
  • StyleBook automation using Citrix ADM's NITRO API: A DevOps primer

    Steven Wright
    • Validation Status: Validated
      Summary: StyleBook automation using Citrix ADM's NITRO API: A DevOps primer
      Has Video?: No

    StyleBook automation using Citrix ADM's NITRO API: A DevOps primer


    Citrix Application Delivery Management (ADM) is a centralized management solution that enables you to operate, upgrade, report on, and troubleshoot all your NetScaler's across a global estate.

    One of Citrix ADM's best features is StyleBooks - declarative descriptions of a desired state written in YAML and consisting of input parameters and components driven by those inputs. A StyleBook causes Citrix ADM to read your current NetScaler configuration, compute the differences between your current and target state, and implement the required settings.

    While you can write StyleBooks yourself, Citrix ADM comes with more than 35 default StyleBooks, covering everything from building a simple HTTP load balancer to all of the content switching, load balancing, and authentication settings needed to support Exchange 2016. Learn about using default StyleBooks and creating custom StyleBooks.

    In this blog post, I focus on simple HTTP load balancers but provide enough detail so you can apply the logic to any StyleBook. Specifically, I'm going to focus on a StyleBook called "lb" with the namespace "com.citrix.adc.stylebooks"which you can find by selecting Applications, Configuration, StyleBooks within Citrix ADM.




    This post is the first in a two-part series that describes how to rapidly create services on your NetScaler's using Citrix ADM StyleBook automation, accelerating your migrations. We'll create 300 load balancers across an estate of several NetScaler's within 15 minutes. This post is aimed at DevOps employees who want to start working with Citrix ADM and need a brief introduction with examples (which you can download here).

    In my second post, I target sysadmins and focus on using preprepared scripts to achieve our goal of creating the 300 load balancers.


    Citrix ADM and the NITRO API

    The second best thing about Citrix ADM is that you can access it using API calls, which is how we'e going to automate our StyleBook. You can see more on that below but, you can also find more information here:

    To call your script to log in using the NITRO API, you need an ID and secret. You can create the ID and secret for Citrix ADM service by doing the following steps:

    1. Sign in to the Citrix Cloud portal.
    2. Select Identity and Access Management from the menu.
    3. Select the API Access tab.
    4. Name your Secure Client, and click Create Client.


    NITRO API request for a session ID

    After you have the ID and secret, you can sign in and collect a session ID using the following Python commands (this isn't my real ID and secret):


    import http.clientimport jsonid = "f20e7432-7a83-416d-a171-9347b92761f4"secret = "7-rotB6QMFZTuOgpPajPBg=="conn = http.client.HTTPSConnection("adm.cloud.com")                 headers = {        'isCloud': 'true',        'Content-Type': 'text/plain',        'Cookie': ''  }request = {       "login": {              "ID": id,              "Secret": secret       }}payload = json.dumps(request)conn.request("POST", "/nitro/v2/config/login", payload, headers)response = conn.getresponse()data = response.read()if response.status != 200:  print("Error:")  print("       Status code: " + str(res.status))  print("       Error payload: " + data)  exit(1)jsondata = json.loads(data)sessionid = jsondata["login"][0]['sessionid']print (sessionid)Outputia6bMEB9xn_XUW0Rfy_86zNbKlG1rJgZrd-DM3u3MIM

    NITRO API request using the session ID to retrieve a list of NetScaler identifiers

    Now that you have a session ID token, you can request a list of NetScaler's and find the unique identifier of the instance on which you would like to operate. The session ID is taken from the preceding script.


    import http.clientimport jsonsessionid = "ia6bMEB9xn_XUW0Rfy_86zNbKlG1rJgZrd-DM3u3MIM"conn = http.client.HTTPSConnection("adm.cloud.com")headers = {        'isCloud': 'true',        'Content-Type': 'text/plain',        'Cookie': 'NITRO_AUTH_TOKEN=' + sessionid    }conn.request("GET", "/nitro/v2/config/managed_device", None, headers)response = conn.getresponse()data = response.read()if res.status != 200:  print("Error:")  print("       Status code: " + str(res.status))  print("       Error payload: " + data)  exit(1)jsondata = json.loads(data)#print('\n\nHere is the full JSON output from ADM.\n')#print (jsondata["managed_device"])print('\n\nHere is a list of ADCs.\n')for device in jsondata["managed_device"]:        name = device['hostname']        ip = device['ip_address']        id = device['id']        type = device['type']        version = device['version']        status = device['status']        if status == "Success":                print (name + " " + ip + " " + id + " " + type)OutputHere is a list of ADCs.myhostname a1fe50be-e187-44bb-871b-d60f112b0aff nsvpx 

    Knowing the parameters to submit to a StyleBook

    Now that we have a session ID and the identifier of an NetScaler to target, we can run a StyleBook. First, however, we need to understand the various parameters that it expects us to submit before doing so.

    You can gather the parameters by programmatically requesting the StyleBook's schema, which describes all valid parameters and which are optional, or by reviewing the source YAML for the StyleBook and its dependencies.

    Here are the Python commands to request a StyleBook's schema.


    import http.clientimport jsonsessionid = "ia6bMEB9xn_XUW0Rfy_86zNbKlG1rJgZrd-DM3u3MIM"base_types = ["string", "ipaddress", "number", "boolean", "tcp-port", "password", "file", "certfile", "keyfile", "certkey", "ipnetwork"]def get_config_parameters(parameters):  configpack_params = {}  for parameter in parameters:    parameter_name = parameter["name"]    parameter_type = parameter["type"]    parameter_required = parameter["required"]    if parameter_type in base_types:        if parameter_required:          parameter_type += "*"        if parameter_type.endswith("[]"):          configpack_params[parameter_name] = [parameter_type]        else:          configpack_params[parameter_name] = parameter_type    else:        if "parameters" in parameter:          subparameters = parameter["parameters"]          datatype = get_config_parameters(subparameters)        else:          datatype = parameter_type        if parameter_type.endswith("[]"):          configpack_params[parameter_name] = [datatype]        else:          configpack_params[parameter_name] = datatype  return configpack_paramsconn = http.client.HTTPSConnection("adm.cloud.com")stylebook = "com.citrix.adc.stylebooks/1.1/lb"headers = {  'Cookie': 'NITRO_AUTH_TOKEN= ' + sessionid}conn.request("GET", "/stylebook/nitro/v1/config/stylebooks/" + stylebook + "/schema", None, headers)res = conn.getresponse()data = res.read()if res.status != 200:  print("Error:")  print("       Status code: " + str(res.status))  print("       Error payload: " + data)  exit(1)schema = json.loads(data, "utf-8")parameters = schema["schema"]["parameters"]config_parameters = {  "parameters": get_config_parameters(parameters)}print(json.dumps(config_parameters))

    The output from this schema request is the format of the parameters section of a config pack. From this output, you can remove parameters you don't intend to use. As a clue, the required parameters are marked with a "*" at the end of their type.

    Another (and possibly easier) way to achieve the same thing is to use the Citrix ADM UI to create a template that shows only the parameters I want to use.

    To create the template, I open Citrix ADM's web interface and run my selected StyleBook with dummy values against a non-production NetScaler in a lab. In doing so, I create a config pack with each of the values I would need for a production service.





    Having created the config pack, I now select Applications > Configuration > Config Packs from within the Citrix ADM web interface and export the resultant configuration.





    After downloading and opening the exported ZIP file, I find that it contains a single JSON file with all the parameters that I need to submit to the API.




    NITRO API request using the session ID to automate a StyleBook and target an NetScaler identifier

    Finally, having retrieved a session ID, the unique identifier of the NetScaler to operate on, and clarity into the parameters needed to submit to the StyleBook, we are ready to script execution of the StyleBook itself.

    Note: Delete the template configuration pack from Citrix ADM if you want to use the same input parameters within your Python script.


    import http.clientimport jsonsessionid = "ia6bMEB9xn_XUW0Rfy_86zNbKlG1rJgZrd-DM3u3MIM"target_adc = "a1fe50be-e187-44bb-871b-d60f112b0aff"stylebook = "com.citrix.adc.stylebooks/1.1/lb"conn = http.client.HTTPSConnection("adm.cloud.com")payload = json.dumps({  "configpack": {    "targets": [      {        "id": target_adc      }    ],    "parameters": {      "lb-appname": "ApplicationName",      "lb-virtual-ip": "",      "lb-virtual-port": "80",      "lb-service-type": "HTTP",      "svc-service-type": "HTTP",      "svc-servers": [        {          "ip": "",          "port": 80,          "add-server": True        },        {          "ip": "",          "port": 80,          "add-server": True        }      ],    }  }})headers = {  'Content-Type': 'application/json',  'Accept': 'application/json',  'Cookie': 'NITRO_AUTH_TOKEN=' + sessionid}conn.request("POST", "/stylebook/nitro/v1/config/stylebooks/" + stylebook + "/configpacks", payload, headers)res = conn.getresponse()data = res.read()if res.status != 200:  print("Error:")  print("       Status code: " + str(res.status))  print("       Error payload: " + data)  exit(1)payload = json.loads(data, "utf-8")jobid = payload["configpack"]["job_id"]print("Configuration Job " + jobid + " has started.")OutputConfiguration Job 204770189 has started.

    Viewing a job_id

    At this point you are able to see the config pack that your script created within the ADM GUI and the resultant configuration on your NetScaler.


    If that didn't happen, you can view the details of the "job_id" and understand its status. We can retrieve the outcome of the job by sending a GET request.

    To illustrate, I purposely ran another StyleBook targeted at a non-existent NetScaler ID.


    import http.clientimport jsonsessionid = "ia6bMEB9xn_XUW0Rfy_86zNbKlG1rJgZrd-DM3u3MIM"jobid = "2476087615"headers = {  'Content-Type': 'application/json',  'Accept': 'application/json',  'Cookie': 'NITRO_AUTH_TOKEN=' + sessionid}conn = http.client.HTTPSConnection("adm.cloud.com")job_status = Nonewhile job_status != "completed" and job_status != "failed":  conn.request("GET", "/stylebook/nitro/v1/config/jobs/" + jobid, None, headers)  response = conn.getresponse()  data = response.read()  if response.status != 202:    print("Error:")    print("       Status code: " + str(response.status))    print("       Error payload: " + data)    exit(1)  payload = json.loads(data, "utf-8")  job_status = payload["job"]["status"]config_id = payload["job"]["progress_info"][0]["id"]if job_status == "completed":  print("Success: configuration " + config_id + " successully created")else:  print("Error: Failed to create configuration.")  progress_info = payload["job"]["progress_info"]  for step in progress_info:      error_details = step["message"]      print("        " + json.dumps(error_details))  exit(1)Output (failure)Error: Failed to create configuration."Validating the parameters""Configuration pack process failed. Instance with id g4702445-2286-4b6d-8fb1-c231a0ee17b1 not found on the system."

    Here, we can observe a clear explanation of the issue. We can observe success messages on jobs that run without issue.

    Output (success)Success: configuration 204770189 successfully created

    Next steps

    We have now seen how we can programmatically authenticate to Citrix ADM, retrieve a list of identifiers for the NetScaler's that it manages, prepare and run StyleBooks against a chosen NetScaler, and retrieve the result.


    We have also observed how you can find the namespace, version, and name of alternative StyleBooks and retrieve the various properties they require.


    Using this knowledge, your DevOps team is able to integrate Citrix ADM StyleBooks and their automated NetScaler configuration into your existing workflows.


    In the second of this two-part series, using the example of creating 300 load balancers across an estate of several NetScaler's within 15 minutes, I share prebuilt scripts that allow those without a DevOps team to create business services rapidly during a platform migration.


    User Feedback

    Recommended Comments

    There are no comments to display.

    Create an account or sign in to comment

    You need to be a member in order to leave a comment

    Create an account

    Sign up for a new account in our community. It's easy!

    Register a new account

    Sign in

    Already have an account? Sign in here.

    Sign In Now

  • Create New...