diff --git a/autotest.sh b/autotest.sh index 1205a5608..42d19abe0 100755 --- a/autotest.sh +++ b/autotest.sh @@ -97,7 +97,7 @@ if [ $(uname -s) = Linux ]; then time ./test/iscsi_tgt/fio/fio.sh time ./test/iscsi_tgt/reset/reset.sh time ./test/iscsi_tgt/rpc_config/rpc_config.sh - + time ./test/iscsi_tgt/idle_migration/idle_migration.sh timing_exit iscsi_tgt fi diff --git a/test/iscsi_tgt/idle_migration/build_configuration.sh b/test/iscsi_tgt/idle_migration/build_configuration.sh new file mode 100755 index 000000000..bc96b0077 --- /dev/null +++ b/test/iscsi_tgt/idle_migration/build_configuration.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +set -xe +rootdir=$(readlink -f $(dirname $0))/../../.. + +rpc_py=$rootdir/scripts/rpc.py + +"$rpc_py" add_initiator_group 1 "ALL" "127.0.0.1/32" +"$rpc_py" add_portal_group 1 '127.0.0.1:3260' + +for i in $(seq 0 15); do + "$rpc_py" construct_malloc_lun 32 512 + "$rpc_py" construct_target_node "Target$i" "Target_alias$i" "Malloc$i:0" "1:1" 64 1 0 0 0 +done diff --git a/test/iscsi_tgt/idle_migration/connection_status.py b/test/iscsi_tgt/idle_migration/connection_status.py new file mode 100755 index 000000000..e9ebafa0e --- /dev/null +++ b/test/iscsi_tgt/idle_migration/connection_status.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python + +import json +import os +import sys +from time import sleep +from subprocess import check_output + +rpc_py = os.path.dirname(os.path.realpath(__file__)) + '/../../../scripts/rpc.py' + +class spdk_rpc(object): + + def __init__(self, rpc_py): + self.rpc_py = rpc_py + + def __getattr__(self, name): + def call(*args): + cmd = "python {} {}".format(self.rpc_py, name) + for arg in args: + cmd += " {}".format(arg) + return check_output(cmd, shell=True) + return call + +if __name__ == '__main__': + + if (len(sys.argv) < 2) or (sys.argv[1] != "idle" and sys.argv[1] != "active"): + print "must specify \"idle\" or \"active\"" + sys.exit(1) + + rpc = spdk_rpc(rpc_py) + + idle = 0 + active = 0 + + # capture connection state 10 times, 10 ms apart and keep a + # a running count of how many connections were found idle + # and active + for i in range(10): + + conns = json.loads(rpc.get_iscsi_connections()) + num_conns = len(conns) + + for conn in conns: + if conn['is_idle'] == 1: + idle += 1 + else: + active += 1 + + # sleep 10ms + sleep(0.01) + + active_pct = float(active) / (idle + active) + + # even when there is no active I/O on a connection, there could be + # a nopin/nopout being processed which causes a connection to + # temporarily go active; also even when fio is actively running + # there could be a brief period of time where the initiator has + # no active I/O to some connection + # + # so do not enforce that *all* connections must be idle or active; + # allow for some percentage of anomalies + anomaly_pct_allowed = 0.10 + + print "active = {}".format(active) + print "idle = {}".format(idle) + print "active_pct = {}".format(active_pct) + + if sys.argv[1] == "idle" and active_pct > anomaly_pct_allowed: + sys.exit(1) + + if sys.argv[1] == "active" and active_pct < (1.00 - anomaly_pct_allowed): + sys.exit(1) + + sys.exit(0) diff --git a/test/iscsi_tgt/idle_migration/idle_migration.sh b/test/iscsi_tgt/idle_migration/idle_migration.sh new file mode 100755 index 000000000..71ce05230 --- /dev/null +++ b/test/iscsi_tgt/idle_migration/idle_migration.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash + +testdir=$(readlink -f $(dirname $0)) +rootdir=$testdir/../../.. +source $rootdir/scripts/autotest_common.sh + +if [ -z "$TARGET_IP" ]; then + echo "TARGET_IP not defined in environment" + exit 1 +fi + +if [ -z "$INITIATOR_IP" ]; then + echo "INITIATOR_IP not defined in environment" + exit 1 +fi + +timing_enter idle_migration + +# iSCSI target configuration +PORT=3260 +RPC_PORT=5260 + +fio_py="python $rootdir/scripts/fio.py" + +./app/iscsi_tgt/iscsi_tgt -c $testdir/iscsi.conf & +pid=$! +echo "Process pid: $pid" + +trap "process_core; killprocess $pid; exit 1" SIGINT SIGTERM EXIT + +waitforlisten $pid ${RPC_PORT} +echo "iscsi_tgt is listening. Running tests..." + +$testdir/build_configuration.sh + +sleep 1 + +iscsiadm -m discovery -t sendtargets -p $TARGET_IP:$PORT +iscsiadm -m node --login -p $TARGET_IP:$PORT + +trap "iscsicleanup; process_core; killprocess $pid; exit 1" SIGINT SIGTERM EXIT + +sleep 5 + +# verify that ids has connections in idle state +python $testdir/connection_status.py idle + +# start fio in background - while it is running, verify that connections are active +$fio_py 4096 16 randrw 15 & +fiopid=$! +sleep 5 +python $testdir/connection_status.py active +kill $fiopid +wait $fiopid || true +sleep 1 + +# verify again that ids has connections in idle state +python $testdir/connection_status.py idle + +trap - SIGINT SIGTERM EXIT + +iscsicleanup +killprocess $pid +timing_exit idle_migration diff --git a/test/iscsi_tgt/idle_migration/iscsi.conf b/test/iscsi_tgt/idle_migration/iscsi.conf new file mode 100644 index 000000000..de468a01b --- /dev/null +++ b/test/iscsi_tgt/idle_migration/iscsi.conf @@ -0,0 +1,14 @@ +[Global] + ReactorMask 0xFFFF + LogFacility "local7" + +[iSCSI] + NodeBase "iqn.2016-06.io.spdk" + AuthFile /usr/local/etc/spdk/auth.conf + Timeout 30 + DiscoveryAuthMethod Auto + MaxSessions 64 + ImmediateData Yes + ErrorRecoveryLevel 0 +[Rpc] + Enable Yes