F5 REST API – Getting started

Introduction

This guide will focus mostly on practical examples. It’s not meant to make you an expert or delve deep into the world of iControl REST, there are already very good guides for that over at Devcentral.

Let’s begin with some pre-requisites:

  1. Your device should ideally be running 11.6.0 or later. iControl REST is available in 11.5.*, but not recommended since it was still under heavy development back then.
  2. If you want to simplify things you should use an admin account to authenticate with.

Reading data

List configured nodes

Let’s start off with an example by listing the configured nodes in a system. Then doing this with tmsh the command is “list ltm nodes“. When doing this with iControl REST it is something similar:

curl -s -k -u "admin:admin" https://192.168.10.23/mgmt/tm/ltm/node | json_pp
{
   "kind" : "tm:ltm:node:nodecollectionstate",
   "items" : [
      {
         "state" : "unchecked",
         "ratio" : 1,
         "dynamicRatio" : 1,
         "kind" : "tm:ltm:node:nodestate",
         "fullPath" : "/Common/BIGIP-01-Member-01",
         "address" : "10.2.2.11",
         "selfLink" : "https://localhost/mgmt/tm/ltm/node/~Common~BIGIP-01-Member-01?ver=12.1.2",
         "partition" : "Common",
         "ephemeral" : "false",
         "generation" : 1,
         "session" : "user-enabled",
         "logging" : "disabled",
         "connectionLimit" : 0,
         "rateLimit" : "disabled",
         "name" : "BIGIP-01-Member-01",
         "monitor" : "default",
         "fqdn" : {
            "addressFamily" : "ipv4",
            "autopopulate" : "disabled",
            "interval" : "3600",
            "downInterval" : 5
         }
      }
   ]
}

Dissecting the command:

As you can see the the command sort of reflects the tmsh command by using “/ltm/node” as opposed to “list ltm node“.

Note how this only shows the node configuration, not the status of the nodes. To get an output similar to “show ltm node” you need to add a “/stats” to the end of the URI. This works for most commands. Easy huh?

Example:

curl -s -k -u "admin:admin" https://192.168.10.23/mgmt/tm/ltm/node/stats | json_pp

More examples

Description tmsh command Equivalent iControl REST endpoint Example command
List node configuration list ltm node  /mgmt/tm/ltm/node curl -s -k -u “admin:admin” https://192.168.10.23/mgmt/tm/ltm/node | json_pp
Show node statuses show ltm node  /mgmt/tm/ltm/node/stats curl -s -k -u “admin:admin” https://192.168.10.23/mgmt/tm/ltm/node/stats | json_pp
List pool configuration list ltm pool /mgmt/tm/ltm/pool curl -s -k -u “admin:admin” https://192.168.10.23/mgmt/tm/ltm/pool | json_pp
Show pool statuses show ltm pool /mgmt/tm/ltm/pool/stats curl -s -k -u “admin:admin” https://192.168.10.23/mgmt/tm/ltm/pool/stats | json_pp
List virtual server configuration list ltm virtual /mgmt/tm/ltm/virtual curl -s -k -u “admin:admin” https://192.168.10.23/mgmt/tm/ltm/virtual| json_pp
Show virtual server statuses show ltm virtual /mgmt/tm/ltm/virtual/stats curl -s -k -u “admin:admin” https://192.168.10.23/mgmt/tm/ltm/virtual/stats | json_pp
List client ssl profiles list ltm profile client-ssl /mgmt/tm/ltm/profile/client-ssl curl -s -k -u “admin:admin” https://192.168.10.23/mgmt/tm/ltm/profile/client-ssl/ | json_pp
Show client ssl profile statistics show ltm profile client-ssl /mgmt/tm/ltm/profile/client-ssl/stats curl -s -k -u “admin:admin” https://192.168.10.23/mgmt/tm/ltm/profile/client-ssl/stats | json_pp

Creating objects

Creating objects is a bit more trickier, but not that hard once you get the hang of it.

Creating a node using tmsh

In this example we’re going to create a node. In tmsh one creates a node with the following syntax:

create ltm node myNode address 10.1.1.1

As you can see the command has the following parameters:

  • Name: myNode
  • Address: 10.1.1.1

Creating a node using iControl REST

Now, the REST API speaks JSON, not tmsh so we can’t copy straight off. First we need to translate it. Lucky for us it’s really simple! Here’s a JSON string that matches the parameters in the example above:

{"name":"myNode","address":"10.1.1.1"}

Now, to use it we need to add a little bit to our curl command which will look like this:

curl -s -k -u "admin:admin" https://192.168.10.23/mgmt/tm/ltm/node -H 'Content-Type: application/json' -X POST -d '{"name":"myNode","address":"10.1.1.1"}' | json_pp
  • -X POST – Tell curl that it will be sending data to the device by using “”
  • -H ‘Content-Type: application/json’ – Let the receiving device know that it will be getting content in the form of JSON.
  • -d ‘{“name”:”myNode”,”address”:”10.1.1.1″}’ – The actual JSON payload

Using the curl command above would create a node with name “myNode” with the IP “10.1.1.1”.

Python examples

Curl is a great tool for troubleshooting and understanding the basics, but in the end you’ll want to use a scripting language.

While you still can use basic authentication as an admin you should opt for a token when authenticating against the REST API.

Please note that if you do these things it’d recommended to use some existing F5 Python libraries or write your own class which manages token renewals and such. But at the same time, you’re probably here to get a grasp of how the API basics works so below are some simplified examples.

