#!/usr/bin/expect

# Expect script to grab cisco interface throughput, second by second
# by jwbensley@gmail.com
# If you don't like it, fuck off.

# Long delay for those tricky hostnames

set timeout 60

# Prompt user for device name/IP address, username, password,
# and interface to query (example: gi0/2)

send_user "Device name: "
expect_user -re "(.*)\n"
set host $expect_out(1,string)

send_user "Username: "
expect_user -re "(.*)\n"
set user $expect_out(1,string)

# Don't show the password it is typed
stty -echo
send_user "Password: "
expect_user -re "(.*)\n"
set pass $expect_out(1,string)
send_user "\n"
stty echo

send_user "SSH or telnet \[ssh\/telnet\]: "
expect_user -re "(.*)\n"
set protocol $expect_out(1,string)
# Use SSH as default
if { $protocol == ""} {
  set protocol "ssh"
}

send_user "show int "
expect_user -re "(.*)\n"
set intf $expect_out(1,string)
if { $intf == "" } {
  send_user "Need interface name\!\n"
  exit
}

send_user "Interval in seconds \[1\]: "
expect_user -re "(.*)\n"
set delay $expect_out(1,string)
# Use 1 second as the default intrace polling intrval if no value is giving
if { $delay == "" } {
  set delay 1
}
send_user "\n"


# Connect to the host and login
if { $protocol == "ssh" } {
  spawn ssh $host -l $user
  # Expect "assword:" as the 'p' in 'password' could be upper or lower case
  expect "assword:"
  send "$pass\r"
  expect "#"
  puts ""
} else {
  spawn telnet $host
  expect "Username:"
  send "$user\r"
  # Expect "assword:" as the 'p' in 'password' could be upper or lower case
  expect "assword:"
  send "$pass\r"
  expect "#"
  puts ""
}

# From this point on we shall disable user output or they will see the "show int x"
# command output constantly
log_user 0

# Grab the current in/out bytes before we start the loop, to get a starting figure
send "show int $intf\r"
expect "#"

set showint [open "showint" "w"]
puts $showint $expect_out(buffer)
close $showint

set inbytesnow [exec grep "packets input" \< showint | cut -d \  -f 9]
set outbytesnow [exec grep "packets output" \< showint | cut -d \  -f 9]
set outdropsnow [exec grep "output drops" \< showint | cut -d \  -f 10]

set inbyteslast $inbytesnow
set outbyteslast $outbytesnow
set outdropslast $outdropsnow

# These variables will be presented at the end of the script when the below
# SIGINT handler is called
set totalinbytes 0
set totaloutbytes 0
set totaloutdrops 0
set duration 0

# Here we will define a SIGINT handler, to catch the death of the script
# On exiting we shall pring out some session stats
proc sigint_handler {} {
  set inmegabytes [expr "$::totalinbytes" / 1000 / 1000]
  set outmegabytes [expr "$::totaloutbytes" / 1000 / 1000]
  puts "\nTotal duration $::duration seconds"
  puts "Total bytes received $::totalinbytes ($inmegabytes MBs)"
  puts "Total bytes sent $::totaloutbytes ($outmegabytes MBs)"
  puts "Total output drops $::totaloutdrops"
  puts "Average speed (bytes over duration)"
  set averagein [expr "$::totalinbytes" / "$::duration" / 1000 * 8]
  set averageout [expr "$::totaloutbytes" / "$::duration" / 1000 * 8]
  puts "In: $averagein Kbps \nOut: $averageout Kbps"
  exit
}
trap sigint_handler SIGINT

# Enter a continuous loop grabbing the number of bytes that
# have passed through an interface, each second.
# The different in this number each cycle, is essentially
# how much traffic this interface is pushing.

while { true } {
  send "show int $intf\r"
  expect "#"

  set showint [open "showint" "w"]
  puts $showint $expect_out(buffer)
  close $showint

  set inbytesnow [exec grep "packets input" \< showint | cut -d \  -f 9]

  # Declare $diff outside of the if statements
  set diff 0

  if { $inbytesnow > $inbyteslast } {
    set diff [expr $inbytesnow - $inbyteslast]
    set bps [expr "$diff" \* 8]
    set kbps [expr "$bps" \/ 1000]
    set kbps [expr "$kbps" \/ "$delay"]
  } elseif { $inbytesnow < $inbyteslast } {
    set diff [expr $inbyteslast - $inbytesnow]
    set bps [expr "$diff" \* 8]
    set kbps [expr "$bps" \/ 1000]
    set kbps [expr "$kbps" \/ "$delay"]
  } elseif { $inbytesnow == $inbyteslast } {
    set diff 0
    set kbps 0
  }

  # Keep a tally of the total bytes received for a stats dump at the end
  set totalinbytes [expr "$totalinbytes" + "$diff"]

  set inbyteslast $inbytesnow
  set inkbps $kbps

  set outbytesnow [exec grep "packets output" \< showint | cut -d \  -f 9]

  if { $outbytesnow > $outbyteslast } {
    set diff [expr $outbytesnow - $outbyteslast]
    set bps [expr "$diff" \* 8]
    set kbps [expr "$bps" \/ 1000]
    set kbps [expr "$kbps" \/ "$delay"]
  } elseif { $outbytesnow < $outbyteslast } {
    set diff [expr $outbyteslast - $outbytesnow]
    set bps [expr "$diff" \* 8]
    set kbps [expr "$bps" \/ 1000]
    set kbps [expr "$kbps" \/ "$delay"]
  } elseif { $outbytesnow == $outbyteslast } {
    set diff 0
    set kbps 0
  }

  # Keep a tally of the total bytes sent for a stats dump at the end
  set totaloutbytes [expr "$totaloutbytes" + "$diff"]

  set outbyteslast $outbytesnow
  set outkbps $kbps

  set outdropsnow [exec grep "output drops" \< showint | cut -d \  -f 10]

  if { $outdropsnow > $outdropslast } {
    set diff [expr $outdropsnow - $outdropslast]
  } elseif { $outdropsnow < $outdropslast } {
    set diff [expr $outdropslast - $outdropsnow]
  } elseif { $outdropsnow == $outdropslast } {
    set diff 0
  }

  # Keep a tally of the total output drops for a stats dump at the end
  set totaloutdrops [expr "$totaloutdrops" + "$diff"]

  set outdropslast $outdropsnow
  set outdrops $diff


  puts "Input: $inkbps Kbps Output: $outkbps Kbps Output drops: $outdrops\r"

  # Keep a record of the duration of this script for the stats dump at the end
  set duration [expr "$duration" + "$delay"]

  sleep $delay
}
