Forum Discussion

rajeshgoud's avatar
rajeshgoud
Icon for Altostratus rankAltostratus
Mar 09, 2016

maintenance page for VIP with different hosts point to different pools if available else redirect to http://$host/maintenance

when HTTP_REQUEST {

sets the timer to return client to host URL set stime 10

Check if the URI is /maintenance switch [HTTP::uri] {

 

  "/maintenance" {


      Send an HTTP 200 response with a Javascript meta-refresh pointing to the host using a refresh time
     HTTP::respond 200 content \

 

"Maintenance page\

Sorry! This site is down for maintenance.

" "Content-Type" "text/html" return } } If the respective pool is down, redirect to the maintenance page else send the request to the respective pool if { [ string length [HTTP::host] eq test.com ] && [ active_members test_PROD_V ] < 1 } { log local0. $host HTTP::redirect "http://$host/maintenance" return } else { [ pool test_PROD_V ] } }

but I am getting error 01070151:3: Rule [TEST_IRULE] error: line 20: [wrong args] [string length [HTTP::host] eq test.com ] , can anyone suggested what is wrong with my iRule

6 Replies

  • Expanding on @arpydays' answer, the conditional clause is incorrect in a few ways. I'm reproducing your code here in a marked up block with comments after:

     

    when HTTP_REQUEST {
         sets the timer to return client to host URL set stime 10
         Check if the URI is /maintenance
        switch [HTTP::uri] {
            "/maintenance" {
                 Send an HTTP 200 response with a Javascript meta-refresh pointing to the host using a refresh time
                HTTP::respond 200 content \
                    " \
                    Sorry! This site is down for maintenance." "Content-Type" "text/html" 
                return
            }
        }
        
         If the respective pool is down, redirect to the maintenance page else 
         send the request to the respective pool 
        if { [ string length [HTTP::host] eq test.com ] && [ active_members test_PROD_V ] < 1 } { 
            log local0. $host 
            HTTP::redirect "http://$host/maintenance" 
            return 
        } else {
            [ pool test_PROD_V ] 
        } 
    }
    

     

    You have used the evaluation operator (the square brackets -- [...]) in a number of places where it will have an unintended effect and will produce runtime errors.

    To explain, the evaluation operator assumes its contents are a valid Tcl statement and evaluates it, substituting the result of the evaluation in place of the operator. From there, normal Tcl processing continues. So, let's say you do this:

    if { [string tolower [HTTP::host]] eq "test.com" } {

    the runtime expands inside-out. So, HTTP::host is evaluated first. That command results in a string. Let's say that it yields the value "test.com". If so, after this first expansion, the statement now looks like this:

    if { [string tolower test.com] eq "test.com" } {

    The remaining evaluation operator is expanded, yielding this:

    if { test.com eq "test.com" } {

    The runtime then executes the if command. That's what you expect and want. But let's consider your final statement:

    [pool test_PROD_V]

    This evaluates the pool command, which results in something (I'm not sure what it is, but I'm guessing it's a integer). Let's assume it is an integer. After the expansion, you'll have something like this:

    1

    Well, the runtime treats every line as a statement. Every statement is a command followed by one or more argument. So, it tries to evaluate the command called "1". There is no such command, so a runtime error is thrown.

    It's important to understand that the evaluation operator is not needed to force Tcl to execute a command. Every time Tcl sees a line, it will treat it as a command followed by zero or more arguments. The evaluation operator is only needed when you want to have Tcl evaluate a command that is embedded inside of a statement.

    Given all of this, your if clause should look like this:

    if { [string tolower [HTTP::host]] eq "test.com" && [active_members test_PROD_V] < 1 } {

    and, as I say, your final statement should simply be:

    pool test_PROD_V

    • rajeshgoud's avatar
      rajeshgoud
      Icon for Altostratus rankAltostratus
      Thanks Vernon, yes...I corrected them but the issue was when I added additional host header I site is inaccessible
  • Another point to simplify the configuration. use relative links in redirect instead of absolute if it is on the same Web service...

    Replace :

    HTTP::redirect "http://$host/maintenance"

    By :

    HTTP::redirect "/maintenance"

    And with the auto refresh in the javascript, redirect to the previous URL for a better user experience..

     

    when HTTP_REQUEST {
         Check if the URI is /maintenance
        switch [HTTP::uri] {
            "/maintenance" {
                 sets the timer to return client to host URL 
                set stime 10
                 Send an HTTP 200 response with a Javascript meta-refresh pointing to the host using a refresh time
                HTTP::respond 200 content \
                    " \
                    Sorry! This site is down for maintenance." "Content-Type" "text/html" 
                return
            }
        }
    
         If the respective pool is down, redirect to the maintenance page else 
         send the request to the respective pool 
        if { [ string length [HTTP::host] eq test.com ] && [ active_members test_PROD_V ] < 1 } { 
            log local0. $host 
            HTTP::redirect "http://$host/maintenance?uri=[HTTP::uri]" 
            return 
        } else {
            pool test_PROD_V
        } 
    }
    

     

    The following irule is one configured for some customers:

     

    when HTTP_REQUEST {
        switch [HTTP::path] {
            "/maintenance/logo.png" {
                HTTP::respond 200 content [ifile get "logo.png"] "Content-Type" "image/png"
                return
            }
            "/maintenance/maintenance.html" {
                HTTP::respond 200 content [ifile get "maintenance.html"] "Content-Type" "text/html"
                return
            }
            "/maintenance/error.html" {
                HTTP::respond 200 content [ifile get "error.html"] "Content-Type" "text/html"
                return
            }
            default {
                set dpool [LB::server pool]
                if { $dpool equals "" } { HTTP::redirect "/maintenance/error.html" ; unset dpool; return}
                if { [active_members $dpool] == 0 } { HTTP::redirect "/maintenance/maintenance.html"; unset dpool; return}
                unset dpool
            }
        }
    }
    
    when HTTP_RESPONSE {
      if { [HTTP::status] eq "404" } { HTTP::redirect "/maintenance/error.html" }
    }
    

     

  • Do you mean this irule ?

     

    when HTTP_REQUEST {
         Check if the URI is /maintenance
        switch [HTTP::uri] {
            "/maintenance" {
                 sets the timer to return client to host URL 
                set stime 10
                 Send an HTTP 200 response with a Javascript meta-refresh pointing to the host using a refresh time
                HTTP::respond 200 content \
                    " \
                    Sorry! This site is down for maintenance." "Content-Type" "text/html" 
                return
            }
        }
    
         If the respective pool is down, redirect to the maintenance page else 
         send the request to the respective pool 
        if { [ active_members [LB::server pool] ] < 1 } { 
            log local0. $host 
            HTTP::redirect "/maintenance?uri=[HTTP::uri]" 
            return 
        }
    }
    

     

  • Hi All, Thank you for the reply, since I am using multiple host to pool iRule, I used the fallback host option to redirect to maintenance page by creating a maintenance VIP on the Load balancer. Thanks and Regards Rajesh Goud M