Getting started with the python SDK part 2: unnamed resources and commands

In the first article in this series we looked at the sdk installation steps, nomenclature, and basic BIG-IP instantiation. In this article, we’ll focus on unnamed resources and commands.

Working with Unnamed Resources

Unlike named resources like virtual servers and pools, an unnamed resource cannot be created or deleted, but otherwise can be configured similarly. A good example of an unnamed resource would be the BIG-IP system DNS settings. The path for this object is mgmt->tm->sys->dns. First, we need to load the object. I'll instantiate in this first example and assume it for the remaining ones.

import requests
from f5.bigip import ManagementRoot
from pprint import pprint as pp # for pretty print of json data
requests.packages.urllib3.disable_warnings() # ignore cert warnings

b = ManagementRoot('ltm3.test.local', 'admin', 'admin')
obj_dns = b.tm.sys.dns.load()
pp(obj_dns.raw)

{'_meta_data': {'allowed_commands': [],
                'bigip': ,
                'container': ,
                'exclusive_attributes': [],
                'icontrol_version': '',
                'icr_session': ,
                'minimum_version': '11.5.0',
                'object_has_stats': True,
                'required_command_parameters': set([]),
                'required_json_kind': 'tm:sys:dns:dnsstate',
                'required_load_parameters': set([]),
                'uri': 'https://ltm3.test.local:443/mgmt/tm/sys/dns/'},
 u'description': u'configured-by-dhcp',
 u'kind': u'tm:sys:dns:dnsstate',
 u'nameServers': [u'10.10.10.1'],
 u'numberOfDots': 0,
 u'search': [u'localdomain'],
 u'selfLink': u'https://localhost/mgmt/tm/sys/dns?ver=12.1.0'}

The metadata is added by the sdk, but the important attributes for configuration purposes here are nameServers and search. If we want to add a google cache resolver and a test.local domain to the seach field, we set the attributes appropriately as lists as shown below.

obj_dns.nameServers = ['10.10.10.1', '8.8.8.8']
obj_dns.search = ['localdomain', 'test.local']
obj_dns.update()
obj_dns.refresh()
obj_dns.nameServers
[u'10.10.10.1', u'8.8.8.8']
obj_dns.search
[u'localdomain', u'test.local']

Once the attributes are set, we call the update method. This will execute a refresh of the local object as well, but for demonstration purposes let’s call the refresh method as well so we can validate our new name servers and search list are accurate, which they are.

There are named resources in the API that behave like unnamed resources, in that they cannot be created or deleted, just updated. Examples would include authentication sources like tacacs, and the management-ip. But they still need to be loaded by name, unlike unnamed resources.

Working with Commands

Commands are interesting as we’re not working with configuration objects, we’re executing tasks like saving or loading the configuration, or kicking off a qkview for diagnostics. The method for commands is exec_cmd. Most commands, like the tmsh utilities, use the keyword run, but for configuration it would be load or save. There is usually a keyword argument required but not always. For our first example, let's look at a simple save of the configuration.

b.tm.sys.config.exec_cmd('save')

That’s it! Pretty simple and straight forward. A load is the same way, unless you are merging files, in which case you need to do a little extra work.

options = {}
options['file'] = '/var/config/rest/downloads/myfile.txt'
options['merge'] = True

b.tm.sys.config.exec_cmd('load', options=[options])

I'm looking into updating the sdk to make a merge cleaner. Also note that the ability to load has been merged to development but isn't yet in an official release.

Utility commands to work with files, ciphers, or dns clients are also available via the sdk. Here are a few examples:

## Checking DNS resolution from BIG-IP
>>> digresults = b.tm.util.dig.exec_cmd('run', utilCmdArgs='@8.8.8.8 www.google.com')
>>> digresults.commandResult
u'\n;  DiG 9.9.8-P4  @8.8.8.8 www.google.com\n; (1 server found)\n;; global options: +cmd\n;; Got answer:\n;; -HEADER- opcode: QUERY, status: NOERROR, id: 253\n;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1\n\n;; OPT PSEUDOSECTION:\n; EDNS: version: 0, flags:; udp: 512\n;; QUESTION SECTION:\n;www.google.com.\t\t\tIN\tA\n\n;; ANSWER SECTION:\nwww.google.com.\t\t225\tIN\tA\t216.58.192.228\n\n;; Query time: 29 msec\n;; SERVER: 8.8.8.8#53(8.8.8.8)\n;; WHEN: Thu Aug 24 14:12:30 CDT 2017\n;; MSG SIZE  rcvd: 59\n\n'
>

