Showing posts with label aXAPI. Show all posts
Showing posts with label aXAPI. Show all posts

Friday, October 11, 2013

A10 Networks aXAPI - Part 2 cli.deploy and cli.show_info

The code in this blog can be downloaded on my github account.
In my last post, A10 Networks aXAPI with Python, examples were given on utilizing Python with existing aXAPI methods such as slb.server.create, slb.service_group.create, and slb.virtual_server.create. It is efficient, clean, and quick.
But there are times when you just need to do a quick query, the procedure you want is not supported in existing method, or maybe you just don't have time to look thru all the documentation. What do you do then? Enter cli.deploy and cli.show_info.
cli.deploy and cli.show_info can be thought of as catch all methods that allows you to configure device or do show commands as if you are in front of the terminal. The procedures are the same, but the body of your HTTP post would just be the commands you want to enter.
  • cli.deploy
In this example, I just write a text file, called cliDeployCommands.txt that lists out the commands I want to enter:
A10_aXAPI$ cat cliDeployCommands.txt
slb server s1 10.0.2.128
port 80 tcp
slb server s2 10.0.2.129
port 80 tcp
wr mem
A10_aXAPI$
Then execute the script. The script is practically identical to the last post except the HTTP POST body. You can download the script on the GitHub link above, it is also pasted at the bottom of this post.
A10_aXAPI$ python axapi_cli_deploy.py -d 192.168.1.200 -c cliDeployCommands.txt
Session Created. Session ID: 958b183474deaa0914176da4121ca8
URL Created. URL: https://192.168.1.200/services/rest/V2/?&session_id=958b183474deaa0914176da4121ca8&format=json&method=cli.deploy&username=admin&password&a10&enable_password=''&grab_config=1 body: slb server s1 10.0.2.128
port 80 tcp
slb server s2 10.0.2.129
port 80 tcp
wr mem
Result: slb server s1 10.0.2.128
SoftAX(config-real server)#port 80 tcp
SoftAX(config-real server-node port)#slb server s2 10.0.2.129
SoftAX(config-real server)#port 80 tcp
SoftAX(config-real server-node port)#wr mem
Building configuration...
Write configuration to primary default startup-config
[OK]
SoftAX(config-real server-node port)#
A10_aXAPI$
  • cli.show_info
In this example, I do the same thing. Create a text file called 'showInfoCommands.txt':
A10_aXAPI$ cat showInfoCommands.txt
show version
show interface brief
A10_aXAPI$
And execute the script accordingly:
A10_aXAPI$ python axapi_cli_showInfo.py -d 192.168.1.200 -c showInfoCommands.txt
Session Created. Session ID: 9835d3e172e2cc25d1499a8b081b91
URL Created. URL: https://192.168.1.200/services/rest/V2/?&session_id=9835d3e172e2cc25d1499a8b081b91&format=json&method=cli.show_info body: show version
show interface brief
Result: show version
AX Series Advanced Traffic Manager AXSoftAX
Copyright 2007-2013 by A10 Networks, Inc. All A10 Networks products are
protected by one or more of the following US patents and patents pending:
7716378, 7675854, 7647635, 7552126, 20090049537, 20080229418, 20080040789,
20070283429, 20070271598, 20070180101
64-bit Advanced Core OS (ACOS) version 2.7.1-P2, build 57 (Aug-02-2013,12:17)
Booted from Hard Disk primary image
Licenses: Bandwidth
Serial Number: SoftAX1000004380
aFleX version: 2.0.0
aXAPI version: 2.1
Hard Disk primary image (default) version 2.7.1-P2, build 57
Hard Disk secondary image version 2.6.1-GR1-P10, build 46
Last configuration saved at Oct-11-2013, 02:29
Virtualization type: VMware
Hardware: 1 CPUs(Stepping 11), Single 9G Hard disk
Memory 2061 Mbyte, Free Memory 855 Mbyte
Hardware Manufacturing Code: N/A
Current time is Oct-11-2013, 02:36
The system has been up 2 days, 12 hours, 10 minutes
SoftAX#show interface brief
Port Link Dupl Speed Trunk Vlan MAC IP Address IPs Name
------------------------------------------------------------------------------------
mgmt Up Full 1000 N/A N/A 000c.29be.5b4c 192.168.1.200/24 1
1 Disb None None None 1 000c.29be.5b56 0.0.0.0/0 0
2 Disb None None None 1 000c.29be.5b60 0.0.0.0/0 0
3 Disb None None None 1 000c.29be.5b6a 0.0.0.0/0 0
SoftAX#
A10_aXAPI$
Again, full script can be viewed at the bottom of this post as well as downloaded from the GitHub link above.
So why wouldn't we use cli.deploy and cli.show_info all the time? After all, wouldn't we want to just use something that 'always work' instead of looking for a particular method every single time? I think the answer is 'maybe'. Some arguments can be made for NOT using cli.deploy and cli.show_info as the single source of tool:
  1. For cli.deploy, there is finite amount of buffer commands you can send in one shot. I have not run into it yet and I'd imagine is it enough for most situations, but there is a limit.
  2. For cli.deploy, you have to know the syntax of configuraiton and order of operations. It is meant for network engineers and arguably not intuative for developers.
  3. For cli.show_info, the result you get back is the same as you would on a remote session. You will need to do your own screen scraping and text parsing, no different than, say, an Expect script. This is HUGE for me, I really do hate screen scraping.
