01. January 2017 · Comments Off on Custom 2x Orange Pi Zero Case · Categories: Cases, Design, Linux · Tags: , , , , , ,

The following is a 2x Orange Pi Zero case I designed in Inkscape and cut out in acrylic on my laser cutter… I have been incorporating a lot of single-board arm systems, like the Raspberry Pi, in my projects lately. Among one of my favorite boards to play with is the Orange Pi; due to its price, hardware design and power. I assisting some developers with one of their projects and wanted 2 headless systems. My solution was to get 2 Orange Pi Zero’s and set them up running armbian. Since a lot of people were handling the systems, I created a custom case to both protect and show off the systems.

Custom Orange Pi Zero Case

12. December 2016 · Comments Off on Convert Cisco APs from LWAP to Autonomous · Categories: Cisco, Networking, Wireless · Tags: , , ,

A lot of companies are pulling out their old Cisco wireless infrastructure to upgrade or replace it all together. As a result its pretty easy to get your hands on older Cisco AP’s, unfortunately by default they require a special controller in order to function. If you want to turn your old Cisco LWAP AP into something other than a paperweight, you either need to get an older controller or convert the AP to Autonomous. The following snippet is what I had to do to convert my Cisco AP from LWAP to Autonomous. Surprisingly they don’t cover this sort of thing on the CCNA wireless exam; or at least not back when I took it.

Before you begin, just make sure you get the proper “k9w7” autonomous code; bear in mind that “k9w8” is the lightweight code. In my case I had an old Aironet 1130 AG Access Point, so I had to get my hands on the c1130-k9w7-tar.124-25d.JA.tar code. I also needed to setup a TFTP server inside the same vlan as the AP. After I consoled into the AP and logged in to it I had to do the following…

debug lwapp console cli
debug lwapp client no-reload
config t
int fa 0
 ip address
archive download-sw /force-reload /overwrite tftp://

Over the last two years I have been involved in several successful migrations off of the Cisco ACE platform. While I do not consider myself an ACE expert I have discovered a nice filter option, albeit poorly documented, to display/isolate only the relevant configuration of a particular service-policy (EX: show running-config filter vip.example.com). This filter option is great for both migrations and copying configurations from one ACE to another; for when you need an identical DR VIP. Because of the general usefulness of being to quickly isolate parts of a configuration, I created a script to do the same for the F5. Just like the filter option on the ACE, this script will parse through an existing bigip.conf for a virtual server and display only required configuration items: virtual-address, pool, node, monitor, policy, profile & rules.


## Filter out a single F5 virtual server config on a BigIP.
## 2016 (v1.0) - Script from www.davideaves.com
### Print Syntax if arguments are not provided. ###
if [ ! -e "$F5CONFIG" ] || [ -z "$F5STANZA" ]
 echo "Usage: $0 bigip.conf example.domain.com_80_vs"
 exit 0;
### The function that does all the filtering. ###
 sed -n -e '/^ltm .*'"$(echo $F5STANZA | sed 's/\//\\\//g')"' {$/,/^}$/ p' $F5CONFIG
### Build Search commands to run after loop finishes ###
F5FILTER "$F5CONFIG" "$F5STANZA" | while read A B C D
  ### Stanza: policy, profile, rule
  if [ -n "LCOUNT" -a "$(echo $A | cut -c1)" == "/" ]
   then echo "$LCOUNT|$A" | grep -v ":[0-9]"
        let LCOUNT++
  ### Stanza: virtual server ###
  elif [ "$A" == "ltm" -a "$B" == "virtual" ]
   then echo "80|$B $C"
  ### Stanza: pool ###
  elif [ "$A" == "pool" ]
   then F5STANZA="$(echo $B | awk -F'/' '{print $NF}')"
   echo "70|$A $B"
   # Dig inside of pool stanza #
   F5FILTER "$F5STANZA" | while read A B C D
    do  if [ "$A" == "monitor" ]
         then echo "40|$B"
        elif [ "$(echo $A | cut -c1)" == "/" -a "$B" == "{" ]
         then echo "50|node $A" | grep ":[0-9]$" | awk -F':' '{print $1}'
  ### Stanza: virtual address ###
  elif [ "$A" == "destination" ]
   then echo "90|virtual-address $(echo $B | awk -F':' '{print $1}')"
  ### Stanza: LOOP ###
  elif [ "$B" == "{" -a -z "$C" ]
   then LCOUNT="10"
   [ "$A" == "policies" ] && { LCOUNT="20"; }
   [ "$A" == "rules" ] && { LCOUNT="30"; }
done | sort -n | uniq | while IFS="|" read SEQ F5STANZA
 do printf "#%.0s" {1..60}
    printf "\r### $SEQ: $F5STANZA \n"

There are a few limitations with this script… It will not pull out any objects referenced in policies or irules. It will also not pull out inherited profiles.

02. November 2016 · Comments Off on Display a LTM Network Map at the bash shell on a F5 BigIP. · Categories: F5, Linux, Linux Scripts, Load Balancing · Tags: , , , ,

I have been doing a bunch of F5 migrations lately and have gotten fond of the visualization of the network map in the F5 GUI. From the CLI to get the status of a VIP you have to parse tmsh output to find the information your looking for. As a personal challenge I wanted to make a script to be ran on the F5 to provide the exact same summary you see in the GUI, but instead form a bash shell…

Network MAP from the GUI


Network Map from the F5 bash shell, using this script



## Display a LTM Network Map at the bash shell on a F5 BigIP.
## 2016 (v1.0) - Script from www.davideaves.com
# Fix broken TERM variable if using screen.
[ "$TERM" == "screen-256color" ] && { export TERM="xterm-256color"; }
# Start: Collect time for runtime.
TIME=`date +%s`
# ANSI color variables.
esc="$(echo -e '\E')";  cCLS="${esc}[0m"
cfBLACK="${esc}[30m";   cbBLACK="${esc}[40m"
cfRED="${esc}[31m";     cbRED="${esc}[41m"
cfGREEN="${esc}[32m";   cbGREEN="${esc}[42m"
cfYELLOW="${esc}[33m";  cbYELLOW="${esc}[43m"
cfBLUE="${esc}[34m";    cbBLUE="${esc}[44m"
cfMAGENTA="${esc}[35m"; cbMAGENTA="${esc}[45m"
cfCYAN="${esc}[36m";    cbCYAN="${esc}[46m"
cfWHITE="${esc}[37m";   cbWHITE="${esc}[47m"
c1BOLD="${esc}[1m";     c0BOLD="${esc}[22m"
DIE() {
 ## End Script if error.
 echo "$c1BOLD""ERROR"" [$cbRED$ERR$cbBLACK]:$cCLS An error has been encountered."
 exit 1;
 ## Return component & identifier of an array element.
 [ -z "$ID" ] && { echo "READID: Varable \"\$ID\" not found."; exit 1; }
 [ -z "$MAP" ] && { echo "READID: Varable \"\$MAP\" not found."; exit 1; }
 export COMPONENT="$(echo ${MAP[$ID]} | awk -F':' '{printf $1}')"
 export IDENTIFIER="$(echo ${MAP[$ID]} | awk -F':' '{printf $2}')"
 ## Display status back to the user.
 [ -z "$STATUS" ] && { set > t; echo "STATUS: Varable \"\$STATUS\" not found."; exit 1; }
 if    [ "$STATUS" == "available enabled" ]; then printf -- "($c0BOLD$cfBLACK$cbGREEN@$cCLS) "
  elif [ "$STATUS" == "available disabled" ]; then printf -- "($c0BOLD$cfBLACK$cbBLUE@$cCLS) "
  elif [ "$STATUS" == "unknown enabled" ]; then printf -- "[$c0BOLD$cfBLACK$cbBLUE#$cCLS] "
  elif [ "$STATUS" == "offline disabled" ]; then printf -- "< $c0BOLD$cfBLACK$cbWHITE-$cCLS> "
  elif [ "$STATUS" == "offline enabled" ]; then printf -- "< $c0BOLD$cfBLACK$cbRED!$cCLS> "
  elif [ "$STATUS" == "available disabled-by-parent" ]; then printf -- "($c1BOLD$cfBLACK$cbWHITE@$cCLS) "
  elif [ "$STATUS" == "unknown disabled-by-parent" ]; then printf -- "[$c1BOLD$cfBLACK$cbWHITE#$cCLS] "
  elif [ "$STATUS" == "offline disabled-by-parent" ]; then printf -- "< $c1BOLD$cfBLACK$cbWHITE-$cCLS> "
  else printf "[ $STATUS ] "
# Validate script requirements are meet.
[ -f "/config/bigip.conf" ] && [ -x "/usr/bin/tmsh" ] || { DIE; }
### Main Loop ###
grep ^"ltm virtual .*"$1".* {$" "/config/bigip.conf" | awk '{print $(NF-1)}' | while read VS
 do ((ID=0))
  # Read VS into an array.
  MAP=( `tmsh show ltm virtual $VS detail | grep -e "Ltm::" -e "Availability" -e "State" | sed 's/|//g;s/ \+//g' | awk -F':' '{print $(NF-1)":"$NF}'` )
  # DEBUG #
  [ "$DEBUG" == "Y" ] && { echo "$cfBLACK$cbCYAN${MAP[*]}$cCLS"; echo; }
  # Display Virtual Server #
  STATUS="$(((ID=ID+1)); READID; printf "$IDENTIFIER") $(((ID=ID+2)); READID; printf "$IDENTIFIER")"
  printf -- "$(STATUS)"
  printf "$IDENTIFIER $(echo "${MAP[`expr ${#MAP[@]}-3`]}" | awk -F'(' '{print "("$NF}')\n"
  ### Iterate from right of MAP array ###
  while [ "$ID" -ge "1" ]
   do ((ID--)); READID
     # Display iRules #
     [ "$IDENTIFIER" == "HTTP_REQUEST" ] && { printf "   (*) $COMPONENT\n"; }
  ### Iterate from left of MAP array ###
  while [ "$ID" -le "${#MAP[@]}" ]
   do ((ID++)); READID
     # Display Nodes #
     if [ "$COMPONENT" == "Node" ]
        STATUS="$(((ID=ID-2)); READID; printf "$IDENTIFIER") $(((ID=ID-1)); READID; printf "$IDENTIFIER")"
        printf -- "      $(STATUS)"
        printf "$(((ID=ID-3)); READID; printf "$COMPONENT:$IDENTIFIER") "
        printf "$( echo $IDENTIFIER | awk -F'(' '{print "("$NF}')\n"
     # Display Pools #
     elif [ "$COMPONENT" == "Pool" ]
        STATUS="$(((ID=ID+1)); READID; printf "$IDENTIFIER") $(((ID=ID+2)); READID; printf "$IDENTIFIER")"
        printf -- "   $(STATUS)"
        printf "$IDENTIFIER\n"
  done; echo
done 2> /dev/null || DIE
# Done: Print status & runtime.
printf "Completed in $B$(expr `date +%s` - $TIME)$B0 seconds...$CLS\n"
19. October 2016 · Comments Off on Graphing radiation with a GMC-320 geiger counter using Cacti · Categories: Cacti, Linux, Linux Scripts

A few years ago, right after the Fukushima Daiichi nuclear disaster, XKCD released an awesome Radiation Dose Chart. Also around that time portable geiger counters became much easier to get a hold of and fairly cheap. Me being a data nerd; I researched a variety of devices and decided to get a CQ GMC-320. Its an awesome portable geiger counter that has a USB data-port on it that allows you to collect the CPM via a USB serial port. The following Cacti template and Python script is how I generated the following Graph.


Additional GMC-320 Links

This Cacti template will import/update the following items:


  • Trend
  • Geiger – sV [ALL]
  • Geiger – sV [AVG]
  • Geiger – mR [ALL]
  • Geiger – mR [AVG]


  • Normal
  • Exact Numbers
  • MicroSievert
  • Interger
  • MilliRoentgen

Data Input Method

  • GQ – GMC-320Re 3.22

Data Template

  • GQ – CPM

Graph Template

  • GMC-320 – CPM values