Note: data returned from utility commands isn't formatted as objects, it's just standard console output (note the newlines above) so any parsing required is up to you. In this next example, we use the python print command to format the newlines properly in displaying the data.

## Checking the Client Ciphers with a specified string
>>> cciphers = b.tm.util.clientssl_ciphers.exec_cmd('run', utilCmdArgs='TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:@STRENGTH')
>>> print cciphers.commandResult
       ID  SUITE                            BITS PROT    METHOD  CIPHER    MAC     KEYX
 0: 49172  ECDHE-RSA-AES256-CBC-SHA         256  TLS1    Native  AES       SHA     ECDHE_RSA
 1: 49162  ECDHE-ECDSA-AES256-SHA           256  TLS1    Native  AES       SHA     ECDHE_ECDSA
 2:    57  DHE-RSA-AES256-SHA               256  TLS1    Native  AES       SHA     EDH/RSA
 3:    56  DHE-DSS-AES256-SHA               256  TLS1    Native  AES       SHA     DHE/DSS
 4:    58  ADH-AES256-SHA                   256  TLS1    Native  AES       SHA     ADH
 5: 49167  ECDH-RSA-AES256-SHA              256  TLS1    Native  AES       SHA     ECDH_RSA
 6: 49157  ECDH-ECDSA-AES256-SHA            256  TLS1    Native  AES       SHA     ECDH_ECDSA
 7:    53  AES256-SHA                       256  TLS1    Native  AES       SHA     RSA
 8:   136  DHE-RSA-CAMELLIA256-SHA          256  TLS1    Native  CAMELLIA  SHA     EDH/RSA
 9:   135  DHE-DSS-CAMELLIA256-SHA          256  TLS1    Native  CAMELLIA  SHA     DHE/DSS
10:   132  CAMELLIA256-SHA                  256  TLS1    Native  CAMELLIA  SHA     RSA
11: 49170  ECDHE-RSA-DES-CBC3-SHA           168  TLS1    Native  DES       SHA     ECDHE_RSA
12: 49160  ECDHE-ECDSA-DES-CBC3-SHA         168  TLS1    Native  DES       SHA     ECDHE_ECDSA
13:    22  DHE-RSA-DES-CBC3-SHA             168  TLS1    Native  DES       SHA     EDH/RSA
14:    27  ADH-DES-CBC3-SHA                 168  TLS1    Native  DES       SHA     ADH
15: 49165  ECDH-RSA-DES-CBC3-SHA            168  TLS1    Native  DES       SHA     ECDH_RSA
16: 49155  ECDH-ECDSA-DES-CBC3-SHA          168  TLS1    Native  DES       SHA     ECDH_ECDSA
17:    10  DES-CBC3-SHA                     168  TLS1    Native  DES       SHA     RSA

I haven't finished adding all of the REST endpoints available yet, but any missing ones can be worked around using the bash command. For example, if you want to get the current status of the routing table, you can pass netstat -rn via the bash command like this:

>>> rtstat = b.tm.util.bash.exec_cmd('run', utilCmdArgs='-c "netstat -rn"')
>>> print rtstat.commandResult
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
127.1.1.0       0.0.0.0         255.255.255.0   U         0 0          0 tmm
192.168.102.0   0.0.0.0         255.255.255.0   U         0 0          0 vlan102
192.168.103.0   0.0.0.0         255.255.255.0   U         0 0          0 vlan103
10.0.2.0        0.0.0.0         255.255.255.0   U         0 0          0 eth0
10.10.10.0      0.0.0.0         255.255.255.0   U         0 0          0 vlan10
127.7.0.0       127.1.1.253     255.255.0.0     UG        0 0          0 tmm
127.20.0.0      0.0.0.0         255.255.0.0     U         0 0          0 tmm_bp
0.0.0.0         10.10.10.1      0.0.0.0         UG        0 0          0 vlan10

Note the extra quotes within the utilCmdArgs string around netstat -rn. These are necessary to pass the argument to the command you want bash to run, rather than to bash itself.

Join me next time where we will explore transactions!

Published Aug 24, 2017
Version 1.0
No CommentsBe the first to comment