There are times when you need to fail over redundant systems from within code - for app upgrades or network changes or what-have you. iControl gives you the power to find out information about the peering arrangements of your device and to fail over devices and fail them back.

While most of this process is relatively straight-forward iControl coding, there are a couple of areas where knowledge of what is going on can save you a lot of time and headaches. This short two-part series will help you write a set of management routines using the base iControl API to control the Failover settings of your BIG-IPs.

The concept is simple... When configured as redundant, One BIG-IP can take over the workload of another if things go wrong. Through the UI and command line you have an impressive amount of control over this process, being able to set the peer groupings and change the status of BIG-IPs at will. As is true with all things BIG-IP, you have this impressive level of control in the iControl API also - perhaps even more control due to the granularity of the API.

With BIG-IP, a device keeps track of it's current state (active or standby), it's peers (in a list of strings), and its current peering mode (active-active or active-passive). This article will show you how to get at these values from iControl. While we are doing this as a prelude to writing an actual application to exert control over the redundant systems, the routines presented in this article are also useful for testing your configuration.

It is always wise to make certain that you know for a fact what you are working with before beginning work. If I accept a job as an architect (my current title) and discover that I now work for a construction firm doing drawings, well, I failed to do my research. The same is true with code. Make certain you know what you are working with before beginning work. So  we start with the simplest of calls, a routine that determines if this machine is even part of a peering arrangement.

This example (and the companion article) is written with Java utilizing the core iControl API. This code will run with only minor modifications in the language of your choice (well, a .NET language anyway, it will take more work to get it going in Perl or PHP), and will work just fine within the context of the Java Wrappers Project. We chose not to use the wrappers so that the example would be more widely applicable, but remember that the wrappers accept all iControl calls, so this code works for them also.

iControl.System::Failover::is_redundant() returns a boolean that tells whether this machine is part of a peering arrangement.

In this source, you have the standard connection work that every call to iControl must make, and a call to is_redundant. The only oddity in this case is our use of fullUrl, which is assumed to be formatted as a connection string to your BIG-IP.

 

public static boolean checkRedundant() {
    SystemFailoverBindingStub stub;
    boolean ret = false;

    try {
        stub = (SystemFailoverBindingStub) new SystemFailoverLocator().getSystemFailoverPort(new URL(fullUrl));
        stub.setTimeout(6000);
        ret = stub.is_redundant();
    } catch (Exception e) {
        System.out.println("isRedundant Error: " + e.getLocalizedMessage());
    }
    return ret;
    }



If the return value from this call is true, then the BIG-IP is part of a redundant pair. If it returns false, the BIG-IP is running in standalone mode. If running in standalone mode, then we're done - none of the other routines will have useful information for us because they're all focused on redundant pair configurations.

Next, we want to find the address of our peer. While not strictly necessary, in our final article one option will be for a status update, in which case we will want to display this information.

 

public static String findPeer() {

    SystemFailoverBindingStub stub;

    String ret[] = {"No peer found"};

    try {

        stub = (SystemFailoverBindingStub) new SystemFailoverLocator().getSystemFailoverPort(new URL(fullUrl));

        stub.setTimeout(6000);

        ret = stub.get_peer_address();

    } catch (Exception e) {

        System.out.println("Peering Error: " + e.getLocalizedMessage());

    }

    return ret[0];

}

Again note that we're handling all of the normal iControl calls with just the method in quesiton (get_peer_address()) and the exception being different. get_peer_address() returns an array of Strings, but since we're looking at a redundant pair, I merely strip out the first element of that array and return it.

Next up is the failover mode - how is this BIG-IP and its peer configured to handle failover. The two possible values are active-passive - where one is a backup for the other - and active-active - where both are processing requests, and if one fails it can take over the workload of the other. A note of caution here, if the sum total of an active-active pair is greater than 100% utilization, you can imagine what will happen when one of them goes down. Still, some processing is better than no processing... But we're checking these values, not setting them, so we'll not delve into the relative strengths and weaknesses of the two arrangements.

public static SystemFailoverFailoverMode checkMode() {

    SystemFailoverBindingStub stub;

    SystemFailoverFailoverMode ret = SystemFailoverFailoverMode.FAILOVER_MODE_ACTIVE_ACTIVE;

    try {

        stub = (SystemFailoverBindingStub) new SystemFailoverLocator().getSystemFailoverPort(new URL(fullUrl));

        stub.setTimeout(6000);

        ret = stub.get_failover_mode();

    } catch (Exception e) {

        System.out.println("Mode Error: " + e.getLocalizedMessage());

    }

    return ret;

}

Another straight-forward implementation that simply asks what the mode is and returns it. Note that the mode is an iControl structure, so you will have to call retVal.toString() or retVal.getValue() on it when this method returns to get something you can print.

