From 044fba43d5aba4e53dcdafd2fc8063789fd5c7d4 Mon Sep 17 00:00:00 2001
From: Sebastian Rieger <sebastian.rieger@informatik.hs-fulda.de>
Date: Mon, 24 Oct 2016 20:53:39 +0200
Subject: [PATCH] new version to support VIRL >1.1 and VIRL clusters using
 websockets for console access

---
 virl-benchmark/check-reachability             |  64 ---------
 .../check-reachability-websocket.py           |  73 ++++++++++
 virl-benchmark/check-usability-of-sims        |  75 +++++++++++
 virl-benchmark/ports-vms.py                   | 127 ------------------
 virl-benchmark/start-virl-topology            |  69 +++++-----
 virl-benchmark/test-virl-telnet-connection    |  17 ---
 6 files changed, 179 insertions(+), 246 deletions(-)
 delete mode 100644 virl-benchmark/check-reachability
 create mode 100644 virl-benchmark/check-reachability-websocket.py
 create mode 100644 virl-benchmark/check-usability-of-sims
 delete mode 100644 virl-benchmark/ports-vms.py
 delete mode 100644 virl-benchmark/test-virl-telnet-connection

diff --git a/virl-benchmark/check-reachability b/virl-benchmark/check-reachability
deleted file mode 100644
index 7be31fc..0000000
--- a/virl-benchmark/check-reachability
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/bin/bash
-
-# Check reachability of all running VIRL VMs by logging in on the telnet console port and expect a prompt that includes the host name
-
-# usage
-if [ ! $# -gt 2 ] ; then
-  echo -e "usage: $0 <username> <timeout for telnet connection to each node> <simulation> [debug level], e.g.,\n"
-  echo "$0 guest VIRLBENCH-223721@smb-WaZLhH 5"
-  exit -1
-fi
-
-# get the IP address of eth0
-IP=$(ip addr show | grep eth0 | grep inet | tr -s " " | cut -d " " -f 3 | cut -d "/" -f 1)
-
-RUNNING=true
-
-USERNAME=$1
-TIMEOUT=$2
-SIMULATION=$3
-if [ $4 ]; then 
-  DEBUG=$4
-else
-  DEBUG=0
-fi
-
-while $RUNNING = true
-do
-# Check if all nodes are ready-to-use using expect
-
-  # get the telnet ports of all nodes in all simulations
-  VM_PORTS=$(./ports-vms.py $USERNAME $SIMULATION)
-  
-  # connect to every telnet port of each node and expect the hostname in the prompt
-  VMS_UNUSABLE=0
-  for VM_PORT in $VM_PORTS
-  do
-    VM_TELNET_PORT=$(echo $VM_PORT | cut -d "=" -f 2)
-    VM_NAME=$(echo $VM_PORT | cut -d "=" -f 1)
-    # connect to every telnet port and check whether it can be used by pressing return
-    # twice and expecting the hostname to appear in the resulting prompt each time
-    if [ $DEBUG -lt 2 ]; then
-    	./test-virl-telnet-connection $IP $VM_TELNET_PORT $VM_NAME $TIMEOUT >/dev/null
-    else
-    	./test-virl-telnet-connection $IP $VM_TELNET_PORT $VM_NAME $TIMEOUT
-    fi
-    EXPECT_EXITCODE=$?
-    if [ $EXPECT_EXITCODE -eq 5 ] ; then
-      VMS_UNUSABLE=$(expr $VMS_UNUSABLE + 1)
-      if [ $DEBUG -gt 0 ]; then echo "$VM_NAME ($VM_TELNET_PORT) still unusable"; fi
-    fi
-  done
-  
-  if [ $VMS_UNUSABLE -gt 0 ]; then
-    if [ $DEBUG -gt 0 ]; then echo "$VMS_UNUSABLE VMs are still unusable"; fi
-  else
-    RUNNING=false
-  fi
-
-  sleep 1
-
-done
-
-DATE=$(date)
-echo "Finished at $DATE"
diff --git a/virl-benchmark/check-reachability-websocket.py b/virl-benchmark/check-reachability-websocket.py
new file mode 100644
index 0000000..f0b2283
--- /dev/null
+++ b/virl-benchmark/check-reachability-websocket.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+
+import sys, time, socket
+from websocket import create_connection, WebSocketTimeoutException
+#websocket._exceptions.WebSocketTimeoutException
+
+def checkws(ws,hostname,timeout,debug):
+        # create websocket
+        ws = create_connection(ws, subprotocols=["binary", "base64"])
+        # set timeout
+        ws.settimeout(timeout);
+        # terminal initialization
+        ws.send("\x0d")
+        ws.send("\xff\xfd\x01")
+        ws.send("\xff\xfb\x03")
+        ws.send("\xff\xfb\x18")
+        ws.send("\xff\xfb\x1f")
+        ws.send("\xff\xfd\x03")
+        ws.send("\xff\xfd\x18")
+        ws.send("\xff\xfd\x1f")
+        ws.send("\xff\xfe\x00")
+        ws.send("\xff\xfc\x00")
+        # initial receive
+        try:
+                result = ""
+                result += ws.recv()
+        except WebSocketTimeoutException:
+                print "timeout"
+        except socket.error:
+                print "socket closed"
+                sys.exit(3)
+        if debug > 1: print result
+        # send three carriage returns
+        ws.send("\r\r\r")
+        start = time.clock()
+        duration = 0
+        # receive result
+        try:
+                result = ""
+                while True:
+                        result += ws.recv()
+                        if duration == 0 and result.count(hostname) >= 3:
+                                duration = time.clock() - start
+                                break
+        except WebSocketTimeoutException:
+                print "timeout"
+        except socket.error:
+                print "socket closed"
+                sys.exit(3)
+        if debug > 1: print result
+        ws.close()
+        # count occurences of hostname
+        if result.count(hostname) >= 3:
+                print "%f *sec elapsed*" % duration
+                return 0
+        else:
+                print "UNUSABLE"
+                return 2
+
+def main():
+        if len(sys.argv) <= 4:
+                sys.stdout.write(str(sys.argv[0]))
+                print ": ws url, hostname, timeout and debug (e.g., \"ws://192.168.76.210:19406/websockify?token=870668d2-8855-4208-9d48-9b1a141271b2\" iosv-1 0.5 0) needed as argument! bailing out"
+                return 1
+        else:
+                ws = str(sys.argv[1]).strip()
+                hostname = str(sys.argv[2]).strip()
+                timeout = float(sys.argv[3])
+                debug = int(sys.argv[4])
+                return checkws(ws,hostname,timeout,debug)
+
+if __name__ == '__main__':
+        sys.exit(main())
diff --git a/virl-benchmark/check-usability-of-sims b/virl-benchmark/check-usability-of-sims
new file mode 100644
index 0000000..ec12b1f
--- /dev/null
+++ b/virl-benchmark/check-usability-of-sims
@@ -0,0 +1,75 @@
+#!/bin/bash
+# check-usability-of-sims
+# HS-Fulda - sebastian.rieger@informatik.hs-fulda.de
+#
+# changelog:
+# V1.0   initial version
+
+# usage
+if [ ! $# -gt 2 ] ; then
+  echo -e "usage: $0 <username> <password> <timeout> [sim-regexp] [debug level], e.g.,\n"
+  echo "$0 guest password 0.5"
+  exit -1
+fi
+
+USERNAME=$1
+PASSWORD=$2
+TIMEOUT=$3
+if [ $4 ]; then
+  SIM_FILTER_REGEXP=$4
+else
+  SIM_FILTER_REGEXP="VIRLBENCH-(.*)@(.*)-[_a-zA-Z0-9]{6}"
+fi
+if [ $5 ]; then
+  DEBUG=$5
+else
+  DEBUG=0
+fi
+
+# get all running benchmark simulations
+SIMS=$(virl_std_client --username $USERNAME --password $PASSWORD --quiet --json simengine-list 2>&1 | egrep -o -e "$SIM_FILTER_REGEXP")
+if [ $DEBUG -gt 1 ]; then
+  echo "Running simulations:"
+  for SIM in $SIMS; do
+    echo $SIM
+  done
+  echo
+fi
+
+# Check if the nodes are ready-for-use using websocket consoles
+TOTAL_USABLE_COUNT=0
+TOTAL_AVG_DURATION=0
+for SIM in $SIMS; do
+  USABLE_COUNT=0
+  AVG_DURATION=0
+  WS_COUNT=$(virl_std_client --username $USERNAME --password $PASSWORD --quiet --json simengine-serial-port --session-id $SIM 2>&1 | grep -c "ws://")
+  WS_NODES=$(virl_std_client --username $USERNAME --password $PASSWORD --quiet --json simengine-serial-port --session-id $SIM 2>&1 | grep "ws://")
+  while [ $USABLE_COUNT -lt $WS_COUNT ]
+  do
+    USABLE_COUNT=0
+    AVG_DURATION=0
+    IFS=$'\n'
+    for WS_NODE in $WS_NODES; do
+      NODE=$(echo $WS_NODE | cut -d "\"" -f 2)
+      WS_URL=$(echo $WS_NODE | cut -d "\"" -f 4)
+      WS_RESULT=$(./check-reachability-websocket.py $WS_URL $NODE $TIMEOUT $DEBUG)
+      if [ $? -eq 0 ]; then
+        if [ $DEBUG -gt 0 ] ; then echo "$WS_RESULT: $NODE in $SIM is usable"; fi
+        DURATION=$(echo $WS_RESULT | egrep -o -e '[0-9]\.[0-9]{6} \*sec elapsed\*' | cut -d ' ' -f 1)
+        AVG_DURATION=$(awk "BEGIN {print $AVG_DURATION + $DURATION}")
+        USABLE_COUNT=$(expr $USABLE_COUNT + 1)
+      else
+        if [ $DEBUG -gt 0 ] ; then echo "$WS_RESULT: $NODE in $SIM is unusable"; fi
+      fi
+    done
+  done
+  # compute average in millisecs
+  TOTAL_AVG_DURATION=$(awk "BEGIN {print $TOTAL_AVG_DURATION + $AVG_DURATION}")
+  TOTAL_USABLE_COUNT=$(expr $TOTAL_USABLE_COUNT + $USABLE_COUNT)
+  AVG_DURATION=$(awk "BEGIN {print $AVG_DURATION / $USABLE_COUNT * 1000}")
+  if [ $DEBUG -gt 0 ] ; then echo "$USABLE_COUNT of $WS_COUNT nodes in $SIM are usable... (avg console delay $AVG_DURATION ms)"; fi
+done
+# compute average in millisecs
+TOTAL_AVG_DURATION=$(awk "BEGIN {print $TOTAL_AVG_DURATION / $TOTAL_USABLE_COUNT * 1000}")
+if [ $DEBUG -gt 0 ] ; then echo "$TOTAL_USABLE_COUNT nodes usable total in all sims... (total avg console delay $TOTAL_AVG_DURATION ms)"; fi
+echo "avgconsoledelay:$TOTAL_AVG_DURATION"
diff --git a/virl-benchmark/ports-vms.py b/virl-benchmark/ports-vms.py
deleted file mode 100644
index 6f61b0b..0000000
--- a/virl-benchmark/ports-vms.py
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/usr/bin/env python
-#
-# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
-#
-# Show all ports of all VM instances for
-# all users and topologies.
-# Like the console port and the VNC port
-#
-# rschmied@cisco.com
-#
-# modified by sebastian.rieger@informatik.hs-fulda.de to display telnet console ports of running nodes in a topology
-#
-
-
-import os, libvirt, re, sys
-from keystoneclient import client as keystone
-from novaclient import client as nova
-from xml.dom.minidom import parseString
-
-"""
-
-In [14]: m.group(0)
-Out[14]: '</guest/endpoint>-<Sample_Project@asa-test-topo-yJHnoK>-<iosv-2>-<Multipoint Connection-1>'
-
-In [15]: m.group(1)
-Out[15]: '/guest/endpoint'
-
-In [16]: m.group(2)
-Out[16]: 'Sample_Project'
-
-In [16]: m.group(3)
-Out[16]: 'asa-test-topo'
-
-In [17]: m.group(4)
-Out[17]: 'iosv-2'
-
-In [18]: m.group(5)
-Out[18]: 'Multipoint Connection-1'
-
-will not match jumphost ports!
-not interested in these, anyway
-
-"""
-
-class KeystoneV3NovaAuthPlugin(object):
-    def __init__(self, keystone_client):
-        self.keystone_client = keystone_client
-
-    def authenticate(self, client, fake_auth_url):
-        client.auth_url = fake_auth_url
-        client.service_catalog = self.keystone_client.service_catalog
-        client.auth_token = self.keystone_client.auth_token
-        client.tenant_id = self.keystone_client.tenant_id
-        client.management_url = self.keystone_client.service_catalog.url_for(
-            attr='region',
-            filter_value=client.region_name,
-            endpoint_type=client.endpoint_type,
-            service_type=client.service_type,
-            service_name=client.service_name).rstrip('/')
-
-def getports(user,simulation):
-	# Sample output / field mapping
-	# </guest/endpoint>-<Sample_Topologies@single-server-WO9N_h>-<csr1000v-1>
-	#         USER            PROJECT          TOPOLOGY             NODE
-	
-	# </advcompnet/endpoint>-<advcompnet-lab1-dcn-scenario1-ymaMSJ>-<veos-4>
-	#   USER                  TOPOLOGY                               NODE
-	prog=re.compile(r'</(.*)/endpoint>-<(.*)-[_0-9a-z]{6}>-<(.*)>', re.IGNORECASE)
-
-	# table=list()
-	try:
-		libvirt_uri = os.environ['LIBVIRT_DEFAULT_URI']
-	except:
-		libvirt_uri = "qemu:///system"
-		print "LIBVIRT_DEFAULT_URI env not set!"
-		print "Using default '" + libvirt_uri + "'"
-	conn=libvirt.openReadOnly(libvirt_uri)
-	
-	kc = keystone.Client(auth_url=os.environ['OS_AUTH_URL'],
-                     username=os.environ['OS_USERNAME'], password=os.environ['OS_PASSWORD'],
-                     project_name=os.environ['OS_TENANT_NAME'])
-	kc.session.auth = kc
-	kc.authenticate()
-	nc=nova.Client('2', os.environ['OS_USERNAME'], os.environ['OS_PASSWORD'], 
-		os.environ['OS_TENANT_NAME'], auth_system='keystonev3', auth_plugin=KeystoneV3NovaAuthPlugin(kc), auth_url='http://fake/v2.0')
-
-	for server in nc.servers.list(search_opts={'all_tenants': True}):
-		m=prog.match(server.name)
-		if m:
-			try:
-				domain=conn.lookupByUUIDString(server.id)
-			except:
-				print "Domain not found / not running"
-				return 1
-			else:
-				doc=parseString(domain.XMLDesc(flags=0))
-			# get the VNC port
-			#port=doc.getElementsByTagName('graphics')[0].getAttribute('port')
-			# get the serial console TCP port
-			for i in doc.getElementsByTagName('source'):
-				if i.parentNode.nodeName == u'console':
-					console=i.getAttribute('service')
-			# get the instance name
-			name=doc.getElementsByTagName('name')[0].childNodes[0].nodeValue
-			# print info
-			if simulation == "*":
-			        if m.group(1) == user:
-			                print m.group(3) + "=" + console
-                        else:
-			        if m.group(1) == user and server.name.find(simulation) != -1:
-			                print m.group(3) + "=" + console
-                       
-
-def main():
-        if len(sys.argv) != 3:
-                sys.stdout.write(str(sys.argv[0]))
-                print ": username and simulation (e.g., project name or session-id) needed as argument! bailing out"
-                return 1
-        else:
-                user = str(sys.argv[1]).strip()
-                simulation = str(sys.argv[2]).strip()
-                getports(user,simulation)
-                return 0
-
-if __name__ == '__main__':
-	sys.exit(main())
-
diff --git a/virl-benchmark/start-virl-topology b/virl-benchmark/start-virl-topology
index 68f2314..1e11e51 100644
--- a/virl-benchmark/start-virl-topology
+++ b/virl-benchmark/start-virl-topology
@@ -4,11 +4,12 @@
 #
 # changelog:
 # V1.0   initial version
+# V2.0   changed benchmark to support clusters and VIRL Version >=1.0.0
 
 # usage
 if [ ! $# -gt 4 ] ; then
   echo -e "usage: $0 <my-topology.virl> <number of concurrent simulations> <username> <password> <timeout> [debug level], e.g.,\n"
-  echo "$0 /home/virl/git-virl-hs-fulda/GIT-VIRL-HS-Fulda/advcompnet-lab2-dcn-fabricpath.virl 6 guest password"
+  echo "$0 /home/virl/git-virl-hs-fulda/GIT-VIRL-HS-Fulda/advcompnet-lab2-dcn-fabricpath.virl 6 guest password 0.5"
   exit -1
 fi
 
@@ -27,8 +28,9 @@ TOPOLOGYFILENAME=$(basename $TOPOLOGY)
 TIMESTAMP=$(date +%H%M%S)
 FILENAME="VIRLBENCH-$TIMESTAMP@$TOPOLOGYFILENAME"
 
-DATE=$(date)
-echo "Script started at $DATE"
+SCRIPTSTART_DATE=$(date)
+SCRIPTSTART_TIMESTAMP=$(date "+%s")
+echo "Script started at $SCRIPTSTART_DATE"
 
 # start the simulations
 RUN=0
@@ -45,8 +47,9 @@ do
   RUN=$(expr $RUN + 1)
 done
 
-DATE=$(date)
-echo "Started at $DATE"
+START_DATE=$(date)
+START_TIMESTAMP=$(date "+%s")
+echo "Started at $START_DATE"
 
 RUNNING=true
 
@@ -91,36 +94,26 @@ do
   sleep 1
 done
 
-DATE=$(date)
-echo "Active at $DATE"
-
-# Check if the nodes are ready-for-use using expect
-./check-reachability $USERNAME $TIMEOUT "VIRLBENCH-$TIMESTAMP" $DEBUG
-
-# Check using load
-
-# Alternative to check if nodes are ready, use CPU load threshold for VMs (IOSv and IOSvL2 have a high CPU load during initial boot)
-#THRESHOLD="70.0"
-
-#while $RUNNING = true
-#do
-#  VM_LOADS=$(top -n 1 | grep kvm.real | tr -s " " | cut -d " " -f 9)
-#
-#  VMS_WITH_HIGH_CPU_LOAD=0
-#  for VM_LOAD in $VM_LOADS
-#  do
-#    if [ $(echo "$VM_LOAD > $THRESHOLD" | bc) -eq 1 ] ; then 
-#      VMS_WITH_HIGH_CPU_LOAD=$(expr $VMS_WITH_HIGH_CPU_LOAD + 1)
-#      echo "$VM_LOAD > 6x0.0"
-#    fi
-#  done
-#  
-#  if [ $VMS_WITH_HIGH_CPU_LOAD -gt 0 ]; then
-#    echo "cpu load = high"
-#  else
-#    RUNNING=false
-#  fi
-#done
-
-DATE=$(date)
-echo "Finished at $DATE"
+ACTIVE_DATE=$(date)
+ACTIVE_TIMESTAMP=$(date "+%s")
+echo "Active at $ACTIVE_DATE"
+
+# Check if the nodes are ready-for-use using websocket consoles
+./check-usability-of-sims $USERNAME $PASSWORD $TIMEOUT "VIRLBENCH-$TIMESTAMP@(.*)-[_a-zA-Z0-9]{6}" $DEBUG
+
+USABLE_DATE=$(date)
+USABLE_TIMESTAMP=$(date "+%s")
+echo "Usable at $USABLE_DATE"
+
+START_TIME=$(( $START_TIMESTAMP - $SCRIPTSTART_TIMESTAMP ))
+ACTIVE_TIME=$(( $ACTIVE_TIMESTAMP - $SCRIPTSTART_TIMESTAMP ))
+USABLE_TIME=$(( $USABLE_TIMESTAMP - $SCRIPTSTART_TIMESTAMP ))
+
+echo
+echo
+echo "CSV Result:"
+echo "==========="
+echo "Topology;ConcurrentSims;Nodes;Script-Start;Started;Active;Usable;Finished;Start Time (sec);Active Time (sec);Usable Time (sec)"
+echo "$TOPOLOGYFILENAME;$RUNCOUNT;$NODE_COUNT;$SCRIPTSTART_DATE;$STARTDATE;$ACTIVE_DATE;$USABLE_DATE;$START_TIME;$ACTIVE_TIME;$USABLE_TIME"
+echo
+echo
diff --git a/virl-benchmark/test-virl-telnet-connection b/virl-benchmark/test-virl-telnet-connection
deleted file mode 100644
index 71f4a39..0000000
--- a/virl-benchmark/test-virl-telnet-connection
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/expect
-
-# connect to telnet port, press return and expect argv 2 (hostname) in
-# prompt, press return again and expect to receive argv 2 again 
-
-set timeout [lindex $argv 3]
-spawn telnet [lindex $argv 0] [lindex $argv 1]
-send "\r"
-expect { 
-  [lindex $argv 2]
-}
-send "\r"
-expect { 
-  [lindex $argv 2]
-  { exit 0 }
-}
-exit 5
-- 
GitLab