Building Application Delivery Services from Templates using the REST API Part two.
In my last (horribly misspelled in earlier versions) blog post on this subject we looked at how to deploy a new application service from an iApp template using an iControl REST API call.
So far so good. Now I want to update this application service programmatically. Let’s say I’m adding a pool member, a fairly common task. I’ve got a couple of options here. I could switch off the ‘strict updates’ setting in the template, then I could use REST commands to create a new node and pool member. Then I probably want to turn the strict updates setting back on. Not too difficult, but it’s multiple calls and I’m pretty lazy.
Much better to take advantage of the fact that iApp templates are reentrant (file that word with other ones I nearly always have to look up to properly understand. See also: idempotent). What this means is I can modify the template or the values and simply redeploy the template – really only the changed values and settings are applied. I can even change the template and redeploy – but that’s beyond this simple introduction.
So, in theory, I can just make the same call again with some additional values. All I need to do is edit my original REST POST call and I should be reconfiguring my application service on the fly.
Yes and no. It turns out there are a few things I need to modify and change. The first is that I’m not using the POST method any more – POST is for new things. For modifying I need to use PUT. That’s an easy change in the Advanced REST Client.
Now, we’re also going to need to make some changes in our body too, first and most obvious is the addition of the extra pool member.
If you look back to the previous blog post we had a single pool member defined like this:
{"name":"pool__members", "columnNames":["addr","port","connection_limit"], "rows":[{"row":["10.0.0.20","80","0"]}]},
Updating this is just a matter of adding another row of values (adding the 10.0.0.31 pool member):
"{"name":"pool__members", "columnNames":["addr","port","connection_limit"], "rows":[{"row":"10.0.0.30","80","0"]},{"row":["10.0.0.31","80","0"]}]},
So far this all makes logical sense. The next change is a little more obscure. We need to add this line to the payload
"execute-action":"definition",
This is the REST equivalent of the “Finished” button. If you don’t have this line your call will execute, you will get a nice 200 OK response code, but nothing will happen. It’s kind of like telling your teenager to do something. They nod, smile and promise to get on with it, but nothing seems to actually happen. If only there was a setting for that.
So, our finished payload looks like this:
{"kind":"tm:sys:application:service:servicestate", "name":"test2", "partition":"Common", "subPath":"test2.app", "fullPath":"/Common/test2.app/test2", "generation":300,"selfLink":"https://localhost/mgmt/tm/sys/application/service/~Common~test2.app~test2?expandSubcollections=true&ver=12.0.0", "execute-action":"definition", "template":"/Common/f5.http", "templateReference":{"link":"https://localhost/mgmt/tm/sys/application/template/~Common~f5.http?ver=12.0.0"}, "templateModified":"no", "trafficGroup":"/Common/traffic-group-1", "trafficGroupReference":{"link":"https://localhost/mgmt/tm/cm/traffic-group/~Common~traffic-group-1?ver=12.0.0"}, "tables":[{"name":"basic__snatpool_members"}, {"name":"net__snatpool_members"}, {"name":"optimizations__hosts"}, {"name":"pool__hosts", "columnNames":["name"],"rows":[{"row":["test2.test.com"]}]}, {"name":"pool__members", "columnNames":["addr","port","connection_limit"], "rows":[{"row":["10.0.0.30","80","0"]}, {"row":["10.0.0.31","80","0"]}]}, {"name":"server_pools__servers"}], "variables":[{"name":"client__http_compression", "encrypted":"no", "value":"/#create_new#"}, {"name":"monitor__monitor", "encrypted":"no","value":"/#create_new#"}, {"name":"monitor__response","encrypted":"no","value":"none"}, {"name":"monitor__uri","encrypted":"no","value":"/"}, {"name":"net__client_mode","encrypted":"no","value":"wan"}, {"name":"net__server_mode","encrypted":"no","value":"lan"}, {"name":"pool__addr","encrypted":"no","value":"10.0.0.41"}, {"name":"pool__pool_to_use","encrypted":"no","value":"/#create_new#"}, {"name":"pool__port","encrypted":"no","value":"80"}, {"name":"ssl__mode","encrypted":"no","value":"no_ssl"}, {"name":"ssl_encryption_questions__advanced","encrypted":"no","value":"no"}, {"name":"ssl_encryption_questions__help","encrypted":"no","value":"hide"}]}
Before I try it, better have a ‘nothing up my sleeves’ moment. Here is the iApp Application Service before we run the command:
Now, execute the PUT call (check you get a 200 OK return).
Refresh the iApp Application Service using the cunningly named ‘Refresh’ button:
Congratulations, we have updated our pool members with a simple, one hit REST call.
Hmm, but have we sent too much? Do we actually need to redefine the rest of the values for unchanging settings? It turns out not. We could actually use just this:
{"kind":"tm:sys:application:service:servicestate", "name":"test2", "partition":"Common", "subPath":"test2.app", "fullPath":"/Common/test2.app/test2", "generation":300, "selfLink":"https://localhost/mgmt/tm/sys/application/service/~Common~test2.app~test2?expandSubcollections=true&ver=12.0.0", "execute-action":"definition", "template":"/Common/f5.http", "templateReference":{"link":"https://localhost/mgmt/tm/sys/application/template/~Common~f5.http?ver=12.0.0"}, "templateModified":"no", "trafficGroup":"/Common/traffic-group-1", "trafficGroupReference":{"link":"https://localhost/mgmt/tm/cm/traffic-group/~Common~traffic-group-1?ver=12.0.0"}, "tables":[{"name":"pool__hosts","columnNames":["name"], "rows":[{"row":["test2.test.com"]}]},{"name":"pool__members", "columnNames":["addr","port","connection_limit"], "rows":[{"row":["10.0.0.30","80","0"]},{"row":["10.0.0.31","80","0"]},{"row":["10.0.0.32","80","0"]}]},]}
What if we wanted to delete some pool members? Simple, we just remove the member’s definition from the payload:
"rows":[{"row":["10.0.0.31","80","0"]},{"row":["10.0.0.32","80","0"]}]},]}
Send the PUT command and it’s gone.
Hopefully these posts have served as a basic introduction to using REST and iApp templates. Next we might take a look at something a bit more scalable than the Advanced REST client and see how to use common tools to automate BIG-IP’s using REST and iApps. Comment below if there is a tool you would particularly like to see tested.
- sagar77_327509Nimbostratus
what URL do you use on the PUT??