Now we know that it is part of a redundant pair, what the IP Address of the other unit in the pair is, and what style of failover they've implemented. The last question we need to answer is "what is the current state of this device?" iControl lets us discover this information with the get_failover_state() interface.

public static SystemFailoverFailoverState checkFailoverState() {

    SystemFailoverBindingStub stub;

    SystemFailoverFailoverState ret = SystemFailoverFailoverState.FAILOVER_STATE_ACTIVE;

    try {

        stub = (SystemFailoverBindingStub) new SystemFailoverLocator().getSystemFailoverPort(new URL(fullUrl));

        stub.setTimeout(6000);

        ret = stub.get_failover_state();

    } catch (Exception e) {

        System.out.println("State Error: " + e.getLocalizedMessage());

    }

    return ret;

}


Again, we set this routine to return the iControl structure, but you're likely to want the String description of the state, so you will have to call .toString() or .getValue() to get the descriptor out in your calling routine.

That's it - we now know if it's part of an HA pair, what device is its partner, what mode the two are configured in, and what the current state of this device is. Next time we will use all of this information to manage selectively toggling devices up and down with a command line routine so that you can manage your BIG-IPs during upgrade cycles.

For today, we will leave you with a sample program that you can run to get the Failover information about your device. All of the above routines are included in this class, and it just needs to be compiled with the iControl library (and the XTrustProvider  if you do not have a system in place for this already) to run.


package f5Sample;
import iControl.SystemFailoverBindingStub;
import iControl.SystemFailoverLocator;
import iControl.SystemFailoverFailoverState;
import iControl.SystemFailoverFailoverMode;
import iControl.ManagementDBVariableBindingStub;
import iControl.ManagementDBVariableLocator;
import iControl.ManagementDBVariableVariableNameValue;
import java.net.URL;

/** * @author dmacvittie * */
public class FailoverMain {
    static String username, password, ipAddress, fullUrl;

 /** * @param args */
public static void main(String[] args) {
    System.setProperty("javax.net.ssl.trustStore", System.getProperty("user.home") + "/.keystore");
    XTrustProvider.install();
    // NOTE: Insert your connection data!!
    setInfo("USERNAME", "PASSWORD", "IP_OR_HOSTNAME");
    if(checkRedundant())
        System.out.println(ipAddress + " is part of a redundant pair.");
    else
        System.out.println(ipAddress + " is standalone.");
    SystemFailoverFailoverState failoverState = checkFailoverState();
    System.out.println("Current failover state is: " + failoverState.toString());
    String peer = findPeer();
    if(peer.length() > 0)
        System.out.println("Peer is at address: " + peer);
    else
        System.out.println("No peer found.");
}

public static void setInfo(String uname, String pword, String ip) {
    username = uname;
    password = pword;
    ipAddress = ip;
    fullUrl = "https://" + username + ":" + password + "@" + ipAddress + "/iControl/iControlPortal.cgi";
}

public static boolean checkRedundant() {
    SystemFailoverBindingStub stub;
    boolean ret = false;
    try {
        stub = (SystemFailoverBindingStub) new SystemFailoverLocator().getSystemFailoverPort(new URL(fullUrl));
        stub.setTimeout(6000);
        ret = stub.is_redundant();
    } catch (Exception e) {
        System.out.println("isRedundant Error: " + e.getLocalizedMessage());
    }
    return ret;
}

public static SystemFailoverFailoverState checkFailoverState() {
    SystemFailoverBindingStub stub;
    SystemFailoverFailoverState ret = SystemFailoverFailoverState.FAILOVER_STATE_ACTIVE;
    try {
        stub = (SystemFailoverBindingStub) new SystemFailoverLocator().getSystemFailoverPort(new URL(fullUrl));
        stub.setTimeout(6000);
        ret = stub.get_failover_state();
    } catch (Exception e) {
        System.out.println("State Error: " + e.getLocalizedMessage());
    }
    return ret;
}

public static SystemFailoverFailoverMode checkMode() {
    SystemFailoverBindingStub stub;
    SystemFailoverFailoverMode ret = SystemFailoverFailoverMode.FAILOVER_MODE_ACTIVE_ACTIVE;
    try {
        stub = (SystemFailoverBindingStub) new SystemFailoverLocator().getSystemFailoverPort(new URL(fullUrl));
        stub.setTimeout(6000);
        ret = stub.get_failover_mode();
    } catch (Exception e) {
        System.out.println("Mode Error: " + e.getLocalizedMessage());
    }
    return ret;
}

public static String findPeer() {
    SystemFailoverBindingStub stub;
    String ret[] = {"No peer found"};
    try {
        stub = (SystemFailoverBindingStub) new SystemFailoverLocator().getSystemFailoverPort(new URL(fullUrl));
        stub.setTimeout(6000);
        ret = stub.get_peer_address();
    } catch (Exception e) {
        System.out.println("Peering Error: " + e.getLocalizedMessage()); } return ret[0];
    }
 }
}