diff --git a/doc/man1/flux-kvs.adoc b/doc/man1/flux-kvs.adoc index e2345af78d29..db0716f5d73a 100644 --- a/doc/man1/flux-kvs.adoc +++ b/doc/man1/flux-kvs.adoc @@ -132,11 +132,13 @@ an RFC 11 snapshot reference. Create an empty directory and commit the change. If 'key' exists, it is overwritten. -*copy* 'source' 'destination':: -Copy 'source' key to 'destination' key. If a directory is copied, a new -reference is created; it is unnecessary for *copy* to recurse into 'source'. +*copy* [-S src-ns] [-D dst-ns] 'source' 'destination':: +Copy 'source' key to 'destination' key. Optionally, specify a source +and/or destination namespace to override the one specified via 'N'. +If a directory is copied, a new reference is created; it is +unnecessary for *copy* to recurse into 'source'. -*move* 'source' 'destination':: +*move* [-S src-ns] [-D dst-ns] 'source' 'destination':: Like *copy*, but 'source' is unlinked after the copy. *dropcache* [--all]:: diff --git a/src/cmd/flux-kvs.c b/src/cmd/flux-kvs.c index 6b203ded480f..990ed4d73144 100644 --- a/src/cmd/flux-kvs.c +++ b/src/cmd/flux-kvs.c @@ -205,6 +205,16 @@ static struct optparse_option getroot_opts[] = { OPTPARSE_TABLE_END }; +static struct optparse_option copy_opts[] = { + { .name = "src-namespace", .key = 'S', .has_arg = 1, + .usage = "Specify source key's namespace", + }, + { .name = "dst-namespace", .key = 'D', .has_arg = 1, + .usage = "Specify destination key's namespace", + }, + OPTPARSE_TABLE_END +}; + static struct optparse_subcommand subcommands[] = { { "namespace-create", "name [name...]", @@ -288,14 +298,14 @@ static struct optparse_subcommand subcommands[] = { "Copy source key to destination key", cmd_copy, 0, - NULL + copy_opts }, { "move", "source destination", "Move source key to destination key", cmd_move, 0, - NULL + copy_opts }, { "dropcache", "[--all]", @@ -1619,14 +1629,19 @@ int cmd_copy (optparse_t *p, int argc, char **argv) int optindex; flux_future_t *f; const char *srckey, *dstkey; + const char *srcns, *dstns; optindex = optparse_option_index (p); if (optindex != (argc - 2)) log_msg_exit ("copy: specify srckey dstkey"); + + srcns = optparse_get_str (p, "src-namespace", NULL); + dstns = optparse_get_str (p, "dst-namespace", NULL); + srckey = argv[optindex]; dstkey = argv[optindex + 1]; - if (!(f = flux_kvs_copy (h, NULL, srckey, NULL, dstkey, 0)) + if (!(f = flux_kvs_copy (h, srcns, srckey, dstns, dstkey, 0)) || flux_future_get (f, NULL) < 0) log_err_exit ("flux_kvs_copy"); flux_future_destroy (f); @@ -1640,16 +1655,21 @@ int cmd_move (optparse_t *p, int argc, char **argv) int optindex; flux_future_t *f; const char *srckey, *dstkey; + const char *srcns, *dstns; h = (flux_t *)optparse_get_data (p, "flux_handle"); optindex = optparse_option_index (p); if (optindex != (argc - 2)) log_msg_exit ("move: specify srckey dstkey"); + + srcns = optparse_get_str (p, "src-namespace", NULL); + dstns = optparse_get_str (p, "dst-namespace", NULL); + srckey = argv[optindex]; dstkey = argv[optindex + 1]; - if (!(f = flux_kvs_move (h, NULL, srckey, NULL, dstkey, 0)) + if (!(f = flux_kvs_move (h, srcns, srckey, dstns, dstkey, 0)) || flux_future_get (f, NULL) < 0) log_err_exit ("flux_kvs_move"); flux_future_destroy (f); diff --git a/t/t1009-kvs-copy.t b/t/t1009-kvs-copy.t index ba3421def9e1..8946dfd0107c 100755 --- a/t/t1009-kvs-copy.t +++ b/t/t1009-kvs-copy.t @@ -78,21 +78,21 @@ test_expect_success 'kvs-move dir dst contains expected value' ' test "$value" = "bar" ' -# from namespace +# from namespace, via nsprefix # copy a value, move a dir test_expect_success 'create test namespace' ' - flux kvs namespace-create fromns + flux kvs namespace-create fromns-prefix ' test_expect_success 'kvs-copy from namespace works' ' flux kvs unlink -Rf test && - flux kvs unlink -Rf ns:fromns/test && - flux kvs put ns:fromns/test.src=foo && - flux kvs copy ns:fromns/test.src test.dst + flux kvs unlink -Rf ns:fromns-prefix/test && + flux kvs put ns:fromns-prefix/test.src=foo && + flux kvs copy ns:fromns-prefix/test.src test.dst ' test_expect_success 'kvs-copy from namespace does not unlink src' ' - value=$(flux kvs get ns:fromns/test.src) && + value=$(flux kvs get ns:fromns-prefix/test.src) && test "$value" = "foo" ' test_expect_success 'kvs-copy from namespace dst contains expected value' ' @@ -102,12 +102,12 @@ test_expect_success 'kvs-copy from namespace dst contains expected value' ' test_expect_success 'kvs-move from namespace works' ' flux kvs unlink -Rf test && - flux kvs unlink -Rf ns:fromns/test && - flux kvs put ns:fromns/test.src.a.b.c=foo && - flux kvs move ns:fromns/test.src test.dst + flux kvs unlink -Rf ns:fromns-prefix/test && + flux kvs put ns:fromns-prefix/test.src.a.b.c=foo && + flux kvs move ns:fromns-prefix/test.src test.dst ' test_expect_success 'kvs-move from namespace unlinks src' ' - test_must_fail flux kvs get --treeobj ns:fromns/test.src + test_must_fail flux kvs get --treeobj ns:fromns-prefix/test.src ' test_expect_success 'kvs-move from namespace dst contains expected value' ' value=$(flux kvs get test.dst.a.b.c) && @@ -115,49 +115,128 @@ test_expect_success 'kvs-move from namespace dst contains expected value' ' ' test_expect_success 'remove test namespace' ' - flux kvs namespace-remove fromns + flux kvs namespace-remove fromns-prefix ' -# to namespace +# to namespace, via nsprefix # copy a value, move a dir test_expect_success 'create test namespace' ' - flux kvs namespace-create tons + flux kvs namespace-create tons-prefix ' test_expect_success 'kvs-copy to namespace works' ' - flux kvs unlink -Rf ns:tons/test && + flux kvs unlink -Rf ns:tons-prefix/test && flux kvs unlink -Rf test && flux kvs put test.src=foo && - flux kvs copy test.src ns:tons/test.dst + flux kvs copy test.src ns:tons-prefix/test.dst ' test_expect_success 'kvs-copy to namespace does not unlink src' ' value=$(flux kvs get test.src) && test "$value" = "foo" ' test_expect_success 'kvs-copy to namespace dst contains expected value' ' - value=$(flux kvs get ns:tons/test.dst) && + value=$(flux kvs get ns:tons-prefix/test.dst) && test "$value" = "foo" ' test_expect_success 'kvs-move to namespace works' ' - flux kvs unlink -Rf ns:tons/test && + flux kvs unlink -Rf ns:tons-prefix/test && flux kvs unlink -Rf test && flux kvs put test.src.a.b.c=foo && - flux kvs move test.src ns:tons/test.dst + flux kvs move test.src ns:tons-prefix/test.dst ' test_expect_success 'kvs-move to namespace unlinks src' ' test_must_fail flux kvs get --treeobj test.src ' test_expect_success 'kvs-move to namespace dst contains expected value' ' - value=$(flux kvs get ns:tons/test.dst.a.b.c) && + value=$(flux kvs get ns:tons-prefix/test.dst.a.b.c) && test "$value" = "foo" ' test_expect_success 'remove test namespace' ' - flux kvs namespace-remove tons + flux kvs namespace-remove tons-prefix ' +# from namespace, via option +# copy a value, move a dir + +test_expect_success 'create test namespace' ' + flux kvs namespace-create fromns-option +' + +test_expect_success 'kvs-copy from namespace works' ' + flux kvs unlink -Rf test && + flux kvs --namespace=fromns-option unlink -Rf test && + flux kvs --namespace=fromns-option put test.src=foo && + flux kvs copy --src-namespace=fromns-option test.src test.dst +' +test_expect_success 'kvs-copy from namespace does not unlink src' ' + value=$(flux kvs --namespace=fromns-option get test.src) && + test "$value" = "foo" +' +test_expect_success 'kvs-copy from namespace dst contains expected value' ' + value=$(flux kvs get test.dst) && + test "$value" = "foo" +' + +test_expect_success 'kvs-move from namespace works' ' + flux kvs unlink -Rf test && + flux kvs --namespace=fromns-option unlink -Rf test && + flux kvs --namespace=fromns-option put test.src.a.b.c=foo && + flux kvs move --src-namespace=fromns-option test.src test.dst +' +test_expect_success 'kvs-move from namespace unlinks src' ' + test_must_fail flux kvs --namespace=fromns-option get --treeobj test.src +' +test_expect_success 'kvs-move from namespace dst contains expected value' ' + value=$(flux kvs get test.dst.a.b.c) && + test "$value" = "foo" +' + +test_expect_success 'remove test namespace' ' + flux kvs namespace-remove fromns-option +' + +# to namespace, via option +# copy a value, move a dir + +test_expect_success 'create test namespace' ' + flux kvs namespace-create tons-option +' + +test_expect_success 'kvs-copy to namespace works' ' + flux kvs --namespace=tons-option unlink -Rf test && + flux kvs unlink -Rf test && + flux kvs put test.src=foo && + flux kvs copy --dst-namespace=tons-option test.src test.dst +' +test_expect_success 'kvs-copy to namespace does not unlink src' ' + value=$(flux kvs get test.src) && + test "$value" = "foo" +' +test_expect_success 'kvs-copy to namespace dst contains expected value' ' + value=$(flux kvs --namespace=tons-option get test.dst) && + test "$value" = "foo" +' + +test_expect_success 'kvs-move to namespace works' ' + flux kvs --namespace=tons-option unlink -Rf test && + flux kvs unlink -Rf test && + flux kvs put test.src.a.b.c=foo && + flux kvs move --dst-namespace=tons-option test.src test.dst +' +test_expect_success 'kvs-move to namespace unlinks src' ' + test_must_fail flux kvs get --treeobj test.src +' +test_expect_success 'kvs-move to namespace dst contains expected value' ' + value=$(flux kvs --namespace=tons-option get test.dst.a.b.c) && + test "$value" = "foo" +' + +test_expect_success 'remove test namespace' ' + flux kvs namespace-remove tons-option +' # expected failures