Full examples of iControlREST for device and application service deployment

In a previous article, I highlighted a proof-of-concept where we fully automated the deployment of BIG-IP in AWS using the web interfaces of BIG-IP inconjunction with Ansible.  The goal of this article is to focus in more detail on the use of iControlREST within that project, in order to show how it can be extremely useful for automating various aspects of your ITOM workflows.

There are four main workflows we execute in order to configure BIG-IP in AWS and to deploy services.  This breakown is provided below.  

For now, we avoid the discussion about which configuration elements are part of the infrastructure deployment or the application deployment.  This is an important discussion, but one that can only take place after we understand how to provision the elements that will be a part of either workflow. 

For each of these workflows, we have provided the log output which shows REST calls and responses.  To gain from these examples, it is important to understand the following:

  • These iControlREST calls were scraped from an execution of the aws-deployments code where we captured log output. In that project, we have written a custom Ansible module called 'bigip_config' (see /library/bigip_config.py in the project directory of Github).  This module is used to provision config objects within TMOS using iControlREST.
  • In order to make it easier to use this 'bigip_config' Ansible module, we aimed to make it idempotent.  This means that we need only identify the resources we wish to create or update, and identify the state of the resource after our module is run.  We don't need to worry about whether the object exists when calling our module, or the procedural set of calls that should be made it order to get it there.  An example might be like: "create iApp service 'my_app' with parameters X, Y, and Z".  We don't care whether 'my_app' already exists.  In order to implement such behavior, the module internally does an HTTP GET against the resource or collection it is modifying. Subsequently, if the resource already exists, a PATCH call is made, otherwise a POST call is made. 
  • In many cases in the code, we repeat a call until it returns successfully or returns the state we are expecting.  You can see this in the examples, where the same call seems to be made repeatedly. 

Basic system configuration

  • The examples below show how we are configuring basic device settings with REST.
  • First, because BIG-IP was just started, we wait until the first iCR call, "GET mgmt/tm/sys/db", succeeds before we continue.
  • The final step the workflow involves provisioning modules on BIG-IP. Note the 30 second wait between provisioning of AVR and ASM reflected in the timestamps.
2015-11-12 09:46:03 : Disabling Setup Utility in GUI
GET mgmt/tm/sys/db ""
2015-11-12 09:46:10 : Disabling Setup Utility in GUI
GET mgmt/tm/sys/db ""
2015-11-12 09:46:17 : Disabling Setup Utility in GUI
GET mgmt/tm/sys/db ""
Method GET mgmt/tm/sys/db returned: {"kind":"tm:sys:db:dbcollectionstate","selfLink":"https://localhost/mgmt/tm/sys/db?ver=11.6.0","items":[....<a whole bunch of database variables>...]}

2015-11-12 09:46:19 : Disabling Setup Utility in GUI
PATCH mgmt/tm/sys/db/setup.run?ver=11.6.0 {"value": "false"}
Method PATCH mgmt/tm/sys/db/setup.run?ver=11.6.0 returned: {"kind":"tm:sys:db:dbstate","name":"setup.run","fullPath":"setup.run","generation":62,"selfLink":"https://localhost/mgmt/tm/sys/db/setup.run?ver=11.6.0","defaultValue":"true","scfConfig":"false","value":"false","valueRange":"false true"}

2015-11-12 09:46:22 : Configuring NTP servers
PATCH mgmt/tm/sys/ntp {"timezone": "America/Los_Angeles", "servers": ["0.pool.ntp.org", "1.pool.ntp.org"]}
Method PATCH mgmt/tm/sys/ntp returned: {"kind":"tm:sys:ntp:ntpstate","selfLink":"https://localhost/mgmt/tm/sys/ntp?ver=11.6.0","servers":["0.pool.ntp.org","1.pool.ntp.org"],"timezone":"America/Los_Angeles","restrictReference":{"link":"https://localhost/mgmt/tm/sys/ntp/restrict?ver=11.6.0","isSubcollection":true}}

2015-11-12 09:46:25 : Configuring syslog logging destinations
PATCH mgmt/tm/sys/syslog {"include": "destination loghost { udp( 10.0.3.32 port (514));};"}
Method PATCH mgmt/tm/sys/syslog returned: {"kind":"tm:sys:syslog:syslogstate","selfLink":"https://localhost/mgmt/tm/sys/syslog?ver=11.6.0","authPrivFrom":"notice","authPrivTo":"emerg","consoleLog":"enabled","cronFrom":"warning","cronTo":"emerg","daemonFrom":"notice","daemonTo":"emerg","include":"destination loghost { udp( 10.0.3.32 port (514));};","isoDate":"disabled","kernFrom":"debug","kernTo":"emerg","local6From":"notice","local6To":"emerg","mailFrom":"notice","mailTo":"emerg","messagesFrom":"notice","messagesTo":"warning","userLogFrom":"notice","userLogTo":"emerg"}

2015-11-12 09:46:28 : Configuring HTTP mgmt access
PATCH mgmt/tm/sys/httpd {"allow": ["ALL"]}
Method PATCH mgmt/tm/sys/httpd returned: {"kind":"tm:sys:httpd:httpdstate","selfLink":"https://localhost/mgmt/tm/sys/httpd?ver=11.6.0","allow":["ALL"],"authName":"BIG-IP","authPamDashboardTimeout":"off","authPamIdleTimeout":1200,"authPamValidateIp":"on","fastcgiTimeout":300,"hostnameLookup":"off","logLevel":"warn","maxClients":10,"redirectHttpToHttps":"disabled","requestBodyMaxTimeout":0,"requestBodyMinRate":500,"requestBodyTimeout":60,"requestHeaderMaxTimeout":40,"requestHeaderMinRate":500,"requestHeaderTimeout":20,"sslCertfile":"/etc/httpd/conf/ssl.crt/server.crt","sslCertkeyfile":"/etc/httpd/conf/ssl.key/server.key","sslCiphersuite":"DEFAULT:!aNULL:!eNULL:!LOW:!RC4:!MD5:!EXP","sslOcspDefaultResponder":"http://127.0.0.1","sslOcspEnable":"off","sslOcspOverrideResponder":"off","sslOcspResponderTimeout":300,"sslOcspResponseMaxAge":-1,"sslOcspResponseTimeSkew":300,"sslProtocol":"all -SSLv2 -SSLv3","sslVerifyClient":"no","sslVerifyDepth":10}

2015-11-12 09:46:31 : Configuring SSH mgmt access
PATCH mgmt/tm/sys/sshd {"allow": ["ALL"]}
Method PATCH mgmt/tm/sys/sshd returned: {"kind":"tm:sys:sshd:sshdstate","selfLink":"https://localhost/mgmt/tm/sys/sshd?ver=11.6.0","allow":["ALL"],"banner":"disabled","inactivityTimeout":0,"logLevel":"info","login":"enabled"}

2015-11-12 09:46:33 : Configuring SNMP access
PATCH mgmt/tm/sys/snmp {"allowedAddresses": ["172.16.0.0/16"]}
Method PATCH mgmt/tm/sys/snmp returned: {"kind":"tm:sys:snmp:snmpstate","selfLink":"https://localhost/mgmt/tm/sys/snmp?ver=11.6.0","agentAddresses":["tcp6:161","udp6:161"],"agentTrap":"enabled","allowedAddresses":["172.16.0.0/16"],"authTrap":"disabled","bigipTraps":"enabled","l2forwardVlan":"none","loadMax1":12,"loadMax15":12,"loadMax5":12,"sysContact":"Customer Name <admin@customer.com>","sysLocation":"Network Closet 1","sysServices":78,"trapCommunity":"public","trapSource":"none","communitiesReference":{"link":"https://localhost/mgmt/tm/sys/snmp/communities?ver=11.6.0","isSubcollection":true},"diskMonitors":[{"name":"root","partition":"Common","minspace":2000,"minspaceType":"size","path":"/"},{"name":"var","partition":"Common","minspace":10000,"minspaceType":"size","path":"/var"}],"processMonitors":[{"name":"bigd","partition":"Common","maxProcesses":"1","minProcesses":1,"process":"bigd"},{"name":"chmand","partition":"Common","maxProcesses":"1","minProcesses":1,"process":"chmand"},{"name":"httpd","partition":"Common","maxProcesses":"infinity","minProcesses":1,"process":"httpd"},{"name":"mcpd","partition":"Common","maxProcesses":"1","minProcesses":1,"process":"mcpd"},{"name":"sod","partition":"Common","maxProcesses":"1","minProcesses":1,"process":"sod"},{"name":"tmm","partition":"Common","maxProcesses":"infinity","minProcesses":1,"process":"tmm"}],"trapsReference":{"link":"https://localhost/mgmt/tm/sys/snmp/traps?ver=11.6.0","isSubcollection":true},"usersReference":{"link":"https://localhost/mgmt/tm/sys/snmp/users?ver=11.6.0","isSubcollection":true}}

2015-11-12 09:46:36 : Configuring FastL4 profiles ... fastL4-route-friendly
GET mgmt/tm/ltm/profile/fastl4 ""
Method GET mgmt/tm/ltm/profile/fastl4 returned: {"kind":"tm:ltm:profile:fastl4:fastl4collectionstate","selfLink":"https://localhost/mgmt/tm/ltm/profile/fastl4?ver=11.6.0","items":[{"kind":"tm:ltm:profile:fastl4:fastl4state","name":"fastL4","partition":"Common","fullPath":"/Common/fastL4","generation":1,"selfLink":"https://localhost/mgmt/tm/ltm/profile/fastl4/~Common~fastL4?ver=11.6.0","clientTimeout":30,"explicitFlowMigration":"disabled","hardwareSynCookie":"enabled","idleTimeout":"300","ipTosToClient":"pass-through","ipTosToServer":"pass-through","keepAliveInterval":"disabled","lateBinding":"disabled","linkQosToClient":"pass-through","linkQosToServer":"pass-through","looseClose":"disabled","looseInitialization":"disabled","mssOverride":0,"priorityToClient":"pass-through","priorityToServer":"pass-through","pvaAcceleration":"full","pvaDynamicClientPackets":1,"pvaDynamicServerPackets":0,"pvaFlowAging":"enabled","pvaFlowEvict":"enabled","pvaOffloadDynamic":"enabled","pvaOffloadState":"embryonic","reassembleFragments":"disabled","receiveWindowSize":0,"resetOnTimeout":"enabled","rttFromClient":"disabled","rttFromServer":"disabled","serverSack":"disabled","serverTimestamp":"disabled","softwareSynCookie":"disabled","synCookieWhitelist":"disabled","tcpCloseTimeout":"5","tcpGenerateIsn":"disabled","tcpHandshakeTimeout":"5","tcpStripSack":"disabled","tcpTimestampMode":"preserve","tcpWscaleMode":"preserve","timeoutRecovery":"disconnect"}]}

2015-11-12 09:46:37 : Configuring FastL4 profiles ... fastL4-route-friendly
POST mgmt/tm/ltm/profile/fastl4 {"looseClose": "enabled", "resetOnTimeout": "disabled", "name": "fastL4-route-friendly", "looseInitialization": "enabled"}
Method POST mgmt/tm/ltm/profile/fastl4 returned: {"kind":"tm:ltm:profile:fastl4:fastl4state","name":"fastL4-route-friendly","fullPath":"fastL4-route-friendly","generation":68,"selfLink":"https://localhost/mgmt/tm/ltm/profile/fastl4/fastL4-route-friendly?ver=11.6.0","clientTimeout":30,"defaultsFrom":"/Common/fastL4","explicitFlowMigration":"disabled","hardwareSynCookie":"enabled","idleTimeout":"300","ipTosToClient":"pass-through","ipTosToServer":"pass-through","keepAliveInterval":"disabled","lateBinding":"disabled","linkQosToClient":"pass-through","linkQosToServer":"pass-through","looseClose":"enabled","looseInitialization":"enabled","mssOverride":0,"priorityToClient":"pass-through","priorityToServer":"pass-through","pvaAcceleration":"full","pvaDynamicClientPackets":1,"pvaDynamicServerPackets":0,"pvaFlowAging":"enabled","pvaFlowEvict":"enabled","pvaOffloadDynamic":"enabled","pvaOffloadState":"embryonic","reassembleFragments":"disabled","receiveWindowSize":0,"resetOnTimeout":"disabled","rttFromClient":"disabled","rttFromServer":"disabled","serverSack":"disabled","serverTimestamp":"disabled","softwareSynCookie":"disabled","synCookieWhitelist":"disabled","tcpCloseTimeout":"5","tcpGenerateIsn":"disabled","tcpHandshakeTimeout":"5","tcpStripSack":"disabled","tcpTimestampMode":"preserve","tcpWscaleMode":"preserve","timeoutRecovery":"disconnect"}

...

2015-11-12 09:46:44 :
PATCH mgmt/tm/sys/provision/asm {"level": "nominal"}
Method PATCH mgmt/tm/sys/provision/asm returned: {"kind":"tm:sys:provision:provisionstate","name":"asm","fullPath":"asm","generation":71,"selfLink":"https://localhost/mgmt/tm/sys/provision/asm?ver=11.6.0","cpuRatio":0,"diskRatio":0,"level":"nominal","memoryRatio":0}

2015-11-12 09:47:18 :
PATCH mgmt/tm/sys/provision/avr {"level": "nominal"}
Method PATCH mgmt/tm/sys/provision/avr returned: {"kind":"tm:sys:provision:provisionstate","name":"avr","fullPath":"avr","generation":114,"selfLink":"https://localhost/mgmt/tm/sys/provision/avr?ver=11.6.0","cpuRatio":0,"diskRatio":0,"level":"nominal","memoryRatio":0}

AWS-specific System Configuration

  • This next workflow is very small and simple.  We are adding some variables to global-settings which are only necessary because BIG-IP is running in AWS. 
  • We've obfuscated the AWS Access Key and Secret Key in the output. 
2015-11-12 09:48:12 : Adding/updating AWS access and secret keys
PATCH mgmt/tm/sys/global-settings {"awsAccessKey": "...<my access key>...", "awsSecretKey": "...<my secret key>..."}
Method PATCH mgmt/tm/sys/global-settings returned: {"kind":"tm:sys:global-settings:global-settingsstate","selfLink":"https://localhost/mgmt/tm/sys/global-settings?ver=11.6.0","awsAccessKey":"...<my access key>...","awsApiMaxConcurrency":1,"awsSecretKey":"...<my secret key>...","consoleInactivityTimeout":0,"customAddr":"none","failsafeAction":"go-offline-restart-tm","fileLocalPathPrefix":"{/shared/} {/tmp/}","guiSecurityBanner":"enabled","guiSecurityBannerText":"Welcome to the BIG-IP Configuration Utility.\n\nLog in with your username and password using the fields on the left.","guiSetup":"disabled","hostAddrMode":"management","hostname":"ip-172-16-11-77.ec2.internal","lcdDisplay":"enabled","mgmtDhcp":"enabled","netReboot":"disabled","passwordPrompt":"Password","quietBoot":"enabled","usernamePrompt":"Username"}

Network Attachment

  • Setup of self-IPs, VLANs, and other network specific configuration is relatively straight forward. 
2015-11-12 09:48:15 : Disabling dhcp
PATCH mgmt/tm/sys/db/dhclient.mgmt {"value": "disable"}
Method PATCH mgmt/tm/sys/db/dhclient.mgmt returned: {"kind":"tm:sys:db:dbstate","name":"dhclient.mgmt","fullPath":"dhclient.mgmt","generation":154,"selfLink":"https://localhost/mgmt/tm/sys/db/dhclient.mgmt?ver=11.6.0","defaultValue":"disable","scfConfig":"true","value":"disable","valueRange":"disable enable"}

2015-11-12 09:48:18 : Adding/updating internal vlan
GET mgmt/tm/net/vlan ""
Method GET mgmt/tm/net/vlan returned: {"kind":"tm:net:vlan:vlancollectionstate","selfLink":"https://localhost/mgmt/tm/net/vlan?ver=11.6.0"}

2015-11-12 09:48:19 : Adding/updating internal vlan
POST mgmt/tm/net/vlan {"interfaces": "1.2", "name": "private"}
Method POST mgmt/tm/net/vlan returned: {"kind":"tm:net:vlan:vlanstate","name":"private","fullPath":"private","generation":167,"selfLink":"https://localhost/mgmt/tm/net/vlan/private?ver=11.6.0","autoLasthop":"default","cmpHash":"default","dagRoundRobin":"disabled","dagTunnel":"outer","failsafe":"disabled","failsafeAction":"failover-restart-tm","failsafeTimeout":90,"ifIndex":80,"learning":"enable-forward","mtu":1500,"sflow":{"pollInterval":0,"pollIntervalGlobal":"yes","samplingRate":0,"samplingRateGlobal":"yes"},"sourceChecking":"disabled","tag":4094,"interfacesReference":{"link":"https://localhost/mgmt/tm/net/vlan/~Common~private/interfaces?ver=11.6.0","isSubcollection":true}}

2015-11-12 09:48:21 : Adding/updating external vlan
GET mgmt/tm/net/vlan ""
Method GET mgmt/tm/net/vlan returned: {"kind":"tm:net:vlan:vlancollectionstate","selfLink":"https://localhost/mgmt/tm/net/vlan?ver=11.6.0","items":[{"kind":"tm:net:vlan:vlanstate","name":"private","partition":"Common","fullPath":"/Common/private","generation":167,"selfLink":"https://localhost/mgmt/tm/net/vlan/~Common~private?ver=11.6.0","autoLasthop":"default","cmpHash":"default","dagRoundRobin":"disabled","dagTunnel":"outer","failsafe":"disabled","failsafeAction":"failover-restart-tm","failsafeTimeout":90,"ifIndex":80,"learning":"enable-forward","mtu":1500,"sflow":{"pollInterval":0,"pollIntervalGlobal":"yes","samplingRate":0,"samplingRateGlobal":"yes"},"sourceChecking":"disabled","tag":4094,"interfacesReference":{"link":"https://localhost/mgmt/tm/net/vlan/~Common~private/interfaces?ver=11.6.0","isSubcollection":true}}]}

...

2015-11-12 09:48:24 : Adding/updating internal selfip
GET mgmt/tm/net/self ""
Method GET mgmt/tm/net/self returned: {"kind":"tm:net:self:selfcollectionstate","selfLink":"https://localhost/mgmt/tm/net/self?ver=11.6.0"}

2015-11-12 09:48:24 : Adding/updating internal selfip
POST mgmt/tm/net/self {"allowService": "default", "vlan": "private", "trafficGroup": "traffic-group-local-only", "name": "private", "address": "172.16.12.44/24"}
Method POST mgmt/tm/net/self returned: {"kind":"tm:net:self:selfstate","name":"private","fullPath":"private","generation":177,"selfLink":"https://localhost/mgmt/tm/net/self/private?ver=11.6.0","address":"172.16.12.44/24","floating":"disabled","inheritedTrafficGroup":"false","trafficGroup":"/Common/traffic-group-local-only","unit":0,"vlan":"/Common/private","allowService":["default"]}

2015-11-12 09:48:26 : Adding/updating external selfip
GET mgmt/tm/net/self ""
Method GET mgmt/tm/net/self returned: {"kind":"tm:net:self:selfcollectionstate","selfLink":"https://localhost/mgmt/tm/net/self?ver=11.6.0","items":[{"kind":"tm:net:self:selfstate","name":"private","partition":"Common","fullPath":"/Common/private","generation":177,"selfLink":"https://localhost/mgmt/tm/net/self/~Common~private?ver=11.6.0","address":"172.16.12.44/24","floating":"disabled","inheritedTrafficGroup":"false","trafficGroup":"/Common/traffic-group-local-only","unit":0,"vlan":"/Common/private","allowService":["default"]}]}

2015-11-12 09:48:27 : Adding/updating external selfip
POST mgmt/tm/net/self {"allowService": ["tcp:4353"], "vlan": "public", "trafficGroup": "traffic-group-local-only", "name": "public", "address": "172.16.13.83/24"}
Method POST mgmt/tm/net/self returned: {"kind":"tm:net:self:selfstate","name":"public","fullPath":"public","generation":178,"selfLink":"https://localhost/mgmt/tm/net/self/public?ver=11.6.0","address":"172.16.13.83/24","floating":"disabled","inheritedTrafficGroup":"false","trafficGroup":"/Common/traffic-group-local-only","unit":0,"vlan":"/Common/public","allowService":["tcp:4353"]}

2015-11-12 09:48:29 : Setting default route using default_gateway or gateway_pool
GET /mgmt/tm/net/route ""
Method GET /mgmt/tm/net/route returned: {"kind":"tm:net:route:routecollectionstate","selfLink":"https://localhost/mgmt/tm/net/route?ver=11.6.0"}

2015-11-12 09:48:29 : Setting default route using default_gateway or gateway_pool
POST /mgmt/tm/net/route {"gw": "172.16.13.1", "name": "default_route", "network": "default"}
Method POST /mgmt/tm/net/route returned: {"kind":"tm:net:route:routestate","name":"default_route","fullPath":"default_route","generation":0,"selfLink":"https://localhost/mgmt/tm/net/route/default_route?ver=11.6.0"}

Application Service Provisioning

This workflow is where things really get interesting.  Let's break it down.

  • We are deploying two sets of virtual servers (the pool members are the same, but the VIP is different). 
  • For virtual 1 (VIP = 172.16.13.128), we use an iApp to deploy a HTTPS virtual with an ASM policy. To do so, we:
    • Deploy all resources that are needed to support the iApp deployment:
      • ​A high-speed logging pool
      • An LTM logging profile (which will send logs to Splunk on port 514)
      • An ASM logging profile (which will send logs to Splunk on port 515)
      • An analytics profile, in case we want to inspect traffic with AVR on-box
      • Base64 encoded images to an iRule data-group
      • iRules to support a sorry page and the analytics profile
      • An ASM policy (we've encoded the XML policy file into base64). Deploying the ASM policies requires first making a new policy via a POST command, then importing the policy over the defaults for the one we have just created. 
        • ​Note that we check the status of the asynchronous REST tasks which are started during the policy 'create' and 'apply' steps. 
      • An LTM policy which attaches the ASM policy above using a ruleset. 
    • Deploy the iApp template (look here to understand how we built the JSON payload for the iApp template). 
    • Finally, deploy the iApp service, an instantiation of the template that references all the above content (look here to understand how we built the JSON payload for the iApp service). 
  • For virtual 2 (VIP = 172.16.13.124), just deploy the web server pool, iRule, and virtual server directly (without an iApp).

2015-11-12 09:49:13 : Deploying/updating Webserver Pool
GET mgmt/tm/ltm/pool ""
Method GET mgmt/tm/ltm/pool returned: {"kind":"tm:ltm:pool:poolcollectionstate","selfLink":"https://localhost/mgmt/tm/ltm/pool?ver=11.6.0"}

2015-11-12 09:49:14 : Deploying/updating Webserver Pool
POST mgmt/tm/ltm/pool {"name": "Vip1_pool", "members": [{"description": "Name=/boring_lovelace,ContainerHostname=a0085832ad28,Image=mutzel/all-in-one-hackazon:postinstall", "name": "172.16.14.87:80", "address": "172.16.14.87"}], "monitor": "http"}
Method POST mgmt/tm/ltm/pool returned: {"kind":"tm:ltm:pool:poolstate","name":"Vip1_pool","fullPath":"Vip1_pool","generation":236,"selfLink":"https://localhost/mgmt/tm/ltm/pool/Vip1_pool?ver=11.6.0","allowNat":"yes","allowSnat":"yes","ignorePersistedWeight":"disabled","ipTosToClient":"pass-through","ipTosToServer":"pass-through","linkQosToClient":"pass-through","linkQosToServer":"pass-through","loadBalancingMode":"round-robin","minActiveMembers":0,"minUpMembers":0,"minUpMembersAction":"failover","minUpMembersChecking":"disabled","monitor":"/Common/http ","queueDepthLimit":0,"queueOnConnectionLimit":"disabled","queueTimeLimit":0,"reselectTries":0,"serviceDownAction":"none","slowRampTime":10,"membersReference":{"link":"https://localhost/mgmt/tm/ltm/pool/~Common~Vip1_pool/members?ver=11.6.0","isSubcollection":true}}

2015-11-12 09:49:18 : Deploying/updating High Speed Logging pool to send to Analytics Server
GET mgmt/tm/ltm/pool ""
Method GET mgmt/tm/ltm/pool returned: {"kind":"tm:ltm:pool:poolcollectionstate","selfLink":"https://localhost/mgmt/tm/ltm/pool?ver=11.6.0","items":[{"kind":"tm:ltm:pool:poolstate","name":"Vip1_pool","partition":"Common","fullPath":"/Common/Vip1_pool","generation":236,"selfLink":"https://localhost/mgmt/tm/ltm/pool/~Common~Vip1_pool?ver=11.6.0","allowNat":"yes","allowSnat":"yes","ignorePersistedWeight":"disabled","ipTosToClient":"pass-through","ipTosToServer":"pass-through","linkQosToClient":"pass-through","linkQosToServer":"pass-through","loadBalancingMode":"round-robin","minActiveMembers":0,"minUpMembers":0,"minUpMembersAction":"failover","minUpMembersChecking":"disabled","monitor":"/Common/http ","queueDepthLimit":0,"queueOnConnectionLimit":"disabled","queueTimeLimit":0,"reselectTries":0,"serviceDownAction":"none","slowRampTime":10,"membersReference":{"link":"https://localhost/mgmt/tm/ltm/pool/~Common~Vip1_pool/members?ver=11.6.0","isSubcollection":true}}]}

2015-11-12 09:49:19 : Deploying/updating High Speed Logging pool to send to Analytics Server
POST mgmt/tm/ltm/pool {"name": "syslog_pool", "members": [{"name": "172.16.14.180:514", "address": "172.16.14.180"}], "monitor": "tcp"}
Method POST mgmt/tm/ltm/pool returned: {"kind":"tm:ltm:pool:poolstate","name":"syslog_pool","fullPath":"syslog_pool","generation":239,"selfLink":"https://localhost/mgmt/tm/ltm/pool/syslog_pool?ver=11.6.0","allowNat":"yes","allowSnat":"yes","ignorePersistedWeight":"disabled","ipTosToClient":"pass-through","ipTosToServer":"pass-through","linkQosToClient":"pass-through","linkQosToServer":"pass-through","loadBalancingMode":"round-robin","minActiveMembers":0,"minUpMembers":0,"minUpMembersAction":"failover","minUpMembersChecking":"disabled","monitor":"/Common/tcp ","queueDepthLimit":0,"queueOnConnectionLimit":"disabled","queueTimeLimit":0,"reselectTries":0,"serviceDownAction":"none","slowRampTime":10,"membersReference":{"link":"https://localhost/mgmt/tm/ltm/pool/~Common~syslog_pool/members?ver=11.6.0","isSubcollection":true}}

...

2015-11-12 09:49:21 : Deploying/updating ASM Logging Profile to send to Remote Analytics Server
POST mgmt/tm/security/log/profile {"application": [{"guaranteeLogging": "enabled", "guaranteeResponseLogging": "disabled", "logicOperation": "or", "protocol": "tcp", "name": "asm_log_to_splunk", "format": {"fieldDelimiter": ",", "type": "predefined"}, "reportAnomalies": "disabled", "facility": "local0", "partition": "Common", "filter": [{"values": ["all"], "name": "protocol"}, {"values": ["all"], "name": "request-type"}, {"name": "search-all"}], "maximumHeaderSize": "any", "localStorage": "enabled", "maximumQuerySize": "any", "maximumEntryLength": "2k", "servers": [{"name": "172.16.14.180:515"}], "remoteStorage": "splunk", "maximumRequestSize": "any", "responseLogging": "none"}], "name": "asm_log_to_splunk"}
Method POST mgmt/tm/security/log/profile returned: {"kind":"tm:security:log:profile:profilestate","name":"asm_log_to_splunk","fullPath":"asm_log_to_splunk","generation":240,"selfLink":"https://localhost/mgmt/tm/security/log/profile/asm_log_to_splunk?ver=11.6.0","applicationReference":{"link":"https://localhost/mgmt/tm/security/log/profile/~Common~asm_log_to_splunk/application?ver=11.6.0","isSubcollection":true}}

2015-11-12 09:49:23 : Deploying/updating Analytics Profile
GET mgmt/tm/ltm/profile/analytics ""
Method GET mgmt/tm/ltm/profile/analytics returned: {"kind":"tm:ltm:profile:analytics:analyticscollectionstate","selfLink":"https://localhost/mgmt/tm/ltm/profile/analytics?ver=11.6.0","items":[{"kind":"tm:ltm:profile:analytics:analyticsstate","name":"analytics","partition":"Common","fullPath":"/Common/analytics","generation":1,"selfLink":"https://localhost/mgmt/tm/ltm/profile/analytics/~Common~analytics?ver=11.6.0","capturedTrafficExternalLogging":"disabled","capturedTrafficInternalLogging":"disabled","collectGeo":"disabled","collectIp":"disabled","collectMaxTpsAndThroughput":"disabled","collectMethods":"enabled","collectPageLoadTime":"disabled","collectResponseCodes":"enabled","collectSubnets":"disabled","collectUrl":"disabled","collectUserAgent":"disabled","collectUserSessions":"disabled","collectedStatsExternalLogging":"disabled","collectedStatsInternalLogging":"enabled","notificationByEmail":"disabled","notificationBySnmp":"disabled","notificationBySyslog":"disabled","publishIruleStatistics":"disabled","sampling":"enabled","sessionCookieSecurity":"ssl-only","sessionTimeoutMinutes":"5","alertsReference":{"link":"https://localhost/mgmt/tm/ltm/profile/analytics/~Common~analytics/alerts?ver=11.6.0","isSubcollection":true},"trafficCaptureReference":{"link":"https://localhost/mgmt/tm/ltm/profile/analytics/~Common~analytics/traffic-capture?ver=11.6.0","isSubcollection":true}}]}

...

2015-11-12 09:49:26 : Uploading Datagroup ... background for sorry page
GET mgmt/tm/ltm/data-group/internal ""
Method GET mgmt/tm/ltm/data-group/internal returned: {"kind":"tm:ltm:data-group:internal:internalcollectionstate","selfLink":"https://localhost/mgmt/tm/ltm/data-group/internal?ver=11.6.0","items":[{"kind":"tm:ltm:data-group:internal:internalstate","name":"aol","partition":"Common","fullPath":"/Common/aol","generation":1,"selfLink":"https://localhost/mgmt/tm/ltm/data-group/internal/~Common~aol?ver=11.6.0","type":"ip","records":[{"name":"64.12.96.0/19"},{"name":"195.93.16.0/20"},{"name":"195.93.48.0/22"},{"name":"195.93.64.0/19"},{"name":"195.93.96.0/19"},{"name":"198.81.0.0/22"},{"name":"198.81.8.0/23"},{"name":"198.81.16.0/20"},{"name":"202.67.65.128/25"},{"name":"205.188.112.0/20"},{"name":"205.188.146.144/30"},{"name":"205.188.192.0/20"},{"name":"205.188.208.0/23"},{"name":"207.200.112.0/21"}]},{"kind":"tm:ltm:data-group:internal:internalstate","name":"images","partition":"Common","fullPath":"/Common/images","generation":1,"selfLink":"https://localhost/mgmt/tm/ltm/data-group/internal/~Common~images?ver=11.6.0","type":"string","records":[{"name":".bmp"},{"name":".gif"},{"name":".jpg"}]},{"kind":"tm:ltm:data-group:internal:internalstate","name":"private_net","partition":"Common","fullPath":"/Common/private_net","generation":1,"selfLink":"https://localhost/mgmt/tm/ltm/data-group/internal/~Common~private_net?ver=11.6.0","type":"ip","records":[{"name":"10.0.0.0/8"},{"name":"172.16.0.0/12"},{"name":"192.168.0.0/16"}]}]}

2015-11-12 09:49:26 : Uploading Datagroup ... background for sorry page
POST mgmt/tm/ltm/data-group/internal {"records": [{"name": "...<base64 image>..."}], "type": "string", "name": "background_images"}
Method POST mgmt/tm/ltm/data-group/internal returned: {"kind":"tm:ltm:data-group:internal:internalstate","name":"background_images","fullPath":"background_images","generation":244,"selfLink":"https://localhost/mgmt/tm/ltm/data-group/internal/background_images?ver=11.6.0","type":"string","records":[{"name":"....large base64 image...."}]}

2015-11-12 09:49:29 : Uploading Datagroup ... image for sorry page
GET mgmt/tm/ltm/data-group/internal ""
Method GET mgmt/tm/ltm/data-group/internal returned: {"kind":"tm:ltm:data-group:internal:internalcollectionstate","selfLink":"https://localhost/mgmt/tm/ltm/data-group/internal?ver=11.6.0","items":[{"kind":"tm:ltm:data-group:internal:internalstate","name":"aol","partition":"Common","fullPath":"/Common/aol","generation":1,"selfLink":"https://localhost/mgmt/tm/ltm/data-group/internal/~Common~aol?ver=11.6.0","type":"ip","records":[{"name":"64.12.96.0/19"},{"name":"195.93.16.0/20"},{"name":"195.93.48.0/22"},{"name":"195.93.64.0/19"},{"name":"195.93.96.0/19"},{"name":"198.81.0.0/22"},{"name":"198.81.8.0/23"},{"name":"198.81.16.0/20"},{"name":"202.67.65.128/25"},{"name":"205.188.112.0/20"},{"name":"205.188.146.144/30"},{"name":"205.188.192.0/20"},{"name":"205.188.208.0/23"},{"name":"207.200.112.0/21"}]},{"kind":"tm:ltm:data-group:internal:internalstate","name":"background_images","partition":"Common","fullPath":"/Common/background_images","generation":244,"selfLink":"https://localhost/mgmt/tm/ltm/data-group/internal/~Common~background_images?ver=11.6.0","type":"string","records":[{"name":"...<base64 image>..."}]},{"kind":"tm:ltm:data-group:internal:internalstate","name":"images","partition":"Common","fullPath":"/Common/images","generation":1,"selfLink":"https://localhost/mgmt/tm/ltm/data-group/internal/~Common~images?ver=11.6.0","type":"string","records":[{"name":".bmp"},{"name":".gif"},{"name":".jpg"}]},{"kind":"tm:ltm:data-group:internal:internalstate","name":"private_net","partition":"Common","fullPath":"/Common/private_net","generation":1,"selfLink":"https://localhost/mgmt/tm/ltm/data-group/internal/~Common~private_net?ver=11.6.0","type":"ip","records":[{"name":"10.0.0.0/8"},{"name":"172.16.0.0/12"},{"name":"192.168.0.0/16"}]}]}

2015-11-12 09:49:30 : Uploading Datagroup ... image for sorry page
POST mgmt/tm/ltm/data-group/internal {"records": [{"name": "...<base64 image>..."}], "type": "string", "name": "sorry_images"}
Method POST mgmt/tm/ltm/data-group/internal returned: {"kind":"tm:ltm:data-group:internal:internalstate","name":"sorry_images","fullPath":"sorry_images","generation":245,"selfLink":"https://localhost/mgmt/tm/ltm/data-group/internal/sorry_images?ver=11.6.0","type":"string","records":[{"name":"....base 64 image...."}]}

2015-11-12 09:49:32 : Uploading iRules ... sorry_page_rule
GET mgmt/tm/ltm/rule ""
Method GET mgmt/tm/ltm/rule returned: {"kind":"tm:ltm:rule:rulecollectionstate","selfLink":"https://localhost/mgmt/tm/ltm/rule?ver=11.6.0","items":[<a whole bunch of irules>]}

2015-11-12 09:49:35 : Uploading iRules ... demo_analytics_rule
GET mgmt/tm/ltm/rule ""
Method GET mgmt/tm/ltm/rule returned: {"kind":"tm:ltm:rule:rulecollectionstate","selfLink":"https://localhost/mgmt/tm/ltm/rule?ver=11.6.0","items":[<a whole bunnch of irules>]}

2015-11-12 09:49:38 : Create the ASM policy
GET mgmt/tm/asm/policies ""
Method GET mgmt/tm/asm/policies returned: {"selfLink":"https://localhost/mgmt/tm/asm/policies","kind":"tm:asm:policies:policycollectionstate","totalItems":0,"items":[]}

2015-11-12 09:49:39 : Create the ASM policy
POST mgmt/tm/asm/policies {"caseInsensitive": true, "name": "linux_high-Vip1", "applicationLanguage": "utf-8"}
...

2015-11-12 09:49:53 : Import our policy over the one existing above
POST mgmt/tm/asm/tasks/import-policy {"policyReference": {"link": "https://localhost/mgmt/tm/asm/policies/qnU5A8PUMuPurLRLUt8VHg"}, "isBase64": true, "file": "...<base64 policy file>...","lastUpdateMicros":1.447350597e+15,"selfLink":"https://localhost/mgmt/tm/asm/tasks/import-policy/hP37L9EM650WeWKkgX7law","kind":"tm:asm:tasks:import-policy:import-policy-taskstate","policyReference":{"link":"https://localhost/mgmt/tm/asm/policies/qnU5A8PUMuPurLRLUt8VHg"},"startTime":"2015-11-12T17:49:57Z","id":"hP37L9EM650WeWKkgX7law"}

2015-11-12 09:50:00 : Determine whether the asm policy import task is complete
GET mgmt/tm/asm/tasks/import-policy/hP37L9EM650WeWKkgX7law ""
Method GET mgmt/tm/asm/tasks/import-policy/hP37L9EM650WeWKkgX7law returned: {"isBase64":true,"status":"STARTED","file":"...<base64 policy file>...","lastUpdateMicros":1.447350597e+15,"selfLink":"https://localhost/mgmt/tm/asm/tasks/import-policy/hP37L9EM650WeWKkgX7law","kind":"tm:asm:tasks:import-policy:import-policy-taskstate","policyReference":{"link":"https://localhost/mgmt/tm/asm/policies/qnU5A8PUMuPurLRLUt8VHg"},"startTime":"2015-11-12T17:49:57Z","id":"hP37L9EM650WeWKkgX7law"}

2015-11-12 09:50:05 : Determine whether the asm policy import task is complete
GET mgmt/tm/asm/tasks/import-policy/hP37L9EM650WeWKkgX7law ""
Method GET mgmt/tm/asm/tasks/import-policy/hP37L9EM650WeWKkgX7law returned: {"isBase64":true,"status":"COMPLETED","file":"...<base64 policy file>...","lastUpdateMicros":1.447350605e+15,"selfLink":"https://localhost/mgmt/tm/asm/tasks/import-policy/hP37L9EM650WeWKkgX7law","kind":"tm:asm:tasks:import-policy:import-policy-taskstate","policyReference":{"link":"https://localhost/mgmt/tm/asm/policies/qnU5A8PUMuPurLRLUt8VHg"},"endTime":"2015-11-12T17:50:05Z","startTime":"2015-11-12T17:49:57Z","id":"hP37L9EM650WeWKkgX7law","result":{"policyReference":{"link":"https://localhost/mgmt/tm/asm/policies/qnU5A8PUMuPurLRLUt8VHg"},"message":"Security policy version information will be ignored, since the file has been modified since it was exported.\nSignature Set linux-high (previously used in this security policy) was added to this system.\nThe operation was completed successfully. The security policy name is '/Common/linux_high-Vip1'."}}

2015-11-12 09:50:08 : Apply the ASM policy
POST mgmt/tm/asm/tasks/apply-policy {"policyReference": {"link": "https://localhost/mgmt/tm/asm/policies/qnU5A8PUMuPurLRLUt8VHg"}}
Method POST mgmt/tm/asm/tasks/apply-policy returned: {"selfLink":"https://localhost/mgmt/tm/asm/tasks/apply-policy/38B8slfPm1_lBBRG1STNeg","kind":"tm:asm:tasks:apply-policy:apply-policy-taskstate","policyReference":{"link":"https://localhost/mgmt/tm/asm/policies/qnU5A8PUMuPurLRLUt8VHg"},"status":"NEW","lastUpdateMicros":1.447350608e+15,"startTime":"2015-11-12T17:50:08Z","id":"38B8slfPm1_lBBRG1STNeg"}

2015-11-12 09:50:10 : Determine whether the asm policy apply task is complete
GET mgmt/tm/asm/tasks/apply-policy/38B8slfPm1_lBBRG1STNeg ""
Method GET mgmt/tm/asm/tasks/apply-policy/38B8slfPm1_lBBRG1STNeg returned: {"selfLink":"https://localhost/mgmt/tm/asm/tasks/apply-policy/38B8slfPm1_lBBRG1STNeg","kind":"tm:asm:tasks:apply-policy:apply-policy-taskstate","policyReference":{"link":"https://localhost/mgmt/tm/asm/policies/qnU5A8PUMuPurLRLUt8VHg"},"status":"STARTED","lastUpdateMicros":1.447350608e+15,"startTime":"2015-11-12T17:50:08Z","id":"38B8slfPm1_lBBRG1STNeg"}

2015-11-12 09:50:14 : Determine whether the asm policy apply task is complete
GET mgmt/tm/asm/tasks/apply-policy/38B8slfPm1_lBBRG1STNeg ""
Method GET mgmt/tm/asm/tasks/apply-policy/38B8slfPm1_lBBRG1STNeg returned: {"selfLink":"https://localhost/mgmt/tm/asm/tasks/apply-policy/38B8slfPm1_lBBRG1STNeg","kind":"tm:asm:tasks:apply-policy:apply-policy-taskstate","policyReference":{"link":"https://localhost/mgmt/tm/asm/policies/qnU5A8PUMuPurLRLUt8VHg"},"status":"STARTED","lastUpdateMicros":1.447350608e+15,"startTime":"2015-11-12T17:50:08Z","id":"38B8slfPm1_lBBRG1STNeg"}

2015-11-12 09:50:20 : Create an LTM policy for use with by iApp which associates the ASM policy
GET mgmt/tm/ltm/policy ""
Method GET mgmt/tm/ltm/policy returned: {"kind":"tm:ltm:policy:policycollectionstate","selfLink":"https://localhost/mgmt/tm/ltm/policy?ver=11.6.0","items":[{"kind":"tm:ltm:policy:policystate","name":"_sys_CEC_SSL_client_policy","partition":"Common","fullPath":"/Common/_sys_CEC_SSL_client_policy","generation":1,"selfLink":"https://localhost/mgmt/tm/ltm/policy/~Common~_sys_CEC_SSL_client_policy?ver=11.6.0","controls":["classification"],"hints":["no-write","no-delete","no-exclusion"],"requires":["ssl-persistence"],"strategy":"/Common/first-match","rulesReference":{"link":"https://localhost/mgmt/tm/ltm/policy/~Common~_sys_CEC_SSL_client_policy/rules?ver=11.6.0","isSubcollection":true}},{"kind":"tm:ltm:policy:policystate","name":"_sys_CEC_SSL_server_policy","partition":"Common","fullPath":"/Common/_sys_CEC_SSL_server_policy","generation":1,"selfLink":"https://localhost/mgmt/tm/ltm/policy/~Common~_sys_CEC_SSL_server_policy?ver=11.6.0","controls":["classification"],"hints":["no-write","no-delete","no-exclusion"],"requires":["ssl-persistence"],"strategy":"/Common/first-match","rulesReference":{"link":"https://localhost/mgmt/tm/ltm/policy/~Common~_sys_CEC_SSL_server_policy/rules?ver=11.6.0","isSubcollection":true}},{"kind":"tm:ltm:policy:policystate","name":"_sys_CEC_video_policy","partition":"Common","fullPath":"/Common/_sys_CEC_video_policy","generation":1,"selfLink":"https://localhost/mgmt/tm/ltm/policy/~Common~_sys_CEC_video_policy?ver=11.6.0","controls":["classification"],"hints":["no-write","no-delete","no-exclusion"],"requires":["http"],"strategy":"/Common/first-match","rulesReference":{"link":"https://localhost/mgmt/tm/ltm/policy/~Common~_sys_CEC_video_policy/rules?ver=11.6.0","isSubcollection":true}}]}

2015-11-12 09:50:23 : Create an LTM policy for use with by iApp which associates the ASM policy
POST mgmt/tm/ltm/policy {"name": "ltm_policy_w_asm_linux_high-Vip1", "rules": [{"ordinal": 1, "conditions": [], "name": "rule-1", "actions": [{"status": 0, "enable": true, "name": "0", "request": true, "vlanId": 0, "code": 0, "policy": "/Common/linux_high-Vip1", "port": 0, "asm": true}]}], "partition": "Common", "controls": ["asm"], "strategy": "/Common/first-match", "requires": ["http"]}
Method POST mgmt/tm/ltm/policy returned: {"kind":"tm:ltm:policy:policystate","name":"ltm_policy_w_asm_linux_high-Vip1","partition":"Common","fullPath":"/Common/ltm_policy_w_asm_linux_high-Vip1","generation":318,"selfLink":"https://localhost/mgmt/tm/ltm/policy/~Common~ltm_policy_w_asm_linux_high-Vip1?ver=11.6.0","controls":["asm"],"requires":["http"],"strategy":"/Common/first-match","rulesReference":{"link":"https://localhost/mgmt/tm/ltm/policy/~Common~ltm_policy_w_asm_linux_high-Vip1/rules?ver=11.6.0","isSubcollection":true}}

2015-11-12 09:50:25 : Deploy the iApp template, since we are not using a default iApp on box
GET mgmt/tm/sys/application/template ""
Method GET mgmt/tm/sys/application/template returned: {"kind":"tm:sys:application:template:templatecollectionstate","selfLink":"https://localhost/mgmt/tm/sys/application/template?ver=11.6.0","items":[...<list of iApp templates on the box>...]}

2015-11-12 09:50:30 : Deploy the iApp service from the f5 http backport template
GET mgmt/tm/sys/application/service ""
Method GET mgmt/tm/sys/application/service returned: {"kind":"tm:sys:application:service:servicecollectionstate","selfLink":"https://localhost/mgmt/tm/sys/application/service?ver=11.6.0"}

2015-11-12 09:51:37 : Deploying/updating webserver pool
GET mgmt/tm/ltm/pool ""
Method GET mgmt/tm/ltm/pool returned: {"kind":"tm:ltm:pool:poolcollectionstate","selfLink":"https://localhost/mgmt/tm/ltm/pool?ver=11.6.0","items":[{"kind":"tm:ltm:pool:poolstate","name":"Vip1_pool","partition":"Common","fullPath":"/Common/Vip1_pool","generation":236,"selfLink":"https://localhost/mgmt/tm/ltm/pool/~Common~Vip1_pool?ver=11.6.0","allowNat":"yes","allowSnat":"yes","ignorePersistedWeight":"disabled","ipTosToClient":"pass-through","ipTosToServer":"pass-through","linkQosToClient":"pass-through","linkQosToServer":"pass-through","loadBalancingMode":"round-robin","minActiveMembers":0,"minUpMembers":0,"minUpMembersAction":"failover","minUpMembersChecking":"disabled","monitor":"/Common/http ","queueDepthLimit":0,"queueOnConnectionLimit":"disabled","queueTimeLimit":0,"reselectTries":0,"serviceDownAction":"none","slowRampTime":10,"membersReference":{"link":"https://localhost/mgmt/tm/ltm/pool/~Common~Vip1_pool/members?ver=11.6.0","isSubcollection":true}},{"kind":"tm:ltm:pool:poolstate","name":"syslog_pool","partition":"Common","fullPath":"/Common/syslog_pool","generation":239,"selfLink":"https://localhost/mgmt/tm/ltm/pool/~Common~syslog_pool?ver=11.6.0","allowNat":"yes","allowSnat":"yes","ignorePersistedWeight":"disabled","ipTosToClient":"pass-through","ipTosToServer":"pass-through","linkQosToClient":"pass-through","linkQosToServer":"pass-through","loadBalancingMode":"round-robin","minActiveMembers":0,"minUpMembers":0,"minUpMembersAction":"failover","minUpMembersChecking":"disabled","monitor":"/Common/tcp ","queueDepthLimit":0,"queueOnConnectionLimit":"disabled","queueTimeLimit":0,"reselectTries":0,"serviceDownAction":"none","slowRampTime":10,"membersReference":{"link":"https://localhost/mgmt/tm/ltm/pool/~Common~syslog_pool/members?ver=11.6.0","isSubcollection":true}}]}

2015-11-12 09:51:37 : Deploying/updating webserver pool
POST mgmt/tm/ltm/pool {"name": "Vip2_pool", "members": [{"description": "Name=/boring_lovelace,ContainerHostname=a0085832ad28,Image=mutzel/all-in-one-hackazon:postinstall", "name": "172.16.14.87:80", "address": "172.16.14.87"}], "monitor": "http"}
Method POST mgmt/tm/ltm/pool returned: {"kind":"tm:ltm:pool:poolstate","name":"Vip2_pool","fullPath":"Vip2_pool","generation":352,"selfLink":"https://localhost/mgmt/tm/ltm/pool/Vip2_pool?ver=11.6.0","allowNat":"yes","allowSnat":"yes","ignorePersistedWeight":"disabled","ipTosToClient":"pass-through","ipTosToServer":"pass-through","linkQosToClient":"pass-through","linkQosToServer":"pass-through","loadBalancingMode":"round-robin","minActiveMembers":0,"minUpMembers":0,"minUpMembersAction":"failover","minUpMembersChecking":"disabled","monitor":"/Common/http ","queueDepthLimit":0,"queueOnConnectionLimit":"disabled","queueTimeLimit":0,"reselectTries":0,"serviceDownAction":"none","slowRampTime":10,"membersReference":{"link":"https://localhost/mgmt/tm/ltm/pool/~Common~Vip2_pool/members?ver=11.6.0","isSubcollection":true}}

2015-11-12 09:51:39 : Uploading iRules ... irule_random_snat
GET mgmt/tm/ltm/rule ""
Method GET mgmt/tm/ltm/rule returned: {"kind":"tm:ltm:rule:rulecollectionstate","selfLink":"https://localhost/mgmt/tm/ltm/rule?ver=11.6.0","items":[...<list of irules on the box>...]}

...

2015-11-12 09:51:43 : Setup the HTTP virtual server
POST mgmt/tm/ltm/virtual {"name": "Vip2_http", "rules": ["/Common/irule_random_snat"], "translateAddress": "enabled", "destination": "/Common/172.16.13.145:80", "mask": "255.255.255.255", "sourceAddressTranslation": {"type": "automap"}, "profiles": [{"name": "http"}, {"name": "tcp-wan-optimized", "context": "clientside"}, {"name": "tcp-lan-optimized", "context": "serverside"}], "translatePort": "enabled", "ipProtocol": "tcp", "pool": "/Common/Vip2_pool"}
Method POST mgmt/tm/ltm/virtual returned: {"kind":"tm:ltm:virtual:virtualstate","name":"Vip2_http","fullPath":"Vip2_http","generation":355,"selfLink":"https://localhost/mgmt/tm/ltm/virtual/Vip2_http?ver=11.6.0","addressStatus":"yes","autoLasthop":"default","cmpEnabled":"yes","connectionLimit":0,"destination":"/Common/172.16.13.145:80","enabled":true,"gtmScore":0,"ipProtocol":"tcp","mask":"255.255.255.255","mirror":"disabled","mobileAppTunnel":"disabled","nat64":"disabled","pool":"/Common/Vip2_pool","rateLimit":"disabled","rateLimitDstMask":0,"rateLimitMode":"object","rateLimitSrcMask":0,"source":"0.0.0.0/0","sourceAddressTranslation":{"type":"automap"},"sourcePort":"preserve","synCookieStatus":"not-activated","translateAddress":"enabled","translatePort":"enabled","vlansDisabled":true,"vsIndex":4,"rules":["/Common/irule_random_snat"],"policiesReference":{"link":"https://localhost/mgmt/tm/ltm/virtual/~Common~Vip2_http/policies?ver=11.6.0","isSubcollection":true},"profilesReference":{"link":"https://localhost/mgmt/tm/ltm/virtual/~Common~Vip2_http/profiles?ver=11.6.0","isSubcollection":true}}

2015-11-12 09:51:45 : Setup the HTTPS virtual server
POST mgmt/tm/ltm/virtual {"name": "Vip2_https", "rules": ["/Common/irule_random_snat"], "translateAddress": "enabled", "destination": "/Common/172.16.13.145:443", "mask": "255.255.255.255", "sourceAddressTranslation": {"type": "automap"}, "profiles": [{"name": "tcp-ssl-wan-optimized", "context": "clientside"}, {"name": "tcp-ssl-lan-optimized", "context": "serverside"}], "translatePort": "enabled", "ipProtocol": "tcp", "pool": "/Common/Vip2_pool"}
Method POST mgmt/tm/ltm/virtual returned: {"kind":"tm:ltm:virtual:virtualstate","name":"Vip2_https","fullPath":"Vip2_https","generation":356,"selfLink":"https://localhost/mgmt/tm/ltm/virtual/Vip2_https?ver=11.6.0","addressStatus":"yes","autoLasthop":"default","cmpEnabled":"yes","connectionLimit":0,"destination":"/Common/172.16.13.145:443","enabled":true,"gtmScore":0,"ipProtocol":"tcp","mask":"255.255.255.255","mirror":"disabled","mobileAppTunnel":"disabled","nat64":"disabled","pool":"/Common/Vip2_pool","rateLimit":"disabled","rateLimitDstMask":0,"rateLimitMode":"object","rateLimitSrcMask":0,"source":"0.0.0.0/0","sourceAddressTranslation":{"type":"automap"},"sourcePort":"preserve","synCookieStatus":"not-activated","translateAddress":"enabled","translatePort":"enabled","vlansDisabled":true,"vsIndex":5,"rules":["/Common/irule_random_snat"],"policiesReference":{"link":"https://localhost/mgmt/tm/ltm/virtual/~Common~Vip2_https/policies?ver=11.6.0","isSubcollection":true},"profilesReference":{"link":"https://localhost/mgmt/tm/ltm/virtual/~Common~Vip2_https/profiles?ver=11.6.0","isSubcollection":true}}

 

Deploying an iApp template using iControlREST

Because we recognize that it may be not obvious how we are deploying iApp templates using iControlREST, we break it down into more detail here.

First, note that there is no 'import' action we can invoke via REST to import the iApp template which mirrors the action in the Configuration Utility (GUI). This means that we need to create the JSON payload containing the iApp and POST it. 

Given an iApp template, like those found on DevCentral, here are the steps to create the JSON body.

 

  1. On a pre-existing BIG-IP install (or one have created in your build process for your code)
    1. Import the iApp template in the Configuration Utility in the 'Common' partition
    2. Do an HTTP GET to retrieve the iApp template payload. Make sure that you use the expandSubcollections=True as a query parameter, as we want to include the stuff in the 'actionsReference' sub-collection.
      1. curl -sku <user>:<password> -X GET  https://<management ip>/mgmt/tm/sys/application/template/~Common~<name of your iApp>?expandSubcollections=true
    3. You should get something back that looks like the following (which is the payload for the f5.http backport iApp).  I have truncated the 'implementation', 'presentation' and 'htmlHelp' actions:
      1. {
            "actionsReference": {
                "isSubcollection": true,
                "items": [
                    {
                        "fullPath": "definition",
                        "generation": 4672,
                        "htmlHelp": "....",
                        "implementation": "...",
                        "kind": "tm:sys:application:template:actions:actionsstate",
                        "name": "definition",
                        "presentation": "...",
                        "roleAcl": [
                            "admin",
                            "manager",
                            "resource-admin"
                        ],
                        "selfLink": "https://localhost/mgmt/tm/sys/application/template/~Common~f5.http.backport.1.1.2/actions/definition?ver=11.6.0"
                    }
                ],
                "link": "https://localhost/mgmt/tm/sys/application/template/~Common~f5.http.backport.1.1.2/actions?ver=11.6.0"
            },
            "fullPath": "/Common/f5.http.backport.1.1.2",
            "generation": 4672,
            "ignoreVerification": "false",
            "kind": "tm:sys:application:template:templatestate",
            "name": "f5.http.backport.1.1.2",
            "partition": "Common",
            "requiresBigipVersionMin": "11.6.0",
            "selfLink": "https://localhost/mgmt/tm/sys/application/template/~Common~f5.http.backport.1.1.2?expandSubcollections=true&ver=11.6.0",
            "totalSigningStatus": "not-all-signed",
            "verificationStatus": "none"
        }
      2. Before we can POST this payload back to any BIG-IP, we need to cleanup a few things:
        1. Remove any of the extraneous fields including 'verificationStatus', 'totalSigningStatus', 'selfLink', 'partition', 'kind', 'generation', 'fullPath'.
        2. Make a new top-level key in the payload called 'actions'.  The value for this key should everything in the 'items' array under the top-level key 'actionsReference'.  Finally, delete the 'actionsReference' key/value pair from the JSON body. The final JSON payload should look like:
          1. {
              "actions": [
                {
                  "htmlHelp": "....",
                  "implementation": "...",
                  "name": "definition",
                  "presentation": "...",
                  "roleAcl": [
                    "admin",
                    "manager",
                    "resource-admin"
                  ]
                }
              ],
              "ignoreVerification": "false",
              "name": "f5.http.backport.1.1.2",
              "requiresBigipVersionMin": "11.6.0",
              "totalSigningStatus": "not-all-signed"
            }
      3. Finally, we can use this to deploy an iApp template on BIG-IP.  In the example below, the iApp_template.json file is formatted like the above. I have also attached it to this page for inspection. 
        1. curl -sku rest_admin:<obfuscated> -H "Content-type: application/json" -X POST -d@./iApp_template.json https://52.23.149.16//mgmt/tm/sys/application/template

Before you go POSTing iApps to any old version of TMOS, be aware that there are still some remaining issues you might have to solve.  Some of the official iApps found on DevCentral are prepended with a TCL library that defines functions used within the iApp.  The iApp solutions team made this design decision so that newer iApps will work against older versions of TMOS.  For example, see the 'F5 HTTP', which starts with the library definition on line 0: "cli script f5.iapp.1.3.0.cli {....".  When you export the iApp template to JSON using REST as we have documented above, this library will not be included in the payload. Because newer versions of BIG-IP (11.6) might already include a version of this 'iApp' library, you can work around this issue by updating the function references to use the existing library on-box.  Here are the high-level steps:

  1. Downloading the iApp from DevCentral
  2. Change the function references to leverage the library that is installed on your BIG-IP.  See an example of this by comparing the F5 HTTP template on the codeshare with the one attached to this page. 
    1. You'll probably have to do some "find and replace" like the following:
    2. f5.iapp.1.3.0.cli:iapp_get_provisioned -> iapp::get_provisioned
    3. There may be some references to functions that do not exist yet.  These will have to be dealt with on a case-by-case basis. 
  3. Uploading the iApp to BIG-IP and exporting we documented above.  

Deploying an iApp service using iControlREST

Fortunately, using iControlREST to manage instances of iApps (also known as iApp services) is much easier than managing templates.  The high-level steps are similar: 

  1. Deploy an iApp service via the Configuration Utility.
  2. Do an HTTP GET to acquire the JSON representation (notice the URL formatting!).
    1. curl -sku <user>:<password> -X GET https://<management ip>/mgmt/tm/sys/application/service/~Common~<your iapp name>.app~<your iapp name> 
  3. Depending on the variables presented by the iApp template, the JSON payload for the iApp service might look something like:
    1.  {
          "deviceGroup": "none",
          "fullPath": "/Common/Vip1_iApp.app/Vip1_iApp",
          "generation": 4674,
          "inheritedDevicegroup": "true",
          "inheritedTrafficGroup": "true",
          "kind": "tm:sys:application:service:servicestate",
          "lists": [
              {
                  "encrypted": "no",
                  "name": "irules__irules",
                  "value": [
                      "/Common/irule_demo_analytics",
                      "/Common/irule_sorry_page"
                  ]
              }
          ],
          "name": "Vip1_iApp",
          "partition": "Common",
          "selfLink": "https://localhost/mgmt/tm/sys/application/service/~Common~Vip1_iApp.app~Vip1_iApp?ver=11.6.0",
          "strictUpdates": "enabled",
          "subPath": "Vip1_iApp.app",
          "tables": [
              {
                  "name": "basic__snatpool_members"
              },
              {
                  "name": "net__snatpool_members"
              },
              {
                  "name": "optimizations__hosts"
              },
              {
                  "columnNames": [
                      "name"
                  ],
                  "name": "pool__hosts",
                  "rows": [
                      {
                          "row": [
                              "demo.example.com"
                          ]
                      }
                  ]
              },
              {
                  "name": "pool__members"
              },
              {
                  "name": "server_pools__servers"
              }
          ],
          "template": "/Common/f5.http.backport.1.1.2",
          "templateModified": "yes",
          "trafficGroup": "/Common/traffic-group-1",
          "variables": [
              {
                  "encrypted": "no",
                  "name": "asm__security_logging",
                  "value": "asm_log_to_splunk"
              },
              {
                  "encrypted": "no",
                  "name": "asm__use_asm",
                  "value": "/Common/ltm_policy_w_asm_linux_high-Vip1"
              },
              {
                  "encrypted": "no",
                  "name": "client__http_compression",
                  "value": "/#do_not_use#"
              },
              {
                  "encrypted": "no",
                  "name": "client__standard_caching_without_wa",
                  "value": "/#do_not_use#"
              },
              {
                  "encrypted": "no",
                  "name": "client__tcp_wan_opt",
                  "value": "/Common/tcp-ssl-wan-optimized"
              },
              {
                  "encrypted": "no",
                  "name": "net__client_mode",
                  "value": "wan"
              },
              {
                  "encrypted": "no",
                  "name": "net__route_to_bigip",
                  "value": "no"
              },
              {
                  "encrypted": "no",
                  "name": "net__same_subnet",
                  "value": "no"
              },
              {
                  "encrypted": "no",
                  "name": "net__server_mode",
                  "value": "lan"
              },
              {
                  "encrypted": "no",
                  "name": "net__snat_type",
                  "value": "automap"
              },
              {
                  "encrypted": "no",
                  "name": "net__vlan_mode",
                  "value": "all"
              },
              {
                  "encrypted": "no",
                  "name": "pool__addr",
                  "value": "172.16.13.128"
              },
              {
                  "encrypted": "no",
                  "name": "pool__http",
                  "value": "/#create_new#"
              },
              {
                  "encrypted": "no",
                  "name": "pool__mask",
                  "value": "none"
              },
              {
                  "encrypted": "no",
                  "name": "pool__persist",
                  "value": "/#cookie#"
              },
              {
                  "encrypted": "no",
                  "name": "pool__pool_to_use",
                  "value": "/Common/Vip1_pool"
              },
              {
                  "encrypted": "no",
                  "name": "pool__port_secure",
                  "value": "443"
              },
              {
                  "encrypted": "no",
                  "name": "pool__redirect_port",
                  "value": "80"
              },
              {
                  "encrypted": "no",
                  "name": "pool__redirect_to_https",
                  "value": "yes"
              },
              {
                  "encrypted": "no",
                  "name": "pool__xff",
                  "value": "yes"
              },
              {
                  "encrypted": "no",
                  "name": "server__oneconnect",
                  "value": "/#do_not_use#"
              },
              {
                  "encrypted": "no",
                  "name": "server__tcp_lan_opt",
                  "value": "/Common/tcp-wan-optimized"
              },
              {
                  "encrypted": "no",
                  "name": "server__tcp_req_queueing",
                  "value": "no"
              },
              {
                  "encrypted": "no",
                  "name": "ssl__cert",
                  "value": "/Common/default.crt"
              },
              {
                  "encrypted": "no",
                  "name": "ssl__client_ssl_profile",
                  "value": "/#create_new#"
              },
              {
                  "encrypted": "no",
                  "name": "ssl__key",
                  "value": "/Common/default.key"
              },
              {
                  "encrypted": "no",
                  "name": "ssl__mode",
                  "value": "client_ssl"
              },
              {
                  "encrypted": "no",
                  "name": "ssl__use_chain_cert",
                  "value": "/#do_not_use#"
              },
              {
                  "encrypted": "no",
                  "name": "ssl_encryption_questions__advanced",
                  "value": "yes"
              },
              {
                  "encrypted": "no",
                  "name": "ssl_encryption_questions__help",
                  "value": "hide"
              },
              {
                  "encrypted": "no",
                  "name": "stats__analytics",
                  "value": "/Common/Vip1-demo_analytics"
              },
              {
                  "encrypted": "no",
                  "name": "stats__request_logging",
                  "value": "/#do_not_use#"
              }
          ]
      }
  4. As ealier, remove some of the fields that don't make sense to re-post. This includes 'deviceGroup', 'fullPath', 'generation', 'kind', 'partition', 'selfLink', and 'subPath'.
  5. You can now use this JSON body with updates to the variable values as needed.  

Example python code for deploying iApp Templates

In addition to the above procedures, we'd like you point you to some python examples which show how to push iApp templates using REST. Hitesh Patel, another monster F5er, has put together the following code:

https://github.com/0xHiteshPatel/appsvcs_integration_iapp/tree/80cc40dcf85e352a25c7ec44d9e4dcc253e51e69/scripts

In his words: "that's 152 lines of awesome right there".

His examples run against 11.5.x, 11.6.x and 12.0. 

Debugging

When trying to create or update an instance of an iApp via REST, you will get error messages in the HTTP response if your POST is unsuccessful.  In addition to the HTTP payload in the response, the following debug steps can be helpful:

1) Set the scriptd log level to debug:

modify sys scriptd log-level debug

2) Look at the TMSH output from the iApp printed to /var/log/scriptd.out.  Typically the last line will show the error that has occured. 

In closing

The above examples should bring you one step closer to automating the delivery of advanced network services for your applications.  We're looking forward to doing future posts on how to automate your deployment.  Finally, if you haven't checked out the Application Services Integration iApp, also by Hitesh, you should probably do so now: https://github.com/0xHiteshPatel/appsvcs_integration_iapp.

Cheers!

Published Nov 09, 2015
Version 1.0
  • Hi Chris,

    Nice work.

    From your example Deploying an iApp service using iControlRest would we also use a post (like for the template example) for the deployment part? If so, would it look something like the below CURL statement?

    curl -sku rest_admin: -H "Content-type:application/json" -X POST -d@./iApp_.json https:///mgmt/tm/sys/application/service/~Common~.app~

    Regards,

    Barney