on
27-Jul-2017
12:30
- edited on
05-Jun-2023
22:36
by
JimmyPackets
If you have dabbled with python and iControl over the years, you might be familiar with some of my other “Getting Stared with …” articles on python libraries. I started my last, on Bigsuds, this way:
I imagine the progression for you, the reader, will be something like this in the first six- or seven-hundred milliseconds after reading the title: Oh cool! Wait, what? Don’t we already have like two libraries for python? Really, a third library for python?
It’s past time to update those numbers as the forth library in our python support evolution, the f5-common-python SDK, has been available since March of last year! I still love Bigsuds, but it only supports the iControl SOAP interface. The f5-common-python SDK is under continuous development in support of the iControl REST interface, and like Bigsuds, does a lot of the API heavy lifting for you so you can just focus on the logic of bending BIG-IP configuration to your will. Not all endpoints are supported yet, but please feel free to open an issue on the GitHub repo if there’s something missing you need for your project. In this article, I’ll cover the basics of installing the SDK and how to utilize the core functionality.
This section is going to be really short, as the SDK is uploaded to PyPI after reach release, though you can clone the GitHub project and run the development branch with latest features if you so desire. I'd recommend installing in a virtual environment to keep your system python uncluttered, but YMMV.
pip install f5-sdk
A simple one-liner and we're done! Moving on...
The first thing you’ll want to do with your shiny new toy is authenticate to the BIG-IP. You can use basic or token authentication to do so.
I disable the certificate security warnings on my test boxes, but the first two lines in the sample code below are not necessary if you are using valid certificates
>>> import requests >>> requests.packages.urllib3.disable_warnings() >>> from f5.bigip import ManagementRoot >>> # Basic Authentication >>> b = ManagementRoot('ltm3.test.local', 'admin', 'admin') >>> # Token Authentication >>> b = ManagementRoot('ltm3.test.local', 'admin', 'admin', token=True) >>> b.tmos_version u'12.1.0'
The
b
object has credentials attached and various other attributes as well, such as the tmos_version
attribute shown above. This is the root object you’ll use (of course you don’t have to call it b, you can call it plutoWillAlwaysBeAPlanetToMe if you want to, but that’s a lot more typing) for all the modules you might interact with on the system.
The method mappings are tied to the tmsh and REST URL ids. Consider the tmsh command
tmsh list /ltm pool
. In the URL, this would be https://ip/mgmt/tm/ltm/pool. For the SDK, at the collection level the command would be b.tm.ltm.pools
. It's plural here because we are signifying the collection.
If there is a collection already ending in an s, like the subcollection of a pool in members, it would be addressed as members_s. This will be more clear as we work through examples in later articles, but I wanted to provide a little guidance before moving on.
There are two types of collections (well three if you include subcollections, but we’ll cover those in a later article,) organizing collections and collections. An organizing collection is a superset of other collections. For example, the ltm or net module listing would be an organizing collection, whereas ltm/pool or net/vlan would be collections. To retrieve either type, you use the
get_collection
method as shown below, with abbreviated output.
# The LTM Organizing Collection >>> for x in b.tm.ltm.get_collection(): ... print x ... {u'reference': {u'link': u'https://localhost/mgmt/tm/ltm/auth?ver=12.1.0'}} {u'reference': {u'link': u'https://localhost/mgmt/tm/ltm/data-group?ver=12.1.0'}} {u'reference': {u'link': u'https://localhost/mgmt/tm/ltm/dns?ver=12.1.0'}} # The Net/Vlan Collection: >>> vlans = b.tm.net.vlans.get_collection() >>> for vlan in vlans: ... print vlan.name ... vlan10 vlan102 vlan103
A named resource, like a pool, vip, or vlan, is a fully configurable object for which the CURDLE methods are supported. These methods are:
Let’s work through all these methods with a pool object.
>>> b.tm.ltm.pools.pool.exists(name='mypool2017', partition='Common') False >>> p1 = b.tm.ltm.pools.pool.create(name='mypool2017', partition='Common') >>> p2 = b.tm.ltm.pools.pool.load(name='mypool2017', partition='Common') >>> p1.loadBalancingMode = 'least-connections-member' >>> p1.update() >>> assert p1.loadBalancingMode == p2.loadBalancingMode Traceback (most recent call last): File "", line 1, in AssertionError >>> p2.refresh() >>> assert p1.loadBalancingMode == p2.loadBalancingMode >>> p1.delete() >>> b.tm.ltm.pools.pool.exists(name='mypool2017', partition='Common') False
Notice in line 1, I am looking to see if the pool called mypool2017 exists, to which I get a return value of False. So I can go ahead and create that pool as shown in line 3. In line 4, I load the same pool so I have two local python objects (p1, p2) that reference the same BIG-IP pool (mypool2017.) In line 5, I update the load balancing algorithm from the default of round robin to least connections member. But at this point, only the local python object has been updated. To update the BIG-IP, in line 6 I apply that method to the object. Now if I assert the LB algorithm between the local p1 and p2 python objects as shown in line 7, it fails, because we have updated p1, but p2 is still as it was when I initially loaded it. Refreshing p2 as shown in line 11 will update it (the local python object, not the BIG-IP pool.) Now I assert again in line 12, and it does not fail. As this was just an exercise, I delete the new pool (could be done on p1 or p2 since they reference the same BIG-IP object) in line 13, and a quick check to see if it exists in line 14 returns false.
The great thing is that even though the endpoints change from pool to virtual to rule and so on, the methods used for them do not.
This is just the tip of the iceberg! There is much more to cover, so come back for the next installment, where we’ll cover unnamed resources and commands. If you can't wait, feel free to dig into the SDK documentation.
the best advice I can give on doing this properly is to look at Tim Rupp's Ansible modules for creating/modifying these objects. They are by far the most complete implementations I've seen using the SDK.
with regard to your error, the correct method is
tm.ltm.virtual_address_s.virtual_address.exists()
Thank you Jason for your prompt reply. I looked at Tim Rupp's modules and took your advise to use it to configure the new unit with Ansible. But still thinking to use f5-sdk to read the values from Old unit, create hosts-variable file for Ansible and then run it to configure the new unit. What do you think ?
Would you please help me again to check my code below which trying to find out how many profiles attached to the VIP :
BigIP Version : 12.1.2 HF2
The part of REST API response is below :
"profilesReference": {
"link": "https://localhost/mgmt/tm/ltm/virtual/~Common~testvip/profiles?ver=12.1.2",
"isSubcollection": true,
"items": [
{
"kind": "tm:ltm:virtual:profiles:profilesstate",
"name": "http_XForwardedFor",
"partition": "Common",
"fullPath": "/Common/http_XForwardedFor",
"generation": 508,
"selfLink": "https://localhost/mgmt/tm/ltm/virtual/~Common~testvip/profiles/~Common~http_XForwardedFor?ver=12.1.2",
"context": "all",
"nameReference": {
"link": "https://localhost/mgmt/tm/ltm/profile/http/~Common~http_XForwardedFor?ver=12.1.2"
}
},
{
"kind": "tm:ltm:virtual:profiles:profilesstate",
"name": "oneconnect",
"partition": "Common",
"fullPath": "/Common/oneconnect",
"generation": 508,
"selfLink": "https://localhost/mgmt/tm/ltm/virtual/~Common~testvip/profiles/~Common~oneconnect?ver=12.1.2",
"context": "all",
"nameReference": {
"link": "https://localhost/mgmt/tm/ltm/profile/one-connect/~Common~oneconnect?ver=12.1.2"
}
},
{
"kind": "tm:ltm:virtual:profiles:profilesstate",
"name": "tcp-lan-optimized",
"partition": "Common",
"fullPath": "/Common/tcp-lan-optimized",
"generation": 508,
"selfLink": "https://localhost/mgmt/tm/ltm/virtual/~Common~testvip/profiles/~Common~tcp-lan-optimized?ver=12.1.2",
"context": "serverside",
"nameReference": {
"link": "https://localhost/mgmt/tm/ltm/profile/tcp/~Common~tcp-lan-optimized?ver=12.1.2"
}
},
{
"kind": "tm:ltm:virtual:profiles:profilesstate",
"name": "tcp-wan-optimized",
"partition": "Common",
"fullPath": "/Common/tcp-wan-optimized",
"generation": 508,
"selfLink": "https://localhost/mgmt/tm/ltm/virtual/~Common~testvip/profiles/~Common~tcp-wan-optimized?ver=12.1.2",
"context": "clientside",
"nameReference": {
"link": "https://localhost/mgmt/tm/ltm/profile/tcp/~Common~tcp-wan-optimized?ver=12.1.2"
}
},
{
"kind": "tm:ltm:virtual:profiles:profilesstate",
"name": "testvip-ssl",
"partition": "Common",
"fullPath": "/Common/testvip-ssl",
"generation": 508,
"selfLink": "https://localhost/mgmt/tm/ltm/virtual/~Common~testvip/profiles/~Common~testvip-ssl?ver=12.1.2",
"context": "clientside",
"nameReference": {
"link": "https://localhost/mgmt/tm/ltm/profile/client-ssl/~Common~testvip-ssl?ver=12.1.2"
}
}
]
}
}
My f5-sdk code is :
vip = mgmt.tm.ltm.virtuals.virtual.load(name='testvip', partition='Common')
print (vip.profilesReference)
for p in vip.profilesReference:
print (p)
Output is :
{'link': 'https://localhost/mgmt/tm/ltm/virtual/~Common~testvip/profiles?ver=12.1.2', 'isSubcollection': True}
link
isSubcollection
How can I get to "items" and then read the "name" of each item to identify which profile is attached to this VIP.
Thank you,
Muhammad
You can do this by first loading the virtual server, then the profiles, like this:
>>> vip = b.tm.ltm.virtuals.virtual.load(name='testvip')
>>> profiles = vip.profiles_s.get_collection()
Then you can check the number of profiles with len, and then print out their names:
>>> len(profiles)
4
>>> for profile in profiles:
... print profile.name
...
cssl
http
serverssl
tcp
>>>
Hey There Jason. Great Tutorials. So I am following your train and maybe I am missing something. So I want to print out a list of Current VIPS and their status. There are over 2 hundred VIPs.
My specific question is how to find out the variables allowed:
For example:
import requests
requests.packages.urllib3.disable_warnings()
from f5.bigip import ManagementRoot
Basic Authentication
b = ManagementRoot('10.234.1.82', 'admin', 'Cl0udyD@y$')
Token Authentication
b = ManagementRoot('ltm3.test.local', 'admin', 'admin', token=True)
print(b.tmos_version)
virtual_servers = b.tm.ltm.virtuals.get_collection()
print(type(virtual_servers))
print(virtual_servers)
for vips in virtual_servers:
print(vips.name)
So I see names is a variable I can pull, but is there a way (documentation or link or even a list pulled via Python) for me to see what other information I can pull that is available for the Virtual Servers, such as the IP, the Associated Pool and maybe even the VIP Up/Down availability status. I might be asking it wrong, and if I am, let me know and I can further attempt to clarify. THANKS Wally
Hi Wally,
There are couple of ways that you can find all the variables.
1) Use postman to query one of the existing Virtual on F5 and find all the variables.
2) Second or the easiest way is to login to and then browse.
https:///restui/default/default.html?$display=/mgmt/tm/ltm/virtual/~Common~mytest-virtual-server-https/
The above will give you a good list of variables available on your Virtual and then you can use F5 SDK to retrieve them.
Hope it helps.
Thank you,
Muhammad
Via postman, you can query the example as well which should have all the fields whether you are using them or not. Via the sdk the example is a collection state and the pool resource kind is not, so the instance creation will terminate with a kind mismatch. I am working on this in issue 1457.
I am having a problem where my F5s are taking a little longer to respond for authentications that they used to and on my phython implementation on Apache it is causing me to get a "500 Internal Server Error" I believe it to be some sort of timeout but am unsure as to where the timeout is and how to fix it. Has anyone else faced this kind of issue and do you know of a resolution to it? Thanks.
Hi Jason,
You responded to a comment above about getting profiles for a particular virtual server. I'm struggling with this a little bit and have a couple questions. Maybe you can help.
When I get a get a collection of profiles for a specific vs I get a couple things back that I don't understand. The first thing is "websecurity", the second thing is that it appears there is an 'ASM_' applied to my the front of an ASM policy name. I'm trying to get a list of all the ASM policies / DoS policies tied to a particular vs but I'm not sure what these things are telling me.
Is it expected to prepend 'ASM_' to ASM policy names such that I can use strip it off and use it as a source of truth?
Is 'websecurity' in some way going to get me to a point where I can identify a DoS profile?
Last thing, how do I get logging profiles applied to vs's?
Thanks a ton for entertaining my questions. Any help you can provide is greatly appreciated!
Matt
HI Matt, I haven't personally done much with ASM around the sdk, but if you'll open a question and post a sanitized version of what you're looking at there, I'll take a look.
Done. It's super simple code. Probably the most basic thing you can see. I just want to get the security profiles associated with the vips really, and understand the output of the code I posted.
Thanks a ton.
Matt
Hi Jason,
A question about the f5-sdk and the REST api in general. Is it possible with the f5-sdk to get the raw output of the tmsh commands back as a json string/object?
From the point of view of change validation, it can be a requirement that we explicitly show the output of the config before a change and the output after the change and the differences.
For example if would be nice to be able to get an objects configuration back as a json object as this would allow to compare and document the differences, if the action was to replace the profile on a a virtual server this would make it easy to compare the before and after to validate only the documented change happened.
This also documents the original config in the case where the change has to be reversed due to issues etc.
Hi @admafitz, I don't think so directly, the rest interface provides "sanitized" data as json objects, not the raw tmsh output. However, you could use the bash util via rest to get raw input.
x = b.tm.util.bash.exec_cmd('run', utilCmdArgs='-c "tmsh list ltm pool testpool"')
print(x.commandResult)
ltm pool testpool {
description "This pool is for test purposes only"
members {
192.168.103.20:http {
address 192.168.103.20
session monitor-enabled
state down
}
192.168.103.21:http {
address 192.168.103.21
session monitor-enabled
state down
}
192.168.103.22:http {
address 192.168.103.22
session monitor-enabled
state down
}
}
Thanks Jason,
I thought this might be the case. I have been told/heard that using the bash exec approach significantly increases the use of the CPU on the F5 device due to (in part) command wrapping/unpacking via REST eg: rest makes call/wraps command, unwraps it on the box, goes through the shell to bash, parses/filters the output, box then wraps the results back up into a json object which is then returned as the result.
Specifically I am thinking of the above approach and also the F5 Ansible modules which are implemented using the F5-sdk and the bigip_command module, which I believe acts in the same way as you have described above.
Is it the case that using the bash exec approach above (or similarly the bigip_command F5 ansible module) that this will result in high CPU being see on the device? If yes is there any recommendation from F5 what to do in the situation where this is really needed or is there recommended practices how to work around this if it is a problem?
Hi Jason,
Thanks for sharing how to install f5-sdk.
While accessing the ltm I am getting below error which is related to SSL cert. Can you please help me how I can disbale the SSL cert checking:
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='ashi2.com', port=443): Max retries exceeded with url: /mgmt/tm/sys/ (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7f078c5b66a0>: Failed to establish a new connection: [Errno -2] Name or service not known',))
Regards,
Ashish Solanki
[root@localhost ~]# f5 login --authentication-provider bigip --host 192.168.70.14 --user root
Password:
2020-04-12 13:30:09,157 - f5sdk.utils.http_utils - WARNING: SSL Insecure request, recommend adding a valid certificate to the device
You can use the below line in your script to remove the stdout warning spam when you have self signed certificates configured:
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
Note that you need to explicitly import urllib3 module in your script for this to work.
still getting the same error. Is there a way to check the dependencies for f5-sdk.
I followed this article while installing f5-sdk and suspecting may be there are depend packages which are not installed with "pip3 install f5-sdk".
I am using Centos* to install SDK and successfully able to SSH my LTM from Centos. LTM VM is connected to internet also.
Below are the steps which I followed:
1. Executed this command on Centos8 pip install f5-sdk
Got message successfully installed.
2. Excuted Python3 command and tried executed below commands:
>>> import requests
>>> requests.packages.urllib3.disable_warnings()
>>> from f5.bigip import ManagementRoot -----------------> after executing this command getting error which I has shared.
>>> # Basic Authentication
>>> b = ManagementRoot('ltm3.test.local', 'admin', 'admin')
>>> # Token Authentication
>>> b = ManagementRoot('ltm3.test.local', 'admin', 'admin', token=True)
>>> b.tmos_version
u'12.1.0'
3. I am able to ssh my F5 LTM from CentOS ----> ssh admin@192.168.70.14 ----> successfully logged in into the LTM
4. when I execute print(requests.get('https://ashi.com')) getting error related to SSL cert.
5. I have one user for LTM i.e. admin/admin which is having Administrator priviledges and access to advanced shell also.
6. LTM is connected to internet also.
https://devcentral.f5.com/s/articles/getting-started-with-the-f5-common-python-sdk-27438 ----> followed this article and in this it is mentioned:
"I disable the certificate security warnings on my test boxes, but the first two lines in the sample code below are not necessary if you are using valid certificates"
Regards,
Ashish Solanki
Hi guys
I'm very new to Python, and I'm trying to use SDK to manage my BIG-IP objects. I don't know why I'm getting this error, if someone could help me I would appreciate it. I can't even establish a successful connection to my BIG-IP (which is local on my VMware Fusion).
Looks like connectivity or DNS resolution, can you test connectivity using curl or postman to connect from the python box to the F5?