Demystifying iControl REST Part 3 - How to pass query parameters and tmsh options
iControl REST. It’s iControl SOAP’s baby, brother, introduced back in TMOS version 11.4 as an early access feature but released fully in version 11.5.
Several articles on basic usage have been written on iControl REST (see the resources at the bottom of this article) so the intent here isn’t basic use, but rather to demystify some of the finer details of using the API. The first article covered URI specifics, the second article discussed subcollections, and this third article will cover query parameters.
Query Parameter Definitions
F5 has documented a number of query parameters that can be passed into iControl ReST calls in order to modify their behavior. The first set follows the OData (open data protocol) standard. The filter parameter also supports several operators.
- $filter
- $select
- $skip
- $top
Yes, the dollar sign is important and necessary on these parameters. The operators you can use on these parameters are below. Note that the eq operator can only be used with the filter.
- eq - equal
- ne - not equal
- lt - less than
- le - less than or equal
- gt - greater than
- ge - greater than or equal
- Logical Operators:
- and
- or
- not
Beyond the OData parameters, there are a few custom parameters as well.
- expandSubcollections - allows you to get the subcollection data in the initial request for objects that have subcollections.
- options - allows you to add arguments to the tmsh equivalent command. An example will be shown below.
- ver - This is for the specific TMOS version. Setting this parameter guarantees consistent behavior through code upgrades. Please note that the JSON return data for a number of calls has changed between the initial release in 11.5.0 and the current release. No items have been removed, but key/value pairs in the output have been added.
Note the lack of a dollar sign on the custom parameters.
Example #1 - Filter
Now that we have the parameters and operators defined, let’s take a look at some examples. First, we’ll take a look at the $filter parameter. If you want to limit your results to a particular partition, your URL will look something like this:
https://172.16.44.128/mgmt/tm/ltm/pool?$filter=partition eq staging https://172.16.44.128/mgmt/tm/ltm/pool?$filter=partition%20eq%20staging https://172.16.44.128/mgmt/tm/ltm/pool?$filter=partition+eq+staging
As long as your client tool supports it, any of these formats will work, but the resulting selfLink reflects the latter format:
Example #2 - Select
I didn’t post the return data from example 1 because it’s a lot of data, even for a small set of returned results. Most of it is all the fields in a pool that are there and important, but default and not of as immediate importance as others. This is where the $select parameter comes in. If you just want to take a look at the name of the pool and say the load balancing mode, your URL will look like this (still filtering for the staging partition:)
https://172.16.44.128/mgmt/tm/ltm/pool?$filter=partition+eq+staging&$select=name,loadBalancingMode
This results in a smaller subset of data limited to the fields we “selected"
items: [5] 0: { name: "sp1" loadBalancingMode: "round-robin" }- 1: { name: "sp2" loadBalancingMode: "round-robin" }- 2: { name: "sp3" loadBalancingMode: "round-robin" }
Example #3 - Top & Skip
For larger sets of data, you can page through the objects in chunks with $top and $skip. If $skip is not specified when $top is used, it behaves as though set to 0. Please note, however, that paging is restricted to collections and sub collections, so whereas this would work to page through the defined data groups, it would not work to page through the records of a data group. Let’s add the top parameter to our previous URL:
https://172.16.44.128/mgmt/tm/ltm/pool?$filter=partition eq staging&$select=name,loadBalancingMode&$top=2 #Results { kind: "tm:ltm:pool:poolcollectionstate" selfLink: "https://localhost/mgmt/tm/ltm/pool?$filter=partition+eq+staging&$select=name%2CloadBalancingMode&$top=2&ver=12.0.0" currentItemCount: 2 itemsPerPage: 2 pageIndex: 1 startIndex: 1 totalItems: 5 totalPages: 3 items: [2] 0: { name: "sp1" loadBalancingMode: "round-robin" } - 1: { name: "sp2" loadBalancingMode: "round-robin" } - - nextLink: "https://localhost/mgmt/tm/ltm/pool?$filter=partition+eq+staging&$select=name%2CloadBalancingMode&$top=2&$skip=2&ver=12.0.0"
So we got the same data back as before, only 2 items instead of the original 5, as well as some additional fields that weren’t there previously. Note that once $top is used, the key/value pairs “nextLink”, “currentItems”, and “totalItems” are added to the response. “nextLink” is the URI that will grab the next $top number of results from the query. If you parse this value and use it (once you have replaced the localhost with your actual host information), you will not have to perform any paging calculations. “currentItems” tells you how many items have been returned in the current call. If this value is less than $top, then you know you have reached the end of the items. “totalItems” tells you how many items would be returned if one did not page using $top.
Example #4 - Options
For this next example, we’ll start with tmsh. If you want to get the connections on the BIG-IP, you type “tmsh show sys conn” at the command line. This can be a very large set of data, however, so there are options on the command line to narrow this down, like cs-client-addr, cs-client-port, and so on. So a narrowed down request at the command line would look like “tmsh show sys conn cs-client-addr 10.0.0.1 cs-client-port 62223.” To translate this command to an API request, you need to use the options parameter
https://172.16.44.128/mgmt/tm/sys/connection?options=cs-server-addr+192.168.102.50+cs-server-port+80 #Results { kind: "tm:sys:connection:connectionstats" selfLink: "https://localhost/mgmt/tm/sys/connection?options=cs-server-addr+192.168.102.50+cs-server-port+80&ver=11.6.0" apiRawValues: { apiAnonymous: "Sys::Connections 192.168.102.5:57359 192.168.102.50:80 192.168.102.5:57359 192.168.103.11:8080 tcp 2 (tmm: 1) none Total records returned: 1 " }- }
Example #5 - Expanding Subcollections
For our final example, we’ll use the expandSubcollections parameter. This is useful for querying objects like pools that have subcollections. Without the parameter specified, the pool data is returned with the specification that pool members is a subcollection, but doesn’t return the set of pool members. By providing the parameter, the pool members are returned along with the pool definition (only first one shown for brevity.)
https://172.16.44.128/mgmt/tm/ltm/pool/testpool?expandSubcollections=true #Results { kind: "tm:ltm:pool:poolstate" name: "testpool" fullPath: "testpool" generation: 1 selfLink: "https://localhost/mgmt/tm/ltm/pool/testpool?expandSubcollections=true&ver=11.6.0" allowNat: "yes" allowSnat: "yes" ignorePersistedWeight: "disabled" ipTosToClient: "pass-through" ipTosToServer: "pass-through" linkQosToClient: "pass-through" linkQosToServer: "pass-through" loadBalancingMode: "round-robin" minActiveMembers: 0 minUpMembers: 0 minUpMembersAction: "failover" minUpMembersChecking: "disabled" queueDepthLimit: 0 queueOnConnectionLimit: "disabled" queueTimeLimit: 0 reselectTries: 0 serviceDownAction: "none" slowRampTime: 10 membersReference: { link: "https://localhost/mgmt/tm/ltm/pool/~Common~testpool/members?ver=11.6.0" isSubcollection: true items: [7] 0: { kind: "tm:ltm:pool:members:membersstate" name: "192.168.103.10:80" partition: "Common" fullPath: "/Common/192.168.103.10:80" generation: 1 selfLink: "https://localhost/mgmt/tm/ltm/pool/~Common~testpool/members/~Common~192.168.103.10:80?ver=11.6.0" address: "192.168.103.10" connectionLimit: 0 dynamicRatio: 1 ephemeral: "false" fqdn: { autopopulate: "disabled" } ...
Example #6 - Careful! Select Revisited
If you want to select just the name and address from the pool members in the previous example, it's not as simple as adding the $select=name,address to that query. Remember from the earlier article about your object/component/sub-component tiers. Instead, you need to specify the members subcollection in the URL, then attach your select parameter.
https://172.16.44.128/mgmt/tm/ltm/pool/testpool/members?$select=name,address #Results { kind: "tm:ltm:pool:members:memberscollectionstate" selfLink: "https://localhost/mgmt/tm/ltm/pool/testpool/members?$select=name%2Caddress&ver=11.6.0" items: [7] 0: { name: "192.168.103.10:80" address: "192.168.103.10" }- 1: { name: "192.168.103.10:8080" address: "192.168.103.10" }- 2: { name: "192.168.103.11:80" address: "192.168.103.11" } ...
A Whiteboard Wednesday Shout Out to iControl REST
I’ve summarized a lot of what was covered in this article in the following Whiteboard Wednesday video. Enjoy!
- tatmotivCirrostratusGreat article, especially since it explains many features which are not covered at all in the official iControl REST documentation! Many Thanks.
- Patrick_Chang_7Historic F5 AccountIt is very important to filter your results when you are expecting a lot of output in the return. One can easily cause problems by overloading the management network.
- Andrew_Le_12873NimbostratusCan you get example for "options" using a component other than 'sys connection' ?
- bahoug_11846NimbostratusCan this be used for listing/deleting persistence records? Looking at the available commands it doesn't appear to be possible.
- JRahm_128324Historic F5 Account@bahoug, yes this is possible: https://172.16.44.15/mgmt/tm/ltm/persistence/persist-records?options=client-addr+192.168.102.1 Results from my local query: { kind: "tm:ltm:persistence:persist-records:persist-recordsstats" selfLink: "https://localhost/mgmt/tm/ltm/persistence/persist-records?options=client-addr+192.168.102.1&ver=12.0.0" apiRawValues: { apiAnonymous: "Sys::Persistent Connections source-address 192.168.102.1 192.168.102.60:80 192.168.103.10:80 (tmm: 0) Total records returned: 1 " }- }
- bahoug_11846Nimbostratus@JRahm I'm guessing the reason I cant get it to work is I am running 11.5.1. I see in your self link you are using v12.0. Your example is exactly what I am looking for to delete persistence records and system connections. I've seen a few other examples that call cli scripts from the restAPI, however its not as elegant as just being able to use the restAPI. BTW this is a great article thanks for putting it together.
- JRahmAdminI'll fire up an 11.5 image tomorrow and test, it should work as is (minus the version parameter) in all versions, but I'll take a look at the tmsh command in 11.5 and make sure the rest version works as well.
- mayouche_162667NimbostratusI was able to run these examples against my environment running version 11.5.3 i have a couple of questions: I'm getting could not resolve GET when using in version 11.5.3 Does Anybody have tips on how to manipulate the output to get a clean formatting? Thank you
- JRahmAdmin@mayouche, can you move your question to Q&A with a link to this article and provide more details? Thanks, Jason
- mraful_64014NimbostratusThis doesn't work everywhere on all collections. For example, if I am looking for the software version and hotfix currently running, the select has no effect here: curl -k -u admin:myPassword -H "Content-Type: application/json" -X GET https://10.19.1.10/mgmt/tm/sys/software/status?$select=active,version,build -d "" | python -m json.tool