v4
7 TopicsCookie Persistence and Troubleshooting
The BIG-IP persistence cookie is a valuable configuration option that allows stateful applications to remain persistent to a specific node with no additional configurations within the application or on the server(s) by doing something like clustering. I hear application development teams refer to this as “sticky session” or “stick sessions”, but in reality this cookie has nothing to do with a user’s “application” session, but has everything to do with the user’s session persistence to the same server that the application session was started on. After reading an F5 Solution article (SOL6917: Overview of BIG-IP persistence cookie encoding) and learning that the information encoded within a BIG-IP Cookie could be useful I decided to make a tool that could decipher this information quickly so that I could use it for troubleshooting. What is useful in a BIG-IP Cookie? The BIG-IP Cookie contains the IP Address of the server that the client is being persisted to, as well as the server port that the connection is being established on. So? Why is this useful? I could get that information from an iRule… True, you can get this information logged within the LB::selected event within an iRule, but that requires you to make an iRule change to gather the information that you actually already have (unless you are encrypting your BIG-IP Cookies which negate the usefulness of this tool). Most changes in Production require change management approval, which you get to bypass when using this tool if cookie persistence is configured. There are many tools that you can use to capture the persistence cookie being provided by the BIG-IP. I commonly use Fiddler2 (http://www.fiddler2.com/fiddler2/)… This is the application that I created to decipher the BIG-IP Cookies. The tool is semi-intelligent for the input. It can take any of the following and give the correct output: BIGipServerpool.ltm.ve.gamezone.com=336202250.40475.0000 336202250.40475.0000 336202250.40475 Paste the cookie into the tool and select ‘Auto-Parse’ option: This will populate the Conversion Area: Then select the ‘Decipher’ option: This becomes useful for troubleshooting purposes to determine which server you are persisted to when you are trying to determine which member server is or is not having an issue. As you can see, this correctly identified which server I was communicating with in this pool of servers: I hope that everyone finds this tool useful. If you find any issues or have any questions please feel free to contact me on DevCentral. Source Code The full source for this application can be retrieved at this link: CookietoolRelease.zip2.6KViews0likes5CommentsPacfiles R iRules?
by Bhattman @ gmail dot com Pac Files are used throughout various companies to direct traffic out proxy systems but is not well understood by most and how it relates to F5 ADCs. Hopefully this article can clear it up for you and give you a better how idea of how to use it with the ADC. What are pac file? A pac file is a text file containing JavaScript code. It is commonly called proxy.pac, but it can be named differently. It’s mostly used for 2 primary reasons: Companies have multiple proxies where traffic is directed through, either for redundancy or access to networks that are normally closed off. Split domain, where a single domain (i.e., domain.com ) is hosted both internally and externally. A very basic pac file contains a single function. It’s function is to direct users through a proxy or proxies based on a URL or website request. A more advanced pacfile script can direct users out through a proxy or proxies based on user’s IP address or subnet. The pac file settings are usually the following link http://pac.webserver.com/proxy.pac. Pac files can also be hosted on different ports where the links for eample port 7070 (i.e., http://pac.webserver.com:7070/proxy.pac) The pac file setting is configured in the browsers option or preference settings. Most cases they are labeled clearly. The pac file can be hosted on the user’s PC or it can be hosted on a web server (i.e. Apache or IIS). Most companies host in a web server, for centralized control. It’s important to remember that, so far no browser supports more then one pacfile at the user browser level. However, there are certain 3rd party extensions that can be used to get around this limitation. However, it’s usually designed for a specific browser rather then a universal version. So now you understand what a pac file is, what does a standard syntax look like? Here is very basic example: 1: function FindProxyForURL(url, host) { 2: 3: 4: if (shExpMatch(url, "http://10.*")|| 5: shExpMatch(url, "https://10.*")|| 6: shExpMatch(url, "ftp://10.*")|| 7: shExpMatch(url, "http://localhost*")|| 8: shExpMatch(url, "https://localhost*")|| 9: shExpMatch(url, "http://127.0.0.1*")|| 10: shExpMatch(url, "https://127.0.0.1*")|| 11: shExpMatch(url, "http://172.*")|| 12: shExpMatch(url, "https://172.*")|| 13: shExpMatch(url, "ftp://172.*")) 14: return "DIRECT"; 15: 16: 17: if (dnsDomainIs(host, "insidesite.com")|| 18: dnsDomainIs(host, "servername.google.com")) 19: return "DIRECT"; 20: 21: return "PROXY proxy.internaldomain.com:8080"; 22: } 23: } Simple? It’s actually simple once you know what each lines are doing. Let me explain: Lines 4 to 14 state that if a user entered a HTTP request that’s a private address or a localhost or loopback, should go direct and not use a proxy. Lines 17 to 19 state that if a user entered a HTTP request where the hostname matches either those 2 entries - should go direct and not use a proxy. Line 21 is the catch all – if the user’s HTTP request does not match any of the IF conditional statements, the script forces a request to go to proxy.internaldomain.com on port 8080. It’s important to note that the pacfile scripts are processed at the client and NOT on the server that is delivering the pacfile. Now that you the basic idea of pac file syntax, the next step is to know how it works with respect to user, proxy and a web server holding a webpage. Let’s say the Pac file is hosted on a proxy server also running a web server. Let’s assume that the user already has the proxy pac file settings already configured in their browser. Step 1: When the user starts the internet browser, browser retrieves the pac file . Step 2: The pacfile is downloaded to the browser’s cache and process any URL requests (For example the user’s browser could have home page going to www.cnn.com) before it let’s the user enter information in the URL Step 3: The user then enters in the URL http://www.google.com Step 4: The browser runs through the pacfile script like the one above, attempting to match to a IF conditional statement. In our example it won’t match any IF statement statement – thus by default is sent to “PROXY proxy.internaldomain.com:8080” Step 5: Proxy makes a request to the internet web server and requests for www.google.com page on behalf of the user. Step 6: The page is returned to the proxy. Step 7: As a final step, the proxy sends the request web page to user. Okay this is great. What does this have to do with ADCs? As it turns out there is one disadvantage for pacfiles – hosting a pacfile. It requires a web server. While the thought of hosting a web page might not be earth shattering it does become a problem when you run into the following scenario. Your IT organization might mandate a reduction in the amount of web servers in the environment. Your IT organization could contain a mixture of Squid, Bluecoat, and/or Ironport proxy systems. Each proxy has their own distinctive method to deliver a pac file, some might provide you flexibility to control your pac file deliver and some might not. Your IT organization wants to deliver different pac files based on users location or type of browser or IP addresses. What if you can host the pac file in an iRule? A centralized and consistent approach to deliver a pac file(s) to a user without requiring a web server OR relying on proxy vendors. The iRule IMPORTANT NOTE: From this point the iRule is written to conform with v10 So how do we get an iRule to deliver a pacfile? At this point we know the following: Pac file is a JavaScript code that the browsers understands Pac file is delivered via HTTP REQUEST and RESPONSE function FindProxyForURL(url, host) { if (isPlainHostName(host)) return "DIRECT"; if (shExpMatch(url, "http://10.*")|| shExpMatch(url, "https://10.*")|| shExpMatch(url, "ftp://10.*")|| shExpMatch(url, "http://localhost*")|| shExpMatch(url, "https://localhost*")|| shExpMatch(url, "http://127.0.0.1*")|| shExpMatch(url, "https://127.0.0.1*")|| shExpMatch(url, "http://172.*")|| shExpMatch(url, "https://172.*")|| shExpMatch(url, "ftp://172.*")) return "DIRECT"; if (dnsDomainIs(host, "inside.com")|| dnsDomainIs(host, "inside.net")|| dnsDomainIs(host, "outside.net")) return "DIRECT"; return "PROXY proxy.internaldomain.com:8080"; } } What’s the first step? Since the script needs to be human readable with indents and spaces we need to set the entire Pac file script into a global variable for example “pacfile” 1: set static::pacfile { 2: function FindProxyForURL(url, host) { 3: 4: if (isPlainHostName(host)) 5: return "DIRECT"; 6: 7: if (shExpMatch(url, "http://10.*")|| 8: shExpMatch(url, "https://10.*")|| 9: shExpMatch(url, "ftp://10.*")|| 10: shExpMatch(url, "http://localhost*")|| 11: shExpMatch(url, "https://localhost*")|| 12: shExpMatch(url, "http://127.0.0.1*")|| 13: shExpMatch(url, "https://127.0.0.1*")|| 14: shExpMatch(url, "http://172.*")|| 15: shExpMatch(url, "https://172.*")|| 16: shExpMatch(url, "ftp://172.*")) 17: return "DIRECT"; 18: 19: 20: if (dnsDomainIs(host, "inside.com")|| 21: dnsDomainIs(host, "inside.net")|| 22: dnsDomainIs(host, "outside.net")) 23: return "DIRECT"; 24: 25: return "PROXY proxy.internaldomain.com:8080"; 26: } 27: } 28: The event to use is when RULE_INIT since we are setting the script into a global variable. Your code looks like the following 1: when RULE_INIT { 2: set static::pacfile { 3: function FindProxyForURL(url, host) { 4: 5: if (isPlainHostName(host)) 6: return "DIRECT"; 7: 8: if (shExpMatch(url, "http://10.*")|| 9: shExpMatch(url, "https://10.*")|| 10: shExpMatch(url, "ftp://10.*")|| 11: shExpMatch(url, "http://localhost*")|| 12: shExpMatch(url, "https://localhost*")|| 13: shExpMatch(url, "http://127.0.0.1*")|| 14: shExpMatch(url, "https://127.0.0.1*")|| 15: shExpMatch(url, "http://172.*")|| 16: shExpMatch(url, "https://172.*")|| 17: shExpMatch(url, "ftp://172.*")) 18: return "DIRECT"; 19: 20: 21: if (dnsDomainIs(host, "inside.com")|| 22: dnsDomainIs(host, "inside.net")|| 23: dnsDomainIs(host, "outside.net")) 24: return "DIRECT"; 25: 26: return "PROXY proxy.internaldomain.com:8080"; 27: } 28: } 29: } The next step is to use HTTP_REQUEST event as the trigger for the request and use HTTP::response command to send the the contents of the pacfile back to the requestor. We also need to include a MIME type so the browser knows that proxy pac file is being send. This is a requirement. We also need to make sure that requestor’s browser does not cache the file for any length of time. This is because we want to make updates and get immediate changes to the requestor. Based on this the code should look something like the following 1: when HTTP_REQUEST { 2: switch -glob [HTTP::uri] { 3: "/proxy.pac" { 4: HTTP::respond 200 content $static::pacfile "Content-Type" "application/x-ns-proxy-autoconfig" "pragma" "no-cache" 5: return 6: } 7: } 8: } Putting it all together the entire code should look like the following 1: when RULE_INIT { 2: set static::pacfile { 3: function FindProxyForURL(url, host) { 4: 5: if (isPlainHostName(host)) 6: return "DIRECT"; 7: 8: if (shExpMatch(url, "http://10.*")|| 9: shExpMatch(url, "https://10.*")|| 10: shExpMatch(url, "ftp://10.*")|| 11: shExpMatch(url, "http://localhost*")|| 12: shExpMatch(url, "https://localhost*")|| 13: shExpMatch(url, "http://127.0.0.1*")|| 14: shExpMatch(url, "https://127.0.0.1*")|| 15: shExpMatch(url, "http://172.*")|| 16: shExpMatch(url, "https://172.*")|| 17: shExpMatch(url, "ftp://172.*")) 18: return "DIRECT"; 19: 20: if (dnsDomainIs(host, "inside.com")|| 21: dnsDomainIs(host, "inside.net")|| 22: dnsDomainIs(host, "outside.net")) 23: return "DIRECT"; 24: 25: return "PROXY proxy.internaldomain.com:8080"; 26: } 27: } 28: } 29: 30: when HTTP_REQUEST { 31: switch -glob [HTTP::uri] { 32: "/proxy.pac" { 33: HTTP::respond 200 content $static::pacfile "Content-Type" "application/x-ns-proxy-autoconfig" "pragma" "no-cache" 34: return 35: } 36: } 37: } As you can see you now have the ability to deliver a pac file.611Views0likes2CommentsHealth Monitors for Exchange 2010
I was recently asked to develop health monitors on my 10.2.4HF3 LTMs for our Exchange 2010 environment. Two of the three monitors were a bit challenging, so I wanted to share what I developed. The monitors have been sanitized to protect our environment - modify them to fit yours. *** Active Sync *** This monitor was challenging me, until I stumbled across this statement for versions 10.2.x and 11.x in SOL2167: "When Basic Authentication is enabled by configuring a User Name and Password in the monitor definition, the system inserts the Authorization header and a terminating double CR/LF sequence (0x0d 0x0a 0x0d 0x0a) after the last character in the Send String." Once I read that, I removed my standard trailing "\r\n\r\n" sequence at the end of the Send String, and the monitor immediately started working. It saved me from having to use an External monitor. You will need to insert a username, password, and host header value in the send string to fit your environment: 1: ltm monitor https active-sync { 2: cipherlist "DEFAULT:+SHA:+3DES:+kEDH" 3: compatibility "enabled" 4: defaults-from https 5: interval 10 6: password "<password>" 7: recv "MS-ASProtocolCommands: Sync,SendMail,SmartForward,SmartReply,GetAttachment,GetHierarchy,CreateCollection,DeleteCollection,MoveCollection,FolderSync" 8: send "OPTIONS /Microsoft-Server-ActiveSync/ HTTP/1.1\r\nHost: <host header value>" 9: time-until-up 0 10: timeout 31 11: username "<domain>\<username>" 12: } *** Outlook Web Access *** This monitor was straightforward. You will need to replace the FQDN in both the URI and the Host: header in the Send String: 1: ltm monitor https outlook-web-access { 2: cipherlist "DEFAULT:+SHA:+3DES:+kEDH" 3: compatibility "enabled" 4: defaults-from https 5: interval 10 6: recv "OutlookSession=" 7: send "GET /owa/auth/logon.aspx?url=https://<hostname>/owa/&reason=0 HTTP/1.1\r\nUser-Agent: Mozilla/4.0\r\nHost: <hostname>\r\n\r\n" 8: time-until-up 0 9: timeout 31 10: } *** Outlook Anywhere *** This monitor was complicated enough that it could not be done by any of the built-in monitor types, so I had to run this with CURL as an External monitor. Here is the LTM monitor definition: 1: ltm monitor external outlook-anywhere { 2: defaults-from external 3: interval 10 4: run "outlook-anywhere.sh" 5: time-until-up 0 6: timeout 31 7: user-defined debug "0" 8: user-defined debugfile "/shared/tmp/outloo-anywhere_debug.log" 9: user-defined receivestring "200 Success" 10: user-defined username "<domain>\<username>" 11: } In order to get this monitor to run in your environment you must update the username variable. In our environment, I had to precede the username with our domain name in order for it to return successful. The outlook-anywhere.sh script looks like this. It needs to be placed in /config/monitors with execute permission: 1: #!/bin/bash 2: # 3: # Exchange 2010 Outlook Anywhere external health monitor 4: # 5: # Syntax: /config/monitors/outlook-anywhere.sh 6: # 7: # Author: 8: # Date: 9: # 10: # Important Notes: 11: # * Username must be preceded by the "<domain>\" string 12: # * There should be four Variables configured in the monitor properties: 13: # - USERNAME: the user credentials used to perform the check 14: # - RECEIVESTRING: The string to look for in a successful response 15: # - DEBUG: Enables output debugging 16: # - DEBUGFILE: File which tores debug output (if DEBUG is enabled) 17: # * The password for USERNAME should only be stored in this file. This way, 18: # it is not accessible via TMSH commands or by viewing the LTM config file 19: # * To execute this script manually, uncomment the variables and execute 20: # the shell script. The output will be stored in DEBUGFILE. 21: # * CAUTION: If you execute this script manually, Make sure you comment 22: # the USERNAME, RECEIVESTRING, DEBUG, and DEBUGFILE variables (do not 23: # commend the PASSWORD variable). If you do not comment these variables, 24: # they will override the variables configured in the Monitor properties 25: # 26: # Revisions: 27: # 28: 29: # Do not comment out the PASSWORD variable 30: PASSWORD='<password>' 31: 32: # Uncomment these variables temporarily if you want to execute the 33: # script manually 34: #USERNAME='\' 35: #RECEIVESTRING='200 Success' 36: #DEBUG=1 37: #DEBUGFILE=/shared/tmp/outlook-anywhere_debug.log 38: 39: # Remove IPv6/IPv4 compatibility prefix (LTM passes addresses in IPv6 format) 40: IP=`echo ${1} | sed 's/::ffff://'` 41: PORT=${2} 42: 43: # Create a PID file 44: PIDFILE="/var/run/`basename ${0}`.${IP}_${PORT}.pid" 45: 46: # Kill of the last instance of this monitor if hung and log current pid 47: if [ -f $PIDFILE ] 48: then 49: kill -9 `cat $PIDFILE` >; /dev/null 2>&1 50: fi 51: echo "$$" >; $PIDFILE 52: 53: 54: if [ $DEBUG -eq 0 ] 55: then 56: 57: curl -v -k --request RPC_IN_DATA -A MSRPC -u "${USERNAME}:${PASSWORD}" --ntlm -H "Host: <hostname>" "https://${IP}/rpc/rpcproxy.dll?:6001" 2>;&1 | grep -ic "${RECEIVESTRING}" > /dev/null 2>&1 58: 59: else 60: 61: echo "*******************" 2>;&1 > "${DEBUGFILE}" 62: echo -e "curl -v -k --request RPC_IN_DATA -A MSRPC -u '${USERNAME}:${PASSWORD}' --ntlm -H \"Host: <hostname>\" \"https://${IP}/rpc/rpcproxy.dll?:6001\" 2>&1 | grep '200 Success'\n" 2>;&1 >> "${DEBUGFILE}" 63: echo "USERNAME: ${USERNAME}" 2>;&1 >> "${DEBUGFILE}" 64: echo "PASSWORD: ${PASSWORD}" 2>;&1 >> "${DEBUGFILE}" 65: echo "RECEIVESTRING: ${RECEIVESTRING}" 2>;&1 >> "${DEBUGFILE}" 66: echo "DEBUG: ${DEBUG}" 2>;&1 >> "${DEBUGFILE}" 67: echo "DEBUGFILE: ${DEBUGFILE}" 2>;&1 >> "${DEBUGFILE}" 68: echo -e "*******************\n" 2>;&1 >> "${DEBUGFILE}" 69: 70: curl -v -k --request RPC_IN_DATA -A MSRPC -u "${USERNAME}:${PASSWORD}" --ntlm -H "Host: <hostname>" "https://${IP}/rpc/rpcproxy.dll?:6001" 2>;&1 | tee -a "${DEBUGFILE}" | grep -ic "${RECEIVESTRING}" > /dev/null 2>&1 71: fi 72: 73: # Retain the return code of the grep command. 74: EXITCODE=$? 75: 76: # Need to remove PIDFILE here because the LTM terminates the script after 77: # receiving anythin in STDOUT 78: rm -f $PIDFILE 79: 80: if [ $EXITCODE -eq 0 ] 81: then 82: echo "UP" 83: fi In order to get this script to run in your environment you must update the PASSWORD variable, and insert your <hostname> into Host: header and the URI string in all three CURL command references. To execute the script manually, you must define the variables that are normally passed by the LTM by uncommenting them near the top of the script. If you do uncomment these variables, make sure you comment them out when you are finished or they will override the variables in the Monitor definition: USERNAME RECEIVESTRING DEBUG (if desired) DEBUGFILE (if DEBUG desired)462Views0likes3CommentsCitrix XenApp 5.0 Implementation Tips
I recently had the pleasure of working on a Citrix 5.0 implementation and I wanted to share a few things that I learned during that setup. As many of you know, there are two deployment guides that have been made available by F5 Networks in regards to setting up Citrix Presentation Server 4.5 in TMOS versions 9.x and 10.x. They are excellent guides and the best thing about them is that you can utilize those guides to assist you in deploying Citrix XenApp 5.0, with a few exceptions of course. Those exceptions are what I will be covering in this tech tip. Both of the previously mentioned deployment guides discuss editing files on the Citrix farms Web Interface servers so that it looks for the client IP address in the X-Forwarded-For HTTP header. Otherwise, every connection will appear to be originating from the BIG-IP LTM and not from its true IP. After reading both guides and looking at my current environment I was dismayed to find that the files and locations mentioned were no longer valid. I then turned to my top three resources on the web in the search for an answer: AskF5, DevCentral and Google. I struck out on the first two (which seldom happens) but my Google search did turn up some interesting results on the Citrix Forums. I finally found some code posted by Sam Jacobs back in August 2009 that modifies the way the Citrix farm looks up the client IP address. His method allows for the use of the X-Forwarded-For header. The first file that you will want to find and edit is the Include.java file. You will want to locate and change this file on every Web Interface XenApp server in the farm. Speaking from experience, save a copy of the original file to a safe location such as your desktop or flash drive. DO NOT copy the file and rename the original to Include.old and leave it on the server. It may sound crazy, but doing that will not work. I’m not a programmer, so I cannot tell you why that will not work, but I can tell you I know for a fact it will not. That being said, here is the file path for the Include.java file: “\Inetpub\wwwroot\Citrix\XenApp\app_code\PagesJava\com\citrix\wi\pageutils\Include.java” Now that you have found the file, open it up with a text editor (I use Textpad) and find the Java routine named “getClientAddress”. Replace the code for that routine with the code listed below. public static String getClientAddress(WIContext wiContext) { String ageClientAddress = AGEUtilities.getAGEClientIPAddress(wiContext); String userIPAddress = wiContext.getWebAbstraction().getRequestHeader("X-FORWARDED-FOR"); if (userIPAddress == null) { userIPAddress = wiContext.getWebAbstraction().getUserHostAddress(); } return (ageClientAddress != null ? ageClientAddress : userIPAddress); } Save the file and wash/rinse/repeat this step on every Web Interface server in the farm. The next thing that you will want to do is to modify the login page so that it displays the client IP address being obtained from the X-Forwarded-For header. The file you will want to edit is called “loginView.ascx” and can be found in the following file path on your Web Interface Servers: ”\inetpub\wwwroot\Citrix\XenApp\app_data\include\loginView.ascx” The code you will want to add is: Client IP: <%= com.citrix.wi.pageutils.Include.getClientAddress(wiContext) %> I added the code directly below the LoginPageControl viewControl line and it works well for me. Save the file and repeat this step on every Web Interface server in the farm and reboot each Web Interface Server after you are done. That’s it! Well, you do have to complete the other setup steps listed in the deployment guide that you are using, but after that your farm will be ready for business! I am aiming to develop some custom monitors for the Web Interface Server and for the XML Broker Servers over the next few weeks. Once I have those done I will put them out in the forums for the community enjoy. -naladar601Views0likes6CommentsiControl Development with BIG-IP LTM VE - Part 2
So now that we've got a vLTM installed and running, what can we do with it... There's a lot of examples out there of perl, python and Java. But not a lot of C... I've also got an iPhone... Sadly we can't use my favourite SOAP programming language on the iPhone. In case you're wondering that's perl. Why perl? Well, mainly I'm a bit lazy, and perl does everything for you... Obviously you're more productive when that's the case, and the SOAP::Lite module has spoiled me for years I'm afraid, but it's time to do some hacking (And in the early days it gets quite ugly) in what I'd consider to be a rather obscure variant of C. Yes, it's Objective-C... Like I've mentioned, the network map is a cool feature. One page showing your BigIP status. Virtual Servers, Default Pools, iRules, PoolMembers etc... Wouldn't that be nice on your iPhone? (Or better yet, your iPad). Obviously some things need to be altered a bit, the iPhone screen isn't exactly the best for viewing a lot of information at once, but it's nice to be able to pull it out of your pocket and quickly check the status when in a meeting... But this isn't about iPhone programming. It's about getting your iPhone to talk to BigIP. And for that we use iControl. The F5 SOAP API to monitor and control an F5 appliance. Opening a connection First off. How to talk to the F5... Well, iControl is a SOAP interface. And this is based upon HTTP. Basically we open an HTTPS connection to the iControl server and send it a few pages of XML that tell it what we want it to do. Then it sends us several more pages of XML to tell us the 4 or so lines we wanted to know... (In case you get the opinion I think SOAP and XML are a wee bit excessive, you're probably right). In objective-C we do something like this -(XMLNode *)queryF5:(NSString *)operation namespace:(NSString *)namespace params:(NSMutableDictionary *)params { NSString *targetURL = [NSString stringWithFormat: @"https://%@:%@@%@:443/iControl/iControlPortal.cgi", adminUser, adminPass, managementHost]; NSMutableURLRequest *req = [SOAPRequest requestForOperation:operation atURL:[NSURL URLWithString: targetURL] withNamespace:namespace withParameters:params]; [req setTimeoutInterval:10]; NSURLResponse *resp; NSData *respData = [NSURLConnection sendSynchronousRequest:req returningResponse:&resp error:nil]; NSString *debugString = [[NSString alloc] initWithData:respData encoding:NSUTF8StringEncoding]; if (respData == nil) { // Error while sending SOAP request"); return nil; } // Successfully sent SOAP request, getting response XMLNode *response = [SOAPResponse responseWi return response; } What does this do? Well, ignoring the fact that some of the variables are seemingly appearing out of thin air (They're not really, they are class member variables. e.g. the adminUser, adminPass etc). First we setup the URL we want to talk to. That's the string "https://%@:%@@%@:443/iControl/iControlPortal.cgi" and we replace all those %@'s with the adminUser, adminPassword and ManagementHost respectively. I'll leave the discussion of what those variables actually are to their descriptive names. But basically we're accessing a URL using (semi) standard URL format. Note that the semi-standard nature of this format is due to the fact that the user:password@host is not actually a part of the HTTP standards. It's an extension made popular by usage only. And luckily the F5's recognise and respond to it. Even though I said this wasn't about iPhone programming, in iPhone world, there is one extra piece of work we have to do. By default an F5 uses a self-signed cert for the HTTPS connection we're using for iControl. And by default an iPhone the iPhone wants to verify the cert trust. Which of course it can't. So we need to over-ride the check. That's done with a piece of code I found on the net... @implementation NSURLRequest(DataController) + (BOOL)allowsAnyHTTPSCertificateForHost:(NSString *)host { return YES; // Should probably return YES only for a specific host } @end Which over-rides the certificate check for the NSURLRequest class we're using to make a SOAP request. Next Time Well. Next time I'll show an actual request and response. And the work that goes into decoding an XML response from a SOAP server. I'd doit in perl, but that's so easy, it's only worth a few lines of code and saying go for it... Doing it in C (Or objective-C in this case) is a fairly surprising piece of work. Other Random Notes Static IP's... Normally you'd run an LTM with either a full-blown DHCP/DDNS architecture, or with a static IP. Most likely a static IP. However in the vLTM world, we're presented with a DHCP configuration on the vLTM and an environment (IN VMWare Fusion) that doesn't really do DDNS, and has a nasty habit of allocating a new IP everytime you suspend your laptop... There are plenty of reasons that I like to run static IP's on my LTM's, but vLTM seems remarkably resistant to allowing this (It may be a bug?). The result is to configure a static IP I had to resort to the command line config utility... I haven't used that since v4...241Views0likes1CommentDynamic Intelligent Application Delivery in a Distributed Environment–Part 2
Designing for Fine Grained Control and Monitor in a Load Balanced Environment – Gathering Information If you haven’t read Dynamic Intelligent Application Delivery Part 1, start there first, as this is not a standalone article and won’t make much sense without proper context. All caught up now? Splendid! We use separate apps and a number of protocols to gather information from both the load balancing devices (F5 BigIP) and pool members (SunONE Directory) to aid in the dispatching of clients to pools and pool members. By necessity the apps are specific to the devices and servers being monitored but could be readily adapted to gather information from other network devices (Such as firewalls) or servers (Such as Apache HTTP, Tomcat, or Weblogic). ldapReporter The ldapReporter perl application (Codeshare entry: ldapReporter) is a small server dedicated app that runs on the pool member [1] and reports pool member ‘load’ to the database. Pool member load (weight) is calculated as weight=1000-$currentConnections - $backlog*10 - $waiters*10; and clamped to the range 0 - 1000 (Where 1000 = no load and 0 = fully loaded) where These stats are all gathered from the slapd process using a search on the ‘cn=monitor’ base The stats are presented to the database in the f5_poolmember table with the SQL update f5_poolmember set dynamicratio=?,dnrsettime=? where ipaddr=? and portnum=? where dynamicratio=weight dnrsettime=current epoch time ipaddr and portnum are provided on the commandline to ldapReporter. Once provided, the app sleeps again for an interval defined on the command line (The default interval is 60 seconds). [1] Although this is not a hard & fast rule. The ldapReporter app could run anywhere that has LDAP access to the poolmember being monitored as stats are gathered via LDAP over the network interface. walkF5Stats walkF5Stats is a medium sized perl application (Codeshare entry: walkF5Stats) that runs in a loop, and every 20 seconds (Configurable on the command line) polls a cluster of BigIP devices for statistics (Both system and those associated with the current configuration). Statistics are gathered via both iControl and SNMP. The walkF5Stats application updates both the database and the RRD’s used to keep historical stats. The stats gathered include the areas of Pools, PoolMembers, Virtual Servers, Networks & Interfaces, CPU & Memory, Profiles (SSL), HA and configuration sync status. Note: walkF5Stats is specific to F5 BigIP appliances Pools - Gather pool availability, traffic and connection stats PoolMembers - Gather poolmember availability, traffic and connection stats Virtual Servers - Gather virtual server availability, traffic and connection stats CPU & memory - Dependent on the BigIP version, gather memory and CPU counters for the host and individual CPU’s. SSL Profiles - Gather statistics (counters) for SSL profiles for hardware of software offloading of SSL connections Networks & Interfaces - Gather Byte counts and availability of networks and interfaces. Including VLAN’s and aggregated links HA & Config Sync Status - Gather the HA status (Active or Standby) and configuration sync status (In sync, local or remote changed) for saving in the DB Appendix – Database Tables db_state_engine table The db_state_engine table is the repository for the SE checks to be performed for the current running operational mode, and the actions involved based on the stateCheck and stateCheckTarget. The SQL access is by dblbsvcid (Service ID) and f5vsid (VS ID) sorted on priority for the current running operational mode (referenced from db_lbsvccluster.lbcurmodeind). db_service_action table db_service_action describes the actions to be taken in response to the flexible state engine checks, and also for operational mode changes (For both the fixed function and flexible state engine). db_ll_action table The db_ll_action table is used to describe multiple small actions that are part of a single larger service action. For example, when executing a CLASS_KEYVALUE action, the db_ll_action table describes the actual key/value pairs to be altered. Other service_actions also use the db_ll_action table to store parameters required for their specific actions (e.g. increment and decrement values, default pool names etc) db_staged_update table The db_staged_update table is used by the pmUpdater process to determine which changes are required to be processed out to devices. db_stager_proc table Related Articles Dynamic Intelligent Application Delivery in a Distributed ... Application Delivery Virtualization - dynamic data center Application Delivery Virtualization - dynamic provisioning Dynamic Infrastructure: The Cloud within the Cloud Application Delivery Virtualization - BIG-IP Dynamic Data Center Agility: F5 and MS System Center Operations ... Enabling The Dynamic Data Center with BIG-IP v10 – Part 3 Does a Dynamic Infrastructure Need ARP for Applications?212Views0likes0CommentsiControl Development with BIG-IP LTM VE – Part 1
Introduction The LTM VE is a lifesaver when it comes to developing applications that use the iControl interface, or for development of iRules. My main (personal) use of it so far is the development of applications that use the iControl interface. Although a real LTM appliance has until now been the obvious choice of development target, the sheer cost of dedicated hardware is a big barrier to independent developers. In this respect the LTM VE comes into its own as an easy to use anywhere device. As iControl is my focus, I'm not going to go much beyond setup and access via iControl. Certainly not into the realms of heavy duty load balancing and iRules at this time. Platform As a dedicated Linux user (Mac's are just a hobby), there is an obvious choice for hosting LTM VE. VMWare Server. The kind people at VMWare are kind enough to offer free licenses for use of VMWare Server, so that's the target. To grab yourself a copy of the VMWare Server, just go to vmware.com and download. The kind people will send you a license key for free, and away you go. Magic! What about the Mac? VMWare also has a Mac option. VMWare Fusion. However beyond a 30 day license, you have to purchase the ability to run it. Why? Windows and Linux are free... Is there some reason Mac users are excluded from that club? While I'm not beyond putting my hand in my pocket for more toys, I already have a Parallels Desktop license on my macbook, so purchasing a VMWare license seems a little wasteful. Unfortunately, LTM VE doesn't support Parallels (Mainly due to the fact that VMWare emulates a PCnet32 ethernet card for eth0. So the LTM VE has pcnet32 modules. The Parallels VM uses a Realtek RTL-8029 and there's no drivers included in the current LTM VE. Maybe some playing around later and I could create or force load a driver from another distribution, but that needs some spare time). hamish@debian:~$ lspci 00:00.0 Host bridge: Intel Corporation 82P965/G965 Memory Controller Hub (rev 02) 00:01.0 PCI bridge: Intel Corporation 82G35 Express PCI Express Root Port (rev 02) 00:03.0 Class ff00: Device 1ab8:4000 00:05.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL-8029(AS) 00:0a.0 PCI bridge: Digital Equipment Corporation DECchip 21150 00:1d.0 USB Controller: Intel Corporation 82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #1 (rev 02) 00:1d.7 USB Controller: Intel Corporation 82801FB/FBM/FR/FW/FRW (ICH6 Family) USB2 EHCI Controller (rev 02) 00:1e.0 PCI bridge: Intel Corporation 82801 PCI Bridge (rev f2) 00:1f.0 ISA bridge: Intel Corporation 82801HB/HR (ICH8/R) LPC Interface Controller (rev 02) 00:1f.1 IDE interface: Intel Corporation 82801BA IDE U100 Controller (rev 05) 00:1f.4 Multimedia audio controller: Intel Corporation 82801BA/BAM AC'97 Audio Controller (rev 02) 01:00.0 VGA compatible controller: Device 1ab8:4005 lspci output from Parallels 4 [root@localhost:Active] config # lspci 00:00.0 Host bridge: Intel Corporation 440BX/ZX/DX - 82443BX/ZX/DX Host bridge (rev 01) 00:01.0 PCI bridge: Intel Corporation 440BX/ZX/DX - 82443BX/ZX/DX AGP bridge (rev 01) 00:07.0 ISA bridge: Intel Corporation 82371AB/EB/MB PIIX4 ISA (rev 08) 00:07.1 IDE interface: Intel Corporation 82371AB/EB/MB PIIX4 IDE (rev 01) 00:07.3 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 08) 00:0f.0 VGA compatible controller: VMware SVGA II Adapter 00:10.0 Ethernet controller: Advanced Micro Devices [AMD] 79c970 [PCnet32 LANCE] (rev 10) 00:11.0 Ethernet controller: Intel Corporation 82545EM Gigabit Ethernet Controller (Copper) (rev 01) 00:12.0 Ethernet controller: Intel Corporation 82545EM Gigabit Ethernet Controller (Copper) (rev 01) [root@localhost:Active] config # lspci output from VMWare Server There is possibly another way to do this for free on a Mac... One I didn't try... Run LTM VE on VMWare Server, under Linux, on a Parallels hosted VM... Two levels of VM... Maybe next week... What Now? If we ignore the other necessary bits such as licensing (There's plenty of other descriptions on licensing a BigIP installation), we have a VMWare Server... Remote I know, until I buy a real copy of VMWare Fusion to run it locally again on my laptop. And what do we want to do? Well the reason I want a LTM VE is to develop software. In the past I've used exclusively perl to access the iControl interface on F5's, but now I want to practice a bit of iPhone programming. And a conversation on one of the devcentral forums led to a small challenge. Can we write an app to show F5 status from an iPhone? An iPhone network-map for the F5. A Small Change to the iControl Server As we're developing an app in C (OK, Objective-C) on a small platform, one thing we really want to be able to do is to tcpdump the packets between the client (iPhone app) and the server (F5) for debugging (Especially since objective-C doesn't include SOAP support as native). And be able to decode it. Now because the traffic is SSL or TLS, you could use ssldump. But you need access to the key to decode the SSL traffic. And perform the dump on the F5 everytime, because Mac's don't come with ssldump by default. So it's easier (And more portable) to just enable HTTP traffic on the iControl server. Luckily the iControl web server is Apache. Which makes the change as easy as editing the main apache config file /etc/httpd/conf/httpd.conf and altering the line that says Listen localhost:80 to Listen 0.0.0.0:80 and performing bigstart restart httpd which means that the apache server now listens for unencrypted (Port 80) HTTP traffic on the wildcard address of 0.0.0.0 (Or *) instead of localhost (127.0.0.1). And it's up... And that's all there is to it. Now we have a LTM VE available on the network with an insecure (clear text) iControl interface ready for easy debugging... What's Left? Console Access. Remember I'm using a Mac. And VMWare Server on a remote linux server. With VMWare Fusion, it's all built in to the Mac, but the interface for a remote VMWare server is via a web browser, and this requires a VMWare plugin for your browser to connect to the client console. Unfortunately this doesn't include a Mac client. What to do... The answer it appears is VNC. A hidden ability of VMWare server is to use a VNC client/server arrangement for the client console. Simply find the .vmx (VMWare Config) file for the VM and add the following lines RemoteDisplay.vnc.enabled="TRUE" RemoteDisplay.vnc.port="5900" RemoteDisplay.vnc.password="somepassword" and when the client VM is running you can connect to the console via your favourite VNC client (I currently use “Chicken of the VNC')342Views0likes1Comment