In conclusion, I believe they both have their places in the toolbag. Isn't it nice that A10 provides both options?
Leave me comments on how I can improve my script and ideas about future posts. I sure appreciate them.
The scripts can be downloaded here.
cli.deploy script:
A10_aXAPI$ cat axapi_cli_deploy.py
#!/usr/bin/env python
#
# v1, September 30, 2013
# by Eric Chou
#
# Reference: AX_aXAPI_Ref_v2-20121010.pdf
#
import httplib, json, urllib, urllib2, optparse
# specify device and command
parser = optparse.OptionParser()
parser.add_option('-d', '--device', dest="device", action="store")
parser.add_option('-c', '--command', dest="commandFile", action="store")
options, args = parser.parse_args()
device = options.device
commandFile = options.commandFile
# Gets the session ID
c = httplib.HTTPSConnection(device)
c.request("GET", "/services/rest/V2/?method=authenticate&username=admin&password=a10&format=json")
response = c.getresponse()
data = json.loads(response.read())
session_id = data['session_id']
print "Session Created. Session ID: " + session_id
# Construct HTTP URL and Post Body
post_body = open(commandFile, 'r').read()
url = "https://" + device + "/services/rest/V2/?&session_id=" + session_id + \
"&format=json&method=cli.deploy&username=admin&password&a10&enable_password=''&grab_config=1"
print "URL Created. URL: " + url + " body: " + post_body
# Making request
req = urllib2.Request(url, post_body)
rsp = urllib2.urlopen(req)
content = rsp.read()
print "Result: " + content
A10_aXAPI$
cli.show_info script:
A10_aXAPI$ cat axapi_cli_showInfo.py
#!/usr/bin/env python
#
# v2, October 10, 2013
# by Eric Chou
#
# Reference: AX_aXAPI_Ref_v2-20121010.pdf
#
import httplib, json, urllib, urllib2, optparse
# specify device and command
parser = optparse.OptionParser()
parser.add_option('-d', '--device', dest="device", action="store")
parser.add_option('-c', '--command', dest="commandFile", action="store")
options, args = parser.parse_args()
device = options.device
commandFile = options.commandFile
# Gets the session ID to
c = httplib.HTTPSConnection(device)
c.request("GET", "/services/rest/V2/?method=authenticate&username=admin&password=a10&format=json")
response = c.getresponse()
data = json.loads(response.read())
session_id = data['session_id']
print "Session Created. Session ID: " + session_id
# Construct HTTP URL and Post Body
post_body = open(commandFile, 'r').read()
url = "https://" + device + "/services/rest/V2/?&session_id=" + session_id + "&format=json&method=cli.show_info"
print "URL Created. URL: " + url + " body: " + post_body
# Making request
req = urllib2.Request(url, post_body)
rsp = urllib2.urlopen(req)
content = rsp.read()
print "Result: " + content
A10_aXAPI$



Monday, September 30, 2013

A10 Networks aXAPI - Part 1 Introduction

