At the beginning of August, John Wagnon and I will join several of F5's excellent sales engineers in NYC to offer iRules training classes as part of F5 Agility 2014 - Americas. This year, each classroom has a layout of 30 BIG-IP Virtual Editions. This is great, as each student will likely have their own system to work with. It's also a monumental task on the planning side. Whereas before I could just copy paste configuration into multiple partitions in one system, now I have to paste the configuration into 30 systems. This realization triggered my lazy button, but it also made me think back to my large-scale operations days. This is something we all deal with in operations. "I have this configuration object here that I need to deploy to all my BIG-IPs...how do I do that?"

In this case, I am using an iRule for a procs lab that needs to exist in the common partition on all the systems so it can be called from the iRules that the students will write. I was going to just connect to the cli and paste into tmsh, but that wasn't working with the iRule code (it required the interactive editor) so I thought I'd use some iControl REST code I played with when that API was released several months back. After what was literally a few minutes of coding, I pushed out the iRule to 28 systems (system 7 and system 20 were down at the time) in less than a minute.

Let me restate that. I pushed out a configuration object to 28 systems in less than a minute. There is no magic here, but think about the time you'd take to log in to each system, paste your code, verify it, and log out, then multiply that by 28. If you're fast, you're still looking at 14-15 minutes. With today's demands on an ever-shrinking workforce, that 14-15 minutes is precious. Now think of the other things you do on a day to day basis that can be automated, thus freeing up your time to focus on other more complex problems.

But I digress. Let's dig into the code, starting with the iControl REST calls.

 

def create_rule(bigip, name, code):
    payload = {}
    payload['kind'] = 'tm:ltm:rule:rulestate'
    payload['name'] = name
    payload['fullPath'] = name
    payload['apiAnonymous'] = code

    bigip.post('%s/ltm/rule/' % b_url_base, data=json.dumps(payload))
    print 'Rule %s created...' % name

def get_rule(bigip, name):
    rule = bigip.get('%s/ltm/rule/%s' % (b_url_base, name))
    return rule

 

There are two functions here, one to get rules and the other to create rules. In the get_rule function, I'm passing the bigip credentials object and the iRule name, and it is returning the json string that the BIG-IP returns. As Colin shared in earlier iControl REST articles, a get method gets data, put modifies it, and post creates it. So if we are creating an iRule, we need to use the post method as shown above in the create_rule function. When creating objects, you need to build the payload, establishing the kind and name and other attributes appropriate to the type of object you are creating. In fact, these two functions can be modified slightly to meet most of the get/create object methods in the API.

Now, let's take a look at the main loop.

 

if __name__ == "__main__":
    import requests, json

    with open('proc.tcl', 'r') as irule:
        mycode = irule.read()
    irule.close()

    b = requests.session()
    b.auth = ('admin', 'admin')
    b.verify = False
    b.headers.update({'Content-Type' : 'application/json'})

    for i in range(1,31):
        if i != 7 and i != 20:
            b_url_base = 'https://192.168.6.%d/mgmt/tm' % i
            create_rule(b, 'ruleProcLib3', mycode)
            rule_verify = get_rule(b, 'ruleProcLib3')
            print rule_verify.text

 

I installed the requests library (not part of the standard offering) and imported that and json to handle the web requests and the data types respectively. Next, I open the iRule text file and read it into a string, preserving the newlines and tabs. This results in the format below

 

'proc sequence {from to} {\n\tfor {set lst {}} {$from <=$to} {incr from} {\n\t\tlappend lst $from\n\t}\n\treturn $lst\n}'

 

After closing the file we read in, we build the session request object, complete with user credentials and content type.. Finally, we create a for loop with all the IP address (this case all IPs were in same subnet sequentially so I just looped on an integer, but you could loop on a list of IPs) and after checking to make sure it wasn't system 7 or system 20, set the base url, then call the functions, passing the session object, rule name, and code to the BIG-IP, then reading it back and printing to console before moving on to the next system. If I were to operationalize this script, I would add error checking from each call so the if statement to avoid systems 7 and 20 could be removed.

When running the script (only have one test system up currently, so my for loop is modified from above code) the output should look similar to the output below.

 

C:\Python27\python.exe C:/Users/rahm/PycharmProjects/scripts/ruledeploy.py
Rule ruleProcLib5 created...
{"kind":"tm:ltm:rule:rulestate","name":"ruleProcLib5","fullPath":"ruleProcLib5","generation":7173,
"selfLink":"https://localhost/mgmt/tm/ltm/rule/ruleProcLib5?ver=11.5.1",
"apiAnonymous":"proc sequence {from to} {\n\tfor {set lst {}} {$from <=$to} {incr from} {\n\t\tlappend lst $from\n\t}\n\treturn $lst\n}"}

Process finished with exit code 0