If you want to do A/B split testing with nginx, you usually are directed to the split clients module.

However, most of us don’t have this module compiled into their nginx installations and this usually results in using our code to do the actual A/B spliting.

Here is how you can do that, without the addition of other modules.

First you need to create a map that will hold your two URLs:

map $time_local $split_redirect {
# 27/Jul/2017:02:33:06 -0500
    "~[13579] \-.*$" @location1;
    "~[02468] \-.*$" @location2;

As you can see, I’m using the $time_local variable for the split. Everyone that access the site on even seconds will go to @location1 and the others to @location2. That is all the “magic” that you would need :)

Then you have two options :) First is to use if, but we know if is evil, so the second option is to use internal error redirects :)

    location ~ ^/page {
        recursive_error_pages on;
        error_page 412 = $split_redirect;
        return 412;
    }   

    location @location1 {
        internal;
        return 301 http://site/page1.html;
    }   

    location @location2 {
        internal;
        return 301 http://site/page2.html;
    }

if you decide to go the if route, here is how you should do it.

You need to change the map to have your locations:

map $time_local $split_redirect {
# 27/Jul/2017:02:33:06 -0500
    "~[13579] \-.*$" http://site/page1.html;;
    "~[02468] \-.*$" http://site/page2.html;;

and then simply add this if to your config:

    if ($split_redirect) {
        rewrite ^ $split_redirect permanent;
    }
Posted by HackMan
Dated: 27th July 2017
Filled Under: Uncategorized
Comments: Post the 1st one!

I’m using bird on my routers for a few years now, and every time I setup a new router I add these shell functions to help me monitor and debug network issues:

function bgp_states {
    for i in $(birdc show protocols|sed 's/\s\+/|/g'|grep BGP); do
        a=(${i//|/ })
        echo ${a[*]}|awk '{printf "%-16s\t%s\t%s\t%s\t%s\t%s\n", $1, $2, $3, $4, $5, $6;}'
        birdc show protocol all ${a[0]}|grep Routes
    done
}

function show_route {
    range=$1
    all=''
    if [[ $1 == for ]]; then range=$2; fi
    if [[ $1 == all ]]; then all='all'; range=$2; fi
    if [[ $range =~ [a-z] ]]; then
        range=$(host -t A $range|head -n1|cut -d ' ' -f 4)
    fi
    birdc show route $all for $range table main
}

function bgp_info {
    birdc "show protocols all $1"
}
Posted by HackMan
Dated: 5th April 2017
Filled Under: Uncategorized
Comments: Post the 1st one!

I was featured at PerlAdvent calendar 2016 with my article about controlling Linux Containers with Perl

The PerlAdvent calendar is a very nice way to countdown the days till Christmas :)

Posted by HackMan
Dated: 20th December 2016
Filled Under: Uncategorized
Comments: Post the 1st one!

Since CentOS 6.x is an old distro it lacks newer GCC and thus you can’t use things like stack protector and some of the PAX security stuff :(
What you can do however, is to install the SCL repo and from there the devtoolset-4:

# yum install centos-release-scl.noarch centos-release-scl-rh.noarch
# yum install devtoolset-4 devtoolset-4-gcc-plugin-devel.x86_64

The above will install gcc and g++ 5.2. But before jumping into building your kernel you need to also install:

# yum install libmpc-devel.x86_64 libmpc.x86_64

Which is needed for proper gcc-plugins support.
Now you can simply start building your kernel:

# scl enable devtoolset-4 bash
# cd /usr/src/kernels/linux-4.4.34
# make

Posted by HackMan
Dated: 22nd November 2016
Filled Under: CentOS, Linux General, Technology
Comments: Post the 1st one!

After yum or apt-get upgrade you are left with services that need to be restarted in order to start using the new libraries you have just upgraded.
Sometimes you know what to restart but if you haven’t done upgrade in a while it is highly possible that you can miss a service.
The following simple two liner will help you find the services you need to restart:

function check_restart() {
  all_maps=$(grep deleted /proc/[0-9]*/maps|grep -vE '\/(SYSV|dev\/)'|cut -d ':' -f1|sort|uniq)
  for i in $all_maps; do pid=${i/\/maps}; echo "${pid/*\/} $(cat ${i/maps/cmdline}|tr '\0' ' ')"; done|sort|uniq
}
Posted by HackMan
Dated: 22nd November 2016
Filled Under: Linux General, Technology
Comments: Post the 1st one!

Yesterday I had a very interesting conversation about congestion control and how it affects long lived connections.
So I decided to do a very simple comparison. I created a 100MB file(dd if=/dev/zero of=test-file bs=1M count=100).

  • Scalable:
  • test-file  100%[==============================================>] 100.00M 5.13MB/s in 23s
    2016-02-28 19:40:55 (4.35 MB/s) - ‘test-file’ saved [104857600/104857600]
    
  • Illinois:
  • test-file  100%[==============================================>] 100.00M 4.20MB/s in 24s
    2016-02-28 19:21:57 (4.13 MB/s) - ‘test-file’ saved [104857600/104857600]
    
  • Yeah:
  • test-file  100%[==============================================>] 100.00M 5.03MB/s in 25s
    2016-02-28 19:34:01 (4.02 MB/s) - ‘test-file’ saved [104857600/104857600]
    
  • Bic:
  • test-file  100%[==============================================>] 100.00M 1.98MB/s in 31s
    2016-02-28 19:39:34 (3.21 MB/s) - ‘test-file’ saved [104857600/104857600]
    
  • Htcp:
  • test-file  100%[==============================================>] 100.00M 2.76MB/s in 34s
    2016-02-28 19:36:12 (2.93 MB/s) - ‘test-file’ saved [104857600/104857600]
    
  • Cubic:
  • test-file  100%[==============================================>] 100.00M 1.54MB/s in 45s
    2016-02-28 19:30:23 (2.21 MB/s) - ‘test-file’ saved [104857600/104857600]
    
  • Hybla:
  • test-file  100%[==============================================>] 100.00M 1.52MB/s in 50s
    2016-02-28 19:38:31 (2.01 MB/s) - ‘test-file’ saved [104857600/104857600]
    
  • Westwood:
  • test-file  100%[==============================================>] 100.00M 2.81MB/s in 53s
    2016-02-28 19:35:26 (1.90 MB/s) - ‘test-file’ saved [104857600/104857600]
    
  • Reno:
  • test-file  100%[=============================================>] 100.00M 1.48MB/s in 62s
    2016-02-28 19:27:38 (1.62 MB/s) - ‘test-file’ saved [104857600/104857600]
    
  • Veno:
  • test-file  100%[=============================================>] 100.00M 1.22MB/s in 64s
    2016-02-28 19:23:14 (1.56 MB/s) - ‘test-file’ saved [104857600/104857600]
    
  • LP:
  • test-file  100%[=============================================>] 100.00M 1.24MB/s in 95s
    2016-02-28 19:32:54 (1.05 MB/s) - ‘test-file’ saved [104857600/104857600]
    

Some information on the best algorithms:

Posted by HackMan
Dated: 29th February 2016
Filled Under: Linux General, Networking, Technology
Comments: Post the 1st one!

Bird’s memory usage with 8 BGP sessions (6 of which full BGP tables):

root@sfgw:~# birdc show memory
BIRD 1.5.0 ready.
BIRD memory usage
Routing tables:    160 MB
Route attributes:  136 MB
ROA tables:        112  B
Protocols:          68 kB
Total:             295 MB

And here are the prefix stats:

root@sfgw:~# bgp_states
BIRD                    1.5.0   ready.
bgp_itd_backup          BGP     main    up      2016-02-16      Established
  Routes:         576411 imported, 1 exported, 21079 preferred
bgp_itd_main            BGP     main    up      2016-02-16      Established
  Routes:         576411 imported, 1 exported, 0 preferred
bgp_telehouse_main      BGP     main    up      2016-02-19      Established
  Routes:         576876 imported, 1 exported, 217446 preferred
bgp_telehouse_backup    BGP     main    up      2016-02-19      Established
  Routes:         470907 imported, 1 exported, 286422 preferred
bgp_evolink_main        BGP     main    up      2016-02-19      Established
  Routes:         576112 imported, 1 exported, 57281 preferred
bgp_evolink_backup      BGP     main    up      07:06:39        Established
  Routes:         576112 imported, 1 exported, 0 preferred
bgp_evolink_bg_backup   BGP     main    up      10:55:36        Established
  Routes:         9767 imported, 1 exported, 0 preferred
bgp_evolink_bg_main     BGP     main    up      10:56:32        Established
  Routes:         9767 imported, 1 exported, 536 preferred
Posted by HackMan
Dated: 23rd February 2016
Filled Under: Networking, Technology, Uncategorized
Comments: Post the 1st one!

I finally decided to request full BGP tables from all of my ISPs, so I can easily change the preferred path to certain destinations.

However this meant that now I have to monitor both the state of the BGP sessions, but also the amount of routes that I receive from my neighbors.

Before my days with full BGP tables I relied on this simple alias:

alias bgp_states='birdc show protocols|awk "/^BIRD|bgp/{printf \"%20s\t%s\t%s\t%s\t%s\t%s\n\", \$1, \$2, \$3, \$4, \$5, \$6}"'
alias bgp_states='birdc show protocols|column -t|grep -E "^BIRD|bgp"'

The above alias(with its two implementations), worked like charm and produced:

root@sfgw:~# bgp_states
BIRD                  1.5.0   ready.
bgp_itd_backup        BGP     main    up     2016-02-16  Established
bgp_evolink_main      BGP     main    up     2016-02-16  Established
bgp_evolink_backup    BGP     main    up     2016-02-16  Established
bgp_itd_main          BGP     main    up     2016-02-16  Established
bgp_telehouse_main    BGP     main    up     18:08:55    Established
bgp_telehouse_backup  BGP     main    up     18:09:25    Established
root@sfgw:~#

However, with full BGP tables, I needed a little bit more information. So I replaced the above aliases with this function:


function bgp_states {
    for i in $(birdc show protocols|grep -E "^BIRD|bgp"|sed 's/\s\+/|/g'); do
        a=( ${i//|/ })
        echo ${a[*]}|awk '{printf "%-16s\t%s\t%s\t%s\t%s\t%s\n", $1, $2, $3, $4, $5, $6;}'
        birdc show protocol all ${a[0]}|grep Routes
    done
}

I was lazy and didn’t want to implement it properly with while read or IFS. Maybe I’ll have version two for this function, also.

So its results are a bit more informative:

root@sfgw:~# bgp_states
BIRD                    1.5.0   ready.
bgp_itd_backup          BGP     main    up      2016-02-16      Established
  Routes:         575148 imported, 1 exported, 20951 preferred
bgp_evolink_main        BGP     main    up      2016-02-16      Established
  Routes:         1 imported, 1 exported, 0 preferred
bgp_evolink_backup      BGP     main    up      2016-02-16      Established
  Routes:         1 imported, 1 exported, 0 preferred
bgp_itd_main            BGP     main    up      2016-02-16      Established
  Routes:         575148 imported, 1 exported, 0 preferred
bgp_telehouse_main      BGP     main    up      18:08:55        Established
  Routes:         575939 imported, 1 exported, 233100 preferred
bgp_telehouse_backup    BGP     main    up      18:09:25        Established
  Routes:         472013 imported, 1 exported, 324399 preferred
root@sfgw:~#
Posted by HackMan
Dated: 19th February 2016
Filled Under: Linux General, Networking, Technology, Uncategorized
Comments: Post the 1st one!

Since I’m a long user of Xchat I decided to upgrade it and found that it does not compile with the recent glib library.

The problem is that the new versions of the glib library introduced one limitation for includes. Now you only have to include glib.h and every more specific inclusion breaks the builds.

Even thou I recently switched to HexChat I made a patch for Xchat 2.8.8, so it can compile with the newer glib version.

The patch is available here.

Posted by HackMan
Dated: 18th February 2016
Filled Under: Linux General, Technology
Comments: Post the 1st one!

Very often I login on machines with older mii-tool that reports 1Gbit/s cards as if they are connected on 100Mbit/s. This is normal as mii-tool is depricated. But a lot of old timers like me are used to its output. So I wrote a very simple awk script which can convert the ethtool output to the one liner output of mii-tool

if [ -z "$1" ]; then
    echo "Usage: mii-tool DEV"
    exit
fi
ethtool $1 2>&1|awk '
/Settings/{d=$3}
/Speed/{
    s=$2
    if (s !~ /Unknown/) {
        gsub(/Mb.*/,"",s)
        s=s"baseTx-"
    }
}
/Duplex/{
    if ($2 == "Full")
        s=s"FD"
    else
        s=s"HD"
}
/Link/{
    if ($3 == "yes")
        l="link ok"
    else
        l="no link"
}
/No data available/{err=1}
END{
    if (err) {
        gsub(/:/,"",d)
        print "SIOCGMIIPHY on \""d"\" failed: No such device"
        exit
    }
    if (s!~ /Unknown/)
        print d," "s", "l
    else
        print d, l
}'

And a shorter version for your .bashrc:
function mii-tool { ethtool $1|awk '/Settings/{d=$3}/Link/{if($3=="yes")l="link ok";else l="no link"}/Speed/{s=$2}/Duplex/{u=$2}END{if(s!~/Unknown/)print d," "s", "u", "l;else print d,l}'}

Posted by HackMan
Dated: 7th December 2015
Filled Under: Linux General, Technology
Comments: Post the 1st one!