Getting a token

Populate the variables below (username, password, ltm) and you’ll end up with a token.

import requests, json

username = 'user'
password = 'password'
ltm = 'myltm.company.com'

body = {
    "username": username,
    "password": password,
    "loginProviderName": "tmos"
}

token_response = requests.post(
    f'https://{ltm}/mgmt/shared/authn/login',
    verify=False,
    auth=(username, password),json=body)\
    .json()

token = token_response['token']['token']

Please note that while verify=False is used above you should opt out of this if you have a legitimate certificate for your management (which you should have).

Retrieving pools

Now that we have token we can go ahead and use it in the subsequent requests to the API. Please note that unless you patch the token to increase the time span in which it is valid it’ll last for 20 minutes.

Appending the following code to the script above will result in the LTM pools being saved in the pools variable.

headers = {
    "X-F5-Auth-Token": token
}

pools = requests.get(
    f'https://{ltm}/mgmt/tm/ltm/pool',
    headers=headers,
    verify=False).json()

Creating a node

The example below will create a node with the name myNode and the IP 10.1.1.1.

requests.post(
   f'https://{ltm}/mgmt/tm/ltm/node',
   headers=headers,
   json={"name":"myNode","address":"10.1.1.1"}
)

Performance considerations

  • If with and without “/stats” gives you the information you need, go without. Simply because “/stats” uses much more  resources.
  • Don’t make using expandSubcollections into a habit.
  • Use $select whenever you can. The REST call would still generate the same amount of data, but less will be sent over the network which means saving CPU resources on both sides.

Troubleshooting

Malformed JSON string

You might get an error message when creating objects telling you that your JSON string is malformed:

malformed JSON string, neither array, object, number, string or atom, at character offset 0 (before "<?xml version="1.0" ...") at /usr/bin/json_pp line 44.

But you’ve validated it on multiple places online. What could be wrong?

Re-check your credentials. Safest way to exclude credentials is to try the admin account, but I do not recommend using it in actual scripts if it can be avoided.

Authorization failed

Unless you’re using token based authentication (available from 12.x) the user accessing the iControl REST API must have admin access. Re-check your credentials.

When the API documentation fails

Sometimes you will encounter instances where the documentation is lacking a bit. This can be very frustrating and it might feel like you’ve hit a dead end. Here’s one way to potentially solve some of these issues.

In this example we’re going to attempt to create a client SSL profile using the normal procedure.

First, let’s go to the API documentation on devcentral:

https://devcentral.f5.com/wiki/iControlREST.APIRef_tm_ltm_profile_client-ssl.ashx

The page displays the following for key, cert and chain:

DEPRECATED – use cert-key-chain option instead. Specifies the name of a key file that you generated and installed on the system. The default key name is default.key.

Searching for cert-key-chain on the page gives us the following:

Well, that wasn’t very helpful, right?

After a while I decided to first read a client SSL profile object and then go from there.

List the current profiles by using the command:

curl -s -k -u "admin:admin" https://192.168.10.23/mgmt/tm/ltm/profile/client-ssl/ | json_pp

The result (omitted a bunch of information for the sake of readability) shows the following:

{
   "kind" : "tm:ltm:profile:client-ssl:client-sslcollectionstate",
   "selfLink" : "https://localhost/mgmt/tm/ltm/profile/client-ssl?ver=12.1.2",
   "items" : [
      {
         ...
         "name" : "mySSLProfile",
         "certKeyChain" : [
            {
               "keyReference" : {
                  "link" : "https://localhost/mgmt/tm/sys/file/ssl-key/~Common~fw.domain.local.key?ver=12.1.2"
               },
               "certReference" : {
                  "link" : "https://localhost/mgmt/tm/sys/file/ssl-cert/~Common~fw.domain.local.crt?ver=12.1.2"
               },
               "cert" : "/Common/fw.domain.local.crt",
               "chainReference" : {
                  "link" : "https://localhost/mgmt/tm/sys/file/ssl-cert/~Common~myChain.crt?ver=12.1.2"
               },
               "chain" : "/Common/myChain.crt",
               "key" : "/Common/fw.domain.local.key",
               "name" : "fw.domain.local_myChain"
            }
         ]
         ...
      }
   ]
}

The references properties can safely be removed, which gives us the following json:

      {
         "name" : "mySSLProfile",
         "certKeyChain" : [
            {
               "cert" : "/Common/fw.domain.local.crt",
               "chain" : "/Common/myChain.crt",
               "key" : "/Common/fw.domain.local.key",
               "name" : "fw.domain.local_myChain"
            }
         ]
      }

Minifying it to be used in curl (there are tools for this online):

{"name":"mySSLProfile","certKeyChain":[{"cert":"/Common/fw.domain.local.crt","chain":"/Common/myChain.crt","key":"/Common/fw.domain.local.key","name":"fw.domain.local_myChain"}]}

Constructing our command like the node example above:

curl -s -k -u "admin:admin" https://192.168.10.23/mgmt/tm/ltm/profile/client-ssl -H 'Content-Type: application/json' -X POST -d '{"name":"mySSLProfile","certKeyChain":[{"cert":"/Common/fw.domain.local.crt","chain":"/Common/myChain.crt","key":"/Common/fw.domain.local.key","name":"fw.domain.local_myChain"}]}' | json_pp

Bingo!