I recently joined A10 Networks as Professional Services Engineer based in the Pacific Northwest. Of course, the first thing I looked for is how to use Python to automate configuration tasks on A10. A quick search shows that A10 has an aXAPI interface that utilizes REST Web services calls to make configuration changes. More information can be found here, http://www.a10networks.com/products/axseries-aXAPI.php.

Here is a quick illustration on how it works:

1. Get a session ID via HTTPS call with username and password.
2. Construct your HTTPS post body in the format specified per guide (XML or JSon supported).
3. Make POST request to the device.

Figure 1. Source http://www.a10networks.com/products/axseries-aXAPI.php.



As I was going thru some simple exercise to do some load balancing, I tried to convert that into simple Python. Basically this is what I wanted to do: 

1. Create two real servers, s1@10.0.1.128 and s2@10.0.1.129. 
2. Create a service group that binds the two real servers into a server farm. 
3. Create a virtual IP that is client facing and answers to port 80. 

Here are the corresponding Python code that maps to the steps above: 

Step 1. Get the Session ID
#!/usr/bin/env python
#
# v1, September 27, 2013
# by Eric Chou
#
# Reference: AX_aXAPI_Ref_v2-20121010.pdf
#
import httplib, json, urllib, urllib2
# Gets the session ID to host 172.31.31.121 (Student 12)
c = httplib.HTTPSConnection("172.31.31.121")
c.request("GET", "/services/rest/V2/?method=authenticate&username=admin&password=a10&format=json")
response = c.getresponse()
data = json.loads(response.read())
session_id = data['session_id']
print "Session Created. Session ID: " + session_id

Step 2. Construct the HTTP Post body

Note that I re-use the session ID because it has not timed out yet. I skip the repeated steps to create more because the only thing that is different is the HTTP body. Full script is at the end of the post. 
###############################
#  Step 1. Create Servers     #
###############################
# Create slb servers s1 10.0.2.128
# Construct HTTP URL and Post Body
post_body = json.dumps(
{"server":
         {
          "name": "s1",
          "host": "10.0.2.128",
          "health_monitor": "(default)",
          "port_list": [
           {"port_num": 80,
            "protocol": 2,}
          ],
          }  
}
)
url = "https://172.31.31.121/services/rest/V2/?&session_id=" + session_id + "&format=json&method=slb.server.create"
print "URL Created. URL: " + url + " body: " + post_body 
(repeat and rinse for all the necessary configuration tasks)

Step 3. Make the request 

# Making request
req = urllib2.Request(url, post_body)
rsp = urllib2.urlopen(req)
content = rsp.read()
print "Result: " + content

That is it! Simple, elegant, and repeatable with minimal effort. :)

Here is the device blank configuration before script: 

AX12#sh run | s slb
AX12#
AX12#

Here is the output after execution: 
>>> 
Session Created. Session ID: 69be80219842402d45f0488c52b782
URL Created. URL: https://172.31.31.121/services/rest/V2/?&session_id=69be80219842402d45f0488c52b782&format=json&method=slb.server.create body: {"server": {"host": "10.0.2.128", "name": "s1", "port_list": [{"protocol": 2, "port_num": 80}], "health_monitor": "(default)"}}
Result: {"response": {"status": "OK"}}
URL Created. URL: https://172.31.31.121/services/rest/V2/?&session_id=69be80219842402d45f0488c52b782&format=json&method=slb.server.create body: {"server": {"host": "10.0.2.129", "name": "s2", "port_list": [{"protocol": 2, "port_num": 80}], "health_monitor": "(default)"}}
Result: {"response": {"status": "OK"}}
URL Created. URL: https://172.31.31.121/services/rest/V2/?&session_id=69be80219842402d45f0488c52b782&format=json&method=slb.service_group.create body: {"service_group": {"protocol": 2, "name": "http", "member_list": [{"port": 80, "server": "s1"}, {"port": 80, "server": "s2"}], "health_monitor": "ping"}}
Result: {"response": {"status": "OK"}}
URL Created. URL: https://172.31.31.121/services/rest/V2/?&session_id=69be80219842402d45f0488c52b782&format=json&method=slb.virtual_server.create body: {"virtual_server": {"subnet": {"mask_len": 24, "address": "10.0.1.122"}, "vport_list": [{"service_group": "http", "protocol": 2, "port": 80}], "name": "vip1"}}
Result: {"response": {"status": "OK"}}
>>>

Device configuration after: 

AX12#sh run | s slb
slb server s1 10.0.2.128
   conn-limit 8000000 no-logging
   port 80  tcp
slb server s2 10.0.2.129
   conn-limit 8000000 no-logging
   port 80  tcp
slb service-group http tcp
    health-check ping
    member s1:80
    member s2:80
slb virtual-server vip1 10.0.1.122 /24
   port 80  tcp
      service-group http
AX12#

And now I can see the fantastic web page by making a request to the VIP serviced by s1: 


aXAPI is pretty cool. I will probably play with it more and post my progress here. 

Happy Coding! Leave me a comment on how you'd like to see aXAPI integration scripts. :)

Here is the full script: 

Note. As you can see, the next step to optimize would be to make the HTTP body construct a function to cut down the code. Also use multiprocess to thread would be nice too. 

#!/usr/bin/env python

#
# v1, September 27, 2013
# by Eric Chou
#
# Reference: AX_aXAPI_Ref_v2-20121010.pdf
#

import httplib, json, urllib, urllib2

# Gets the session ID to host 172.31.31.121 (Student 12)
c = httplib.HTTPSConnection("172.31.31.121")
c.request("GET", "/services/rest/V2/?method=authenticate&username=admin&password=a10&format=json")
response = c.getresponse()
data = json.loads(response.read())
session_id = data['session_id']
print "Session Created. Session ID: " + session_id

###############################
#  Step 1. Create Servers     #
###############################

# Create slb servers s1 10.0.2.128 
# Construct HTTP URL and Post Body
post_body = json.dumps(
{"server":
         {
          "name": "s1",
          "host": "10.0.2.128",
          "health_monitor": "(default)",
          "port_list": [
           {"port_num": 80,
            "protocol": 2,}
          ],
          }     
}
)
url = "https://172.31.31.121/services/rest/V2/?&session_id=" + session_id + "&format=json&method=slb.server.create"
print "URL Created. URL: " + url + " body: " + post_body 

# Making request 
req = urllib2.Request(url, post_body)
rsp = urllib2.urlopen(req)
content = rsp.read()
print "Result: " + content

# Create slb server s2 10.0.2.129
post_body = json.dumps(
{"server":
         {
          "name": "s2",
          "host": "10.0.2.129",
          "health_monitor": "(default)",
          "port_list": [
           {"port_num": 80,
            "protocol": 2,}
          ],
          }     
}
)
url = "https://172.31.31.121/services/rest/V2/?&session_id=" + session_id + "&format=json&method=slb.server.create"
print "URL Created. URL: " + url + " body: " + post_body 

# Making request 
req = urllib2.Request(url, post_body)
rsp = urllib2.urlopen(req)
content = rsp.read()
print "Result: " + content

####################################
#  Step 2. Create Service Group    #
####################################

# Create service group http with member server s1 and s2
post_body = json.dumps(
{"service_group":
         {
          "name": "http",
          "protocol": 2,
          "health_monitor": "ping",
          "member_list": [
           {"server": "s1",
            "port": 80,},
           {"server": "s2",
            "port": 80,},
          ],
          }     
}
)
url = "https://172.31.31.121/services/rest/V2/?&session_id=" + session_id + "&format=json&method=slb.service_group.create"
print "URL Created. URL: " + url + " body: " + post_body 

# Making request 
req = urllib2.Request(url, post_body)
rsp = urllib2.urlopen(req)
content = rsp.read()
print "Result: " + content

#####################################
#  Step 3. Create Virtual Server    #
#####################################

# Create virtual server
post_body = json.dumps(
{"virtual_server":
         {
          "name": "vip1",
          "subnet":
           {
            "address": "10.0.1.122",
            "mask_len": 24,
           },
          "vport_list": [
           {"protocol": 2,
            "port": 80,
            "service_group": "http",
            },
          ],
          }  
}
)
url = "https://172.31.31.121/services/rest/V2/?&session_id=" + session_id + "&format=json&method=slb.virtual_server.create"
print "URL Created. URL: " + url + " body: " + post_body 

# Making request 
req = urllib2.Request(url, post_body)
rsp = urllib2.urlopen(req)
content = rsp.read()
print "Result: " + content