#!/bin/bash # IBM(c) 2017 EPL license http://www.eclipse.org/legal/epl-v10.html #(C)IBM Corp # ################################################################### # # Description: # This script is used for performance testing purpose. It could # generate n*250 fake nodes based on a predefined template (/opt/xcat/share/xcat/templates/objects/node/), # and then run the performance testing on a batch of xCAT commands. # # Note: It is availabe for the commands which require management node only. # # Syntax: # $prog [command-list-file] # ################################################################### if [ -z $LC_ALL ]; then export LC_ALL=C fi # Used for number parameter validation isNumber() { expr $1 + 0 &>/dev/null } # Used for prerequiste checking preChecking() { local val="" for cmd in brctl ifconfig; do which $cmd > /dev/null 2>&1 [ $? -ne 0 ] && val="$cmd,$val" done echo $val | sed s/,$// } # Give a simple usage if [ -z "$1" ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then echo "[PERF_DRYRUN=y] [PERF_NOCREATE=y] $0 [command-list-file]" exit else isNumber $1 if [ ! $? -eq 0 ]; then echo "You must input an numeric string for total nodes number." exit -1 fi fi # Source xCAT profile to make sure the xCAT commands could be executed without absolute path. if [ -z $XCATROOT ]; then if [ -r /etc/profile.d/xcat.sh ]; then . /etc/profile.d/xcat.sh fi fi pass=$(preChecking) if [ ! -z "$pass" ]; then echo "Error: Missing required tools: $pass" [ -z $PERF_DRYRUN ] && exit -1 fi # Mandatory, to specify the number of total fake nodes which will be created for testing FAKE_NODE_TOTAL=$1 # Optional, the prefix of the fake compute node name. # By default, it is 'fake' but it could be changed when you set environment variable `FAKE_NODE_PREFIX` if [ -z $FAKE_NODE_PREFIX ]; then FAKE_NODE_PREFIX='fake' fi # Optional, the group name of all the fake compute nodes. # By default, it is 'perftest' but it could be changed when you set environment variable `FAKE_NODE_GROUP` if [ -z $FAKE_NODE_GROUP ]; then FAKE_NODE_GROUP='perftest' fi # Mandatory, the Provision network for all the fake compute nodes. It must be a string like 'A.B', and be matched with `tabdump networks` # By default, it is '192.168' but it could be changed when you set environment variable `FAKE_NETWORK_PRO` if [ -z $FAKE_NETWORK_PRO ]; then FAKE_NETWORK_PRO='192.168' fi # Mandatory, the BMC network for all the fake compute nodes. It must be a string like 'A.B' and no need to be defined in 'networks' table. # By default, it is '192.169' but it could be changed when you set environment variable `FAKE_NETWORK_BMC` # Note: it could not be the same subnet as 'FAKE_NETWORK_PRO' if [ -z $FAKE_NETWORK_BMC ]; then FAKE_NETWORK_BMC='192.169' fi # Optional, The network mask for the fake network object. # By default, it is '255.255.0.0' but it could be changed when you set environment variable `FAKE_NETWORK_MASK` if [ -z $FAKE_NETWORK_MASK ]; then FAKE_NETWORK_MASK='255.255.0.0' fi # Optional, The bridge device name for the temporary interface which is required on MN as nodeset/makedhcp will check if the MN and CN in same subnet. # By default, it is 'perfvirbr0' but it could be changed when you set environment variable `FAKE_NETWORK_INTF` if [ -z $FAKE_NETWORK_INTF ]; then FAKE_NETWORK_INTF='perfvirbr0' fi # Optional, The node template name used for generating fake nodes. # By default, it is '-template' but it could be changed when you set environment variable `FAKE_NODE_GROUP` if [ -z $PERF_NODETEMPL ]; then PERF_NODETEMPL="`arch`-template" fi # IP address assinged to node will be in [1-250] NODE_PER_ROW=250 MYSUFFIX=`date +"%Y%m%d%H%M%S"` if [ -z $PERFORMANCE_DIR ]; then PERFORMANCE_DIR=$XCATROOT/share/xcat/tools/autotest/result fi PERFORMANCE_NODE_TMPL=$PERFORMANCE_DIR/perf-node.tmpl PERFORMANCE_REPORT=$PERFORMANCE_DIR/perfreport-$FAKE_NODE_TOTAL.log.$MYSUFFIX PERFORMANCE_STANZ=$PERFORMANCE_DIR/perfstanz-$FAKE_NODE_TOTAL.$MYSUFFIX # If the command list file is not specified, the tool will only create the stanz file for fake nodes. # If it is specified but not exists, the tool will exit with error. if [ ! -z $2 ]; then if [ -f $2 ]; then RUN_CMD_LIST=$2 else echo "ERROR: The command list file you specified does not exist." exit -1 fi fi # Get a random MAC address genMAC() { printf '00:60:2F:%02X:%02X:%02X' $[RANDOM%256] $[RANDOM%256] $[RANDOM%256] } # Generate stanz file for all fake nodes genStanz() { if [ ! -z $PERF_DRYRUN ]; then echo $1, $2, $3, $4 else echo -n . fi sed -e '/Object name:/c \'"$1"':\n objtype=node' \ -e '/ip=/c \ ip='"$3"'' \ -e '/mac=/c \ mac='"$2"'' \ -e '/bmc=/c \ bmc='"$4"'' \ -e '/bmcusername=/c \ bmcusername=fake' \ -e '/bmcpassword=/c \ bmcpassword=fake' \ -e '/groups=/c \ groups=all,'"$FAKE_NODE_GROUP"'' \ -e '/postscripts=/c \ postscripts=mypostboot' \ -e '/postbootscripts=/c \ postbootscripts=mypostboot' \ $PERFORMANCE_NODE_TMPL >> $PERFORMANCE_STANZ } # Create a fake xCAT node definition fakeNode() { # TODO: support regular expression for IP genStanz $FAKE_NODE_PREFIX$1 $(genMAC) $FAKE_NETWORK_PRO.$2.$3 $FAKE_NETWORK_BMC.$2.$3 #mkdef -f -t node $FAKE_NODE_PREFIX$1 --template $PERF_NODETEMPL ip=$FAKE_NETWORK_PRO.$2.$3 mac=$(genMAC) \ # bmc=$FAKE_NETWORK_BMC.$2.$3 bmcpassword=fake bmcusername=fake groups=all,performance > /dev/null 2>&1 } # Create a fake xCAT network definition fakeNetwork() { lsdef -t network -o net-$FAKE_NODE_PREFIX > /dev/null 2>&1 if [ 0 != $? ]; then mkdef -t network net-$FAKE_NODE_PREFIX net=$FAKE_NETWORK_PRO.0.0 mask=$FAKE_NETWORK_MASK > /dev/null else chdef -t network -o net-$FAKE_NODE_PREFIX net=$FAKE_NETWORK_PRO.0.0 mask=$FAKE_NETWORK_MASK > /dev/null fi } # Create a fake xCAT network definition fakeInterface() { result=`ifconfig $1 2>/dev/null` if [ -z "$2" ]; then [ -z "$result" ] && brctl addbr $1 ifconfig $1 $FAKE_NETWORK_PRO.251.254 netmask $FAKE_NETWORK_MASK || echo "$1 is not configured successfully" elif [ ! -z "$result" ]; then ifconfig $1 down brctl delbr $1 || echo "$1 is not removed successfully, you may need to clean up manually." fi } getOSimage() { # The OS image name used in nodeset to replace the MACRO Variable `#OSIMAGE#`. # By default, it could be detectd automatically according to the arch if [ -z $PERF_OSIMAGE ]; then # covert it to an array osimage_array=($(lsdef -t osimage 2>/dev/null| grep `arch`|grep 'install'|awk '/compute/ {print $1}')) index=`expr $RANDOM % ${#osimage_array[@]} 2>/dev/null` echo ${osimage_array[$index]} else echo $PERF_OSIMAGE fi } # Create batch fake nodes stanz file for testing bootstrap() { declare -i count=0 [ $rack = 0 ] && rack=1 for i in $(seq 0 $(expr $rack - 1)) do for j in $(seq 1 $NODE_PER_ROW) do count+=1 fakeNode $count $i $j [ $(($count % $1)) = 0 ] && echo [ "x$count" == "x$FAKE_NODE_TOTAL" ] && break done done } # Get current time getTime() { date +%s -d "$1" } # Executing the testing on specific commands defined in command list file # All MACROs defined in command list file will be replaced with the real value runTest() { cmd=$1 [ -z $osimage ] || cmd="${cmd/\#OSIMAGE\#/$osimage}" if [[ $cmd =~ '#STANZ#' ]]; then #mkdef -z execCmd "${cmd/\#STANZ\#/$PERFORMANCE_STANZ}" "$FAKE_NODE_TOTAL" elif [[ $cmd =~ '#NODES#' ]]; then #noderange operation if [ -z "$2" ]; then # No SERIES defined, run command on the whole group execCmd "${cmd/\#NODES\#/$FAKE_NODE_GROUP}" "$FAKE_NODE_TOTAL" else # run the command for each number in SERIES for num in $2 do isNumber $num || continue if [[ $num -le $FAKE_NODE_TOTAL ]]; then #cmd=$1 execCmd "${cmd/\#NODES\#/$FAKE_NODE_PREFIX[1-$num]}" "$num" fi done fi elif [[ $cmd =~ '#PERFGRP#' ]]; then execCmd "${cmd/\#PERFGRP\#/$FAKE_NODE_GROUP}" "$FAKE_NODE_TOTAL" else execCmd "$cmd" "N/A" fi } # Output performance result for each command. printResult() { #TODO, more clear short desc for this command desc=`echo "$1" | awk '{print $1}'` result=$([[ $4 = 0 ]] && echo "SUCESS" || echo "FAIL") # TOTAL, CMD, NODERANGE, TIME, SUCESS, FULL COMMAND echo "$FAKE_NODE_TOTAL; $desc; $2; $3; $result; \"$1\"" | tee -a $PERFORMANCE_REPORT } # Executing each command and print the result to report file execCmd() { echo "Testing for [ $1 ] ..." if [ ! -z $PERF_DRYRUN ]; then return fi starttime=`date +'%Y-%m-%d %H:%M:%S'` start=$(getTime "$starttime") eval "$1" > /dev/null 2>&1 retval=$? endtime=`date +'%Y-%m-%d %H:%M:%S'` end=$(getTime "$endtime") printResult "$1" "$2" "$(($end-$start))" "$retval" } ################################################# # Main Loop of the performance baseline testing # ################################################# version=`lsxcatd -a 2>/dev/null | grep Version` if [ 0 != $? ]; then echo "ERROR: xCAT daemon is not running. Start 'xcatd' and rerun this tool." exit 99 fi mkdir -p $PERFORMANCE_DIR lsdef -t node --template $PERF_NODETEMPL > $PERFORMANCE_NODE_TMPL 2>/dev/null if [ 0 != $? ]; then echo "ERROR: Cannot find the default template for `arch`, make sure it exists and rerun this tool." exit 99 fi #Get available OS image, it will be used for nodeset if possible osimage=$(getOSimage) rack=$(expr $FAKE_NODE_TOTAL / $NODE_PER_ROW) echo "==================================================" # Starting to add fake nodes starttime=`date +'%Y-%m-%d %H:%M:%S'` start=$(getTime "$starttime") bootstrap 50 endtime=`date +'%Y-%m-%d %H:%M:%S'` end=$(getTime "$endtime") echo echo "==================================================" #echo "It takes $(($end-$start)) seconds to create $FAKE_NODE_TOTAL nodes" #echo "$FAKE_NODE_TOTAL", "$(($end-$start))", "mkdef" >> $PERFORMANCE_REPORT if [ -z $RUN_CMD_LIST ]; then echo "Done. Check the stanz file in $PERFORMANCE_STANZ" exit 0 fi echo "Continue the performance testing for commands in $RUN_CMD_LIST " if [ -z "$osimage" ]; then echo "WARN: Cannot determine the OS image, the commands which defined with #OSIMAGE# will be failed." fi echo $version | tee $PERFORMANCE_REPORT echo "==================================================" # Initial Populate the fake nodes into DB if [ -z $PERF_NOCREATE ]; then #create fake network for makedns, makedhcp etc... fakeNetwork execCmd "mkdef -z -f < $PERFORMANCE_STANZ" "$FAKE_NODE_TOTAL" fi # fake interface is required for topology with service nodes as it will determine if then Mn/Sn are # in the same subnet with CNs fakeInterface $FAKE_NETWORK_INTF series=`grep '^#SERIES#' $RUN_CMD_LIST | awk '{print $2}'` if [ ! -z $series ]; then series=${series//,/ } fi #echo $series cmdlist=`cat $RUN_CMD_LIST` IFS_BAK=$IFS IFS=$'\n' for line in $cmdlist do [ "x${line:0:1}" = "x#" ] && continue # begin to run the command IFS=$IFS_BAK runTest "$line" "$series" IFS=$'\n' done IFS=$IFS_BAK IFS_BAK= rm -f $PERFORMANCE_NODE_TMPL rm -f $PERFORMANCE_STANZ fakeInterface $FAKE_NETWORK_INTF del if [ -z $PERF_DRYRUN ]; then echo echo "Done. Check the performance result in $PERFORMANCE_REPORT" fi