HTTP Callout

An HTTP callout is an HTTP request that the appliance generates and sends to an external application when certain criteria are met during policy evaluation. The information that is retrieved from the server can be analyzed and used to make some decision.

When the  netscaler (configured with http callout in policies/actions) receives a client request or a server response, it stalls policy evaluation briefly and sends an HTTP request to the HTTP callout agent by using the parameters configured for the specified HTTP callout. Upon receiving the response, the appliance inspects the specified portion of the response, and then either performs an action or evaluates the next policy, depending on whether the evaluation of the response from the HTTP callout agent evaluates to TRUE or FALSE, respectively. Here is the HTTPCallout flow for request side configuration

How HTTPCallout works

NITRO API

The netscaler NITRO protocol allows you to configure and monitor the NetScaler appliance programmatically.
NITRO exposes its functionality through Representational State Transfer (REST) interfaces.

For more details about nitro api, Please checkout the blogs

NITRO APIs: Fun over HTTP

NITRO APIs: Dynamic Behavior using HTTP Query

HTTPCallout and  Netscaler callback

Similar to external servers, HTTPCallout can call a http vserver or any MIP or SNIP. If there is a SNIP or MIP with management access enabled, HTTPCallouts can call the appliance administration utilities. By access in the NITRO API using callout we can achieve runtime configurations.

Steps to make it work

  • Create a SNIP with a internal ip address and enable management access.
  • Create a http callout
  • Update the httpcallout parameters with the SNIP and NITRO http requests
  • Create actions/policies to call the callout
  • Bind the policies to make it active.

Use cases

  • Time/load based resource allocation. Let say the application have a peak load at some particular duration. We can have a callout to bind additional services to the application based the application’s through put or number of connections. Once the condition become normal  (Again by checking the though put or some other attributes) we can remove some of the services.
  • Timely cache flush. We can monitor the cache content group memory usage and based on that we can flush some content groups
  • Dynamic data set update. Data sets like patset can be updated on the fly. For example new usernames on a website ( whoever registers on a website) can be added into patset which holds valid username set to allow.
  • And many more based on some dynamic conditional config changes.

Example 1

Unbinding some services based on the connection details

Let say we want to unbind one service or a service group based on number of input connections. If the connections are less than 1000 remove a service/service group from a lb vserver.

Condition: Number of connection to the vserver “vserver1″ is less than 1000

Action: remove service “svc2″ from vserver

Configuration:

add ip 1.1.1.1 255.255.255.0 -type SNIP -mgmtAccess ENABLED
add policy httpCallout unbind_service
set policy httpCallout unbind_service -IPAddress 1.1.1.1 -port 80 -hostExpr '"nitro.callout.net"' -returnType BOOL -httpMethod POST -urlStemExpr "\"/nitro/v1/config\"" -headers Content-Type("application/x-www-form-urlencoded") Authorization("Basic bnNyb290Om5zcm9vdA==") -parameters object("{\"params\":{\"action\": \"unbind\"},\"lbvserver_service_binding\":{\"name\": \"vserver1\", \"serviceName\" :\"svc2\"}}") -resultExpr q/HTTP.RES.BODY(1000).AFTER_STR("message\": \"").BEFORE_STR("\"").EQ("Done")/

add responder policy call_unbind_service "SYS.VSERVER(\"vserver1\").CONNECTIONS.LT(1000) && SYS.HTTP_CALLOUT(unbind_service)" NOOP
bind lb vserver vserver1 -policyName call_unbind_service -priority 100 -gotoPriorityExpression NEXT

Authorization header is nothing but base64 encoded username password using basic authentication type.
Actual Callout request

POST /nitro/v1/config HTTP/1.1\r\n
Content-Type: application/x-www-form-urlencoded\r\n
Host: callback.callout.net\r\n
Accept: */*\r\nContent-Length:109\r\n
Authorization: Basic bnNyb290Om5zcm9vdA==\r\n
\r\n
object={"params":{"action": "unbind"},"lbvserver_service_binding":{"name": "vserver1", "serviceName":"svc2"}}

Response for callout

HTTP/1.1 200 OK\r\n
Date: Fri, 2 Aug 2011 09:16:50 GMT\r\n
Server: Apache\r\n
Expires: Thu, 19 Nov 1981 08:52:00 GMT\r\n
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\nPragma: no-cache\r\n
Content-Length: 64\r\n
Content-Type: application/json; charset=utf-8\r\n
\r\n
{ "errorcode": 0, "message": "done" }

Similarly A different callout can help to bind the service/servicegroup back if the vserver handling reaches the peak.

Example 2

Flush the cache on the contentgroup default when the day changes

Condition: When the date changes

Action: flush the cache in default contentgroup

We need to store the sys date somewhere and compare with the current date. If it changed we need to remove the cache. currently there is no way to store any data in netscaler. But using same nitro+callout we can store it in comment section of the policies.

So here what we need

  • A callout to set the system date in policy’s comment parameters
  • A callout to flush the cache
  • A callout to get the stored date
  • A policy to check the current sys date is changed from the stored.

Configuration

add policy expression sys_date "SYS.TIME.DAY+\"-\"+SYS.TIME.MONTH+\"-\"+SYS.TIME.YEAR"
add policy httpCallout store_system_time
add policy httpCallout flush_cache
add policy httpCallout get_stored_time

set policy httpCallout store_system_time -IPAddress 1.1.1.1 -port 80 -returnType BOOL -httpMethod POST -hostExpr "\"callback.callout.net\"" -urlStemExpr "\"/nitro/v1/config\"" -headers Content-Type("application/x-www-form-urlencoded") Authorization("Basic bnNyb290Om5zcm9vdA==") -parameters object("{\"params\":{\"action\": \"set\"},\"responderpolicy\":{\"name\": \"check_date\", \"comment\": \""+sys_date+"\"}}") -resultExpr q/HTTP.RES.BODY(1000).AFTER_STR("message\": \"").BEFORE_STR("\"").EQ("Done")/

set policy httpCallout flush_cache -IPAddress 1.1.1.1 -port 80 -returnType BOOL -httpMethod POST -hostExpr "\"callback.callout.net\"" -urlStemExpr "\"/nitro/v1/config\"" -headers Content-Type("application/x-www-form-urlencoded") Authorization("Basic bnNyb290Om5zcm9vdA==") -parameters object("{\"params\":{\"action\": \"flush\"},\"cachecontentgroup\":{\"name\": \"default\"}}") -resultExpr q/HTTP.RES.BODY(1000).AFTER_STR("message\": \"").BEFORE_STR("\"").EQ("Done")/

set policy httpCallout get_stored_time -IPAddress 1.1.1.1 -port 80 -returnType TEXT -hostExpr "\"callback.callout.net\"" -urlStemExpr "\"/nitro/v1/config/responderpolicy/check_date\"" -headers Authorization("Basic bnNyb290Om5zcm9vdA==") -resultExpr q/HTTP.RES.BODY(1000).AFTER_STR("comment\": \"").BEFORE_STR("\"") ALT "0"/
add responder policy check_date "(sys_date != SYS.HTTP_CALLOUT(get_stored_time))" NOOP
add responder policy set_date "SYS.HTTP_CALLOUT(store_system_time)" NOOP
add responder policy flush_cache "SYS.HTTP_CALLOUT(flush_cache)" NOOP
add responder policylabel flushcache_and_setdate
bind responder policylabel flushcache_and_setdate flush_cache 1 NEXT
bind responder policylabel flushcache_and_setdate set_date 2 END
bind lb vserver vsvrLB -policyName check_date -priority 1 -gotoPriorityExpression END -invoke policylabel flushcache_and_setdate