diff --git a/autotest.sh b/autotest.sh index f9e29a05d..a0f914fbf 100755 --- a/autotest.sh +++ b/autotest.sh @@ -152,6 +152,7 @@ if [ $SPDK_RUN_FUNCTIONAL_TEST -eq 1 ]; then timing_enter lib run_test "env" test/env/env.sh + run_test "rpc" test/rpc/rpc.sh run_test "rpc_client" test/rpc_client/rpc_client.sh run_test "json_config" ./test/json_config/json_config.sh run_test "alias_rpc" test/json_config/alias_rpc/alias_rpc.sh diff --git a/scripts/rpc.py b/scripts/rpc.py index 44870d36b..74f6c59aa 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -37,6 +37,14 @@ if __name__ == "__main__": help="""Set verbose level. """) parser.add_argument('--dry_run', dest='dry_run', action='store_true', help="Display request and exit") parser.set_defaults(dry_run=False) + parser.add_argument('--server', dest='is_server', action='store_true', + help="Start listening on stdin, parse each line as a regular rpc.py execution and create \ + a separate connection for each command. Each command's output ends with either \ + **STATUS=0 if the command succeeded or **STATUS=1 if it failed. --server is meant \ + to be used in conjunction with bash coproc, where stdin and stdout are connected to \ + pipes and can be used as a faster way to send RPC commands. If enabled, rpc.py \ + must be executed without any other parameters.") + parser.set_defaults(is_server=False) subparsers = parser.add_subparsers(help='RPC methods', dest='called_rpc_name') def framework_start_init(args): @@ -2374,7 +2382,26 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse exit(1) args = parser.parse_args() - if args.dry_run: + if args.is_server: + for input in sys.stdin: + cmd = shlex.split(input) + try: + tmp_args = parser.parse_args(cmd) + except SystemExit as ex: + print("**STATUS=1", flush=True) + continue + + try: + tmp_args.client = rpc.client.JSONRPCClient( + tmp_args.server_addr, tmp_args.port, tmp_args.timeout, + log_level=getattr(logging, tmp_args.verbose.upper())) + call_rpc_func(tmp_args) + print("**STATUS=0", flush=True) + except JSONRPCException as ex: + print(ex.message) + print("**STATUS=1", flush=True) + exit(0) + elif args.dry_run: args.client = dry_run_client() print_dict = null_print print_json = null_print diff --git a/test/common/autotest_common.sh b/test/common/autotest_common.sh index 98077e9a7..0d37e957f 100644 --- a/test/common/autotest_common.sh +++ b/test/common/autotest_common.sh @@ -300,6 +300,31 @@ for i in "$@"; do esac done +# start rpc.py coprocess if it's not started yet +if [[ -z $RPC_PIPE_PID ]] || ! kill -0 "$RPC_PIPE_PID" &>/dev/null; then + coproc RPC_PIPE { "$rootdir/scripts/rpc.py" --server; } + exec {RPC_PIPE_OUTPUT}<&${RPC_PIPE[0]} {RPC_PIPE_INPUT}>&${RPC_PIPE[1]} + # all descriptors will automatically close together with this bash + # process, this will make rpc.py stop reading and exit gracefully +fi + +function rpc_cmd() { + xtrace_disable + local rsp rc + + echo "$@" >&$RPC_PIPE_INPUT + while read -t 5 -ru $RPC_PIPE_OUTPUT rsp; do + if [[ $rsp == "**STATUS="* ]]; then + break + fi + echo "$rsp" + done + + rc=${rsp#*=} + xtrace_restore + [[ $rc == 0 ]] +} + function timing() { direction="$1" testname="$2" diff --git a/test/make/check_so_deps.sh b/test/make/check_so_deps.sh index 1d6c2bc37..943072393 100755 --- a/test/make/check_so_deps.sh +++ b/test/make/check_so_deps.sh @@ -123,11 +123,7 @@ fail_file=$output_dir/check_so_deps_fail rm -f $fail_file -for lib in $SPDK_LIBS; do - confirm_deps $lib& -done - -wait +( for lib in $SPDK_LIBS; do confirm_deps $lib & done; wait ) $MAKE $MAKEFLAGS clean git checkout "$rootdir/mk/spdk.lib.mk" diff --git a/test/rpc/rpc.sh b/test/rpc/rpc.sh new file mode 100755 index 000000000..4fbda195f --- /dev/null +++ b/test/rpc/rpc.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +testdir=$(readlink -f $(dirname $0)) +rootdir=$(readlink -f $testdir/../..) +source $rootdir/test/common/autotest_common.sh + +# simply check if rpc commands have any effect on spdk +function rpc_integrity() { + time { + bdevs=$($rpc bdev_get_bdevs) + [ "$(jq length <<< "$bdevs")" == "0" ] + + malloc=$($rpc bdev_malloc_create 8 512) + bdevs=$($rpc bdev_get_bdevs) + [ "$(jq length <<< "$bdevs")" == "1" ] + + $rpc bdev_passthru_create -b "$malloc" -p Passthru0 + bdevs=$($rpc bdev_get_bdevs) + [ "$(jq length <<< "$bdevs")" == "2" ] + + $rpc bdev_passthru_delete Passthru0 + $rpc bdev_malloc_delete $malloc + bdevs=$($rpc bdev_get_bdevs) + [ "$(jq length <<< "$bdevs")" == "0" ] + } +} + +$rootdir/app/spdk_tgt/spdk_tgt & +spdk_pid=$! +trap 'killprocess $spdk_pid; exit 1' SIGINT SIGTERM EXIT +waitforlisten $spdk_pid + +# basic integrity test +rpc="$rootdir/scripts/rpc.py" +run_test "rpc_integrity" rpc_integrity +# same test, but with rpc_cmd() instead +rpc="rpc_cmd" +run_test "rpc_daemon_integrity" rpc_integrity + +trap - SIGINT SIGTERM EXIT +killprocess $spdk_pid