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 9973dc945ed6..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, srckey, 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, srckey, 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/src/common/libkvs/Makefile.am b/src/common/libkvs/Makefile.am index 1caa22e44e06..918b1d0c48f6 100644 --- a/src/common/libkvs/Makefile.am +++ b/src/common/libkvs/Makefile.am @@ -16,12 +16,14 @@ noinst_LTLIBRARIES = libkvs.la libkvs_la_SOURCES = \ kvs.c \ kvs_lookup.c \ + kvs_lookup_private.h \ kvs_getroot.c \ kvs_dir.c \ kvs_dir_private.h \ kvs_classic.c \ kvs_watch.c \ kvs_commit.c \ + kvs_commit_private.h \ kvs_txn.c \ kvs_txn_private.h \ treeobj.h \ diff --git a/src/common/libkvs/kvs_commit.c b/src/common/libkvs/kvs_commit.c index 3076173e51ca..49729095bd61 100644 --- a/src/common/libkvs/kvs_commit.c +++ b/src/common/libkvs/kvs_commit.c @@ -46,19 +46,18 @@ flux_future_t *flux_kvs_fence (flux_t *h, int flags, const char *name, "ops", ops); } -flux_future_t *flux_kvs_commit (flux_t *h, int flags, flux_kvs_txn_t *txn) +flux_future_t *flux_kvs_commit_ns (flux_t *h, + const char *namespace, + int flags, + flux_kvs_txn_t *txn) { - const char *namespace; json_t *ops; - if (!txn) { + if (!txn || !namespace) { errno = EINVAL; return NULL; } - if (!(namespace = flux_kvs_get_namespace (h))) - return NULL; - if (!(ops = txn_get_ops (txn))) { errno = EINVAL; return NULL; @@ -71,6 +70,16 @@ flux_future_t *flux_kvs_commit (flux_t *h, int flags, flux_kvs_txn_t *txn) "ops", ops); } +flux_future_t *flux_kvs_commit (flux_t *h, int flags, flux_kvs_txn_t *txn) +{ + const char *namespace; + + if (!(namespace = flux_kvs_get_namespace (h))) + return NULL; + + return flux_kvs_commit_ns (h, namespace, flags, txn); +} + /* * vi:tabstop=4 shiftwidth=4 expandtab */ diff --git a/src/common/libkvs/kvs_commit_private.h b/src/common/libkvs/kvs_commit_private.h new file mode 100644 index 000000000000..0a468b2dbf1b --- /dev/null +++ b/src/common/libkvs/kvs_commit_private.h @@ -0,0 +1,23 @@ +/************************************************************\ + * Copyright 2019 Lawrence Livermore National Security, LLC + * (c.f. AUTHORS, NOTICE.LLNS, COPYING) + * + * This file is part of the Flux resource manager framework. + * For details, see https://github.com/flux-framework. + * + * SPDX-License-Identifier: LGPL-3.0 +\************************************************************/ + +#ifndef _KVS_COMMIT_PRIVATE_H +#define _KVS_COMMIT_PRIVATE_H + +flux_future_t *flux_kvs_commit_ns (flux_t *h, + const char *namespace, + int flags, + flux_kvs_txn_t *txn); + +#endif /* !_KVS_COMMIT_PRIVATE_H */ + +/* + * vi:tabstop=4 shiftwidth=4 expandtab + */ diff --git a/src/common/libkvs/kvs_copy.c b/src/common/libkvs/kvs_copy.c index b70c00c278e5..43239fa3aaaa 100644 --- a/src/common/libkvs/kvs_copy.c +++ b/src/common/libkvs/kvs_copy.c @@ -21,10 +21,14 @@ #include #include "kvs_copy.h" +#include "kvs_commit_private.h" +#include "kvs_lookup_private.h" struct copy_context { int commit_flags; + char *srcns; char *srckey; + char *dstns; char *dstkey; }; @@ -32,14 +36,18 @@ static void copy_context_destroy (struct copy_context *ctx) { if (ctx) { int saved_errno = errno; + free (ctx->srcns); free (ctx->srckey); + free (ctx->dstns); free (ctx->dstkey); free (ctx); errno = saved_errno; } } -static struct copy_context *copy_context_create (const char *srckey, +static struct copy_context *copy_context_create (const char *srcns, + const char *srckey, + const char *dstns, const char *dstkey, int commit_flags) { @@ -47,7 +55,10 @@ static struct copy_context *copy_context_create (const char *srckey, if (!(ctx = calloc (1, sizeof (*ctx)))) return NULL; - if (!(ctx->srckey = strdup (srckey)) || !(ctx->dstkey = strdup (dstkey))) { + if ((srcns && !(ctx->srcns = strdup (srcns))) + || !(ctx->srckey = strdup (srckey)) + || (dstns && !(ctx->dstns = strdup (dstns))) + || !(ctx->dstkey = strdup (dstkey))) { copy_context_destroy (ctx); return NULL; } @@ -76,8 +87,14 @@ static void copy_continuation (flux_future_t *f, void *arg) goto error; if (flux_kvs_txn_unlink (txn, 0, ctx->srckey) < 0) goto error; - if (!(f2 = flux_kvs_commit (h, ctx->commit_flags, txn))) - goto error; + if (ctx->srcns) { + if (!(f2 = flux_kvs_commit_ns (h, ctx->srcns, ctx->commit_flags, txn))) + goto error; + } + else { + if (!(f2 = flux_kvs_commit (h, ctx->commit_flags, txn))) + goto error; + } if (flux_future_continue (f, f2) < 0) { flux_future_destroy (f2); goto error; @@ -110,8 +127,14 @@ static void lookup_continuation (flux_future_t *f, void *arg) goto error; if (flux_kvs_txn_put_treeobj (txn, 0, ctx->dstkey, val) < 0) goto error; - if (!(f2 = flux_kvs_commit (h, ctx->commit_flags, txn))) - goto error; + if (ctx->dstns) { + if (!(f2 = flux_kvs_commit_ns (h, ctx->dstns, ctx->commit_flags, txn))) + goto error; + } + else { + if (!(f2 = flux_kvs_commit (h, ctx->commit_flags, txn))) + goto error; + } if (flux_future_continue (f, f2) < 0) { flux_future_destroy (f2); goto error; @@ -124,9 +147,12 @@ static void lookup_continuation (flux_future_t *f, void *arg) flux_kvs_txn_destroy (txn); } -flux_future_t *flux_kvs_copy (flux_t *h, const char *srckey, - const char *dstkey, - int commit_flags) +flux_future_t *flux_kvs_copy (flux_t *h, + const char *srcns, + const char *srckey, + const char *dstns, + const char *dstkey, + int commit_flags) { struct copy_context *ctx; flux_future_t *f1; @@ -136,9 +162,19 @@ flux_future_t *flux_kvs_copy (flux_t *h, const char *srckey, errno = EINVAL; return NULL; } - if (!(f1 = flux_kvs_lookup (h, FLUX_KVS_TREEOBJ, srckey))) - return NULL; - if (!(ctx = copy_context_create (srckey, dstkey, commit_flags))) + if (srcns) { + if (!(f1 = flux_kvs_lookup_ns (h, srcns, FLUX_KVS_TREEOBJ, srckey))) + return NULL; + } + else { + if (!(f1 = flux_kvs_lookup (h, FLUX_KVS_TREEOBJ, srckey))) + return NULL; + } + if (!(ctx = copy_context_create (srcns, + srckey, + dstns, + dstkey, + commit_flags))) goto error; if (flux_aux_set (h, NULL, ctx, (flux_free_f)copy_context_destroy) < 0) { copy_context_destroy (ctx); @@ -152,9 +188,12 @@ flux_future_t *flux_kvs_copy (flux_t *h, const char *srckey, return NULL; } -flux_future_t *flux_kvs_move (flux_t *h, const char *srckey, - const char *dstkey, - int commit_flags) +flux_future_t *flux_kvs_move (flux_t *h, + const char *srcns, + const char *srckey, + const char *dstns, + const char *dstkey, + int commit_flags) { struct copy_context *ctx; flux_future_t *f1; @@ -164,9 +203,13 @@ flux_future_t *flux_kvs_move (flux_t *h, const char *srckey, errno = EINVAL; return NULL; } - if (!(f1 = flux_kvs_copy (h, srckey, dstkey, commit_flags))) + if (!(f1 = flux_kvs_copy (h, srcns, srckey, dstns, dstkey, commit_flags))) return NULL; - if (!(ctx = copy_context_create (srckey, dstkey, commit_flags))) + if (!(ctx = copy_context_create (srcns, + srckey, + dstns, + dstkey, + commit_flags))) goto error; if (flux_aux_set (h, NULL, ctx, (flux_free_f)copy_context_destroy) < 0) { copy_context_destroy (ctx); diff --git a/src/common/libkvs/kvs_copy.h b/src/common/libkvs/kvs_copy.h index 862f598c5523..dd5263efc731 100644 --- a/src/common/libkvs/kvs_copy.h +++ b/src/common/libkvs/kvs_copy.h @@ -15,26 +15,39 @@ extern "C" { #endif -/* Create a copy of 'srckey' at 'dstkey'. +/* Create a copy of 'srckey' at 'dstkey'. Read from / write to the + * specified namespaces. If a namespace is not specified (i.e. NULL), + * the namespace from flux_kvs_get_namespace() will be used. + * * Due to the hash-tree design of the KVS, dstkey is by definition a * "deep copy" (or writable snapshot) of all content below srckey. * The copy operation has a low overhead since it only copies a single - * directory entry. 'srckey' and 'dstkey' may be in different namespaces. + * directory entry. + * * Returns future on success, NULL on failure with errno set. */ -flux_future_t *flux_kvs_copy (flux_t *h, const char *srckey, - const char *dstkey, - int commit_flags); +flux_future_t *flux_kvs_copy (flux_t *h, + const char *srcns, + const char *srckey, + const char *dstns, + const char *dstkey, + int commit_flags); -/* Move 'srckey' to 'dstkey'. - * This is a copy followed by an unlink on 'srckey'. - * 'srckey' and 'dstkey' may be in different namespaces. - * The copy and unlink are not atomic. +/* Move 'srckey' to 'dstkey'. Read from / write to the + * specified namespaces. If a namespace is not specified (i.e. NULL), + * the namespace from flux_kvs_get_namespace() will be used. + * + * This is a copy followed by an unlink on 'srckey'. The copy and + * unlink are not atomic. + * * Returns future on success, NULL on failure with errno set. */ -flux_future_t *flux_kvs_move (flux_t *h, const char *srckey, - const char *dstkey, - int commit_flags); +flux_future_t *flux_kvs_move (flux_t *h, + const char *srcns, + const char *srckey, + const char *dstns, + const char *dstkey, + int commit_flags); #ifdef __cplusplus } diff --git a/src/common/libkvs/kvs_lookup.c b/src/common/libkvs/kvs_lookup.c index 056c72763c35..77e6ded8e558 100644 --- a/src/common/libkvs/kvs_lookup.c +++ b/src/common/libkvs/kvs_lookup.c @@ -104,20 +104,20 @@ static int validate_lookup_flags (int flags, bool watch_ok) } } -flux_future_t *flux_kvs_lookup (flux_t *h, int flags, const char *key) +flux_future_t *flux_kvs_lookup_ns (flux_t *h, + const char *namespace, + int flags, + const char *key) { struct lookup_ctx *ctx; flux_future_t *f; - const char *namespace; const char *topic = "kvs.lookup"; - if (!h || !key || strlen (key) == 0 + if (!h || !namespace || !key || strlen (key) == 0 || validate_lookup_flags (flags, true) < 0) { errno = EINVAL; return NULL; } - if (!(namespace = flux_kvs_get_namespace (h))) - return NULL; if (!(ctx = alloc_ctx (h, flags, key))) return NULL; if ((flags & FLUX_KVS_WATCH) @@ -139,6 +139,15 @@ flux_future_t *flux_kvs_lookup (flux_t *h, int flags, const char *key) return f; } +flux_future_t *flux_kvs_lookup (flux_t *h, int flags, const char *key) +{ + const char *namespace; + + if (!(namespace = flux_kvs_get_namespace (h))) + return NULL; + return flux_kvs_lookup_ns (h, namespace, flags, key); +} + flux_future_t *flux_kvs_lookupat (flux_t *h, int flags, const char *key, const char *treeobj) { diff --git a/src/common/libkvs/kvs_lookup_private.h b/src/common/libkvs/kvs_lookup_private.h new file mode 100644 index 000000000000..a90d9e159bd4 --- /dev/null +++ b/src/common/libkvs/kvs_lookup_private.h @@ -0,0 +1,23 @@ +/************************************************************\ + * Copyright 2019 Lawrence Livermore National Security, LLC + * (c.f. AUTHORS, NOTICE.LLNS, COPYING) + * + * This file is part of the Flux resource manager framework. + * For details, see https://github.com/flux-framework. + * + * SPDX-License-Identifier: LGPL-3.0 +\************************************************************/ + +#ifndef _KVS_LOOKUP_PRIVATE_H +#define _KVS_LOOKUP_PRIVATE_H + +flux_future_t *flux_kvs_lookup_ns (flux_t *h, + const char *namespace, + int flags, + const char *key); + +#endif /* !_KVS_LOOKUP_PRIVATE_H */ + +/* + * vi:tabstop=4 shiftwidth=4 expandtab + */ diff --git a/src/common/libkvs/kvs_txn.c b/src/common/libkvs/kvs_txn.c index 8195acdb57d0..f7438d82dbde 100644 --- a/src/common/libkvs/kvs_txn.c +++ b/src/common/libkvs/kvs_txn.c @@ -183,7 +183,7 @@ int flux_kvs_txn_vpack (flux_kvs_txn_t *txn, int flags, int saved_errno; char *s; - if (!txn || !key | !fmt) { + if (!txn || !key || !fmt) { errno = EINVAL; goto error; } @@ -290,7 +290,7 @@ int flux_kvs_txn_symlink (flux_kvs_txn_t *txn, int flags, json_t *dirent = NULL; int saved_errno; - if (!txn || !key | !target) { + if (!txn || !key || !target) { errno = EINVAL; goto error; } diff --git a/src/common/libkvs/test/kvs_copy.c b/src/common/libkvs/test/kvs_copy.c index 632a90962d5f..9c16e5e2d2fb 100644 --- a/src/common/libkvs/test/kvs_copy.c +++ b/src/common/libkvs/test/kvs_copy.c @@ -25,23 +25,29 @@ int main (int argc, char *argv[]) plan (NO_PLAN); errno = 0; - ok (flux_kvs_copy (NULL, "a", "b", 0) == NULL && errno == EINVAL, + ok (flux_kvs_copy (NULL, NULL, "a", NULL, "b", 0) == NULL + && errno == EINVAL, "flux_kvs_copy h=NULL fails with EINVAL"); errno = 0; - ok (flux_kvs_copy (h, NULL, "b", 0) == NULL && errno == EINVAL, + ok (flux_kvs_copy (h, NULL, NULL, NULL, "b", 0) == NULL + && errno == EINVAL, "flux_kvs_copy srckey=NULL fails with EINVAL"); errno = 0; - ok (flux_kvs_copy (h, "a", NULL, 0) == NULL && errno == EINVAL, + ok (flux_kvs_copy (h, NULL, "a", NULL, NULL, 0) == NULL + && errno == EINVAL, "flux_kvs_copy srckey=NULL fails with EINVAL"); errno = 0; - ok (flux_kvs_move (NULL, "a", "b", 0) == NULL && errno == EINVAL, + ok (flux_kvs_move (NULL, NULL, "a", NULL, "b", 0) == NULL + && errno == EINVAL, "flux_kvs_move h=NULL fails with EINVAL"); errno = 0; - ok (flux_kvs_move (h, NULL, "b", 0) == NULL && errno == EINVAL, + ok (flux_kvs_move (h, NULL, NULL, NULL, "b", 0) == NULL + && errno == EINVAL, "flux_kvs_move srckey=NULL fails with EINVAL"); errno = 0; - ok (flux_kvs_move (h, "a", NULL, 0) == NULL && errno == EINVAL, + ok (flux_kvs_move (h, NULL, "a", NULL, NULL, 0) == NULL + && errno == EINVAL, "flux_kvs_move srckey=NULL fails with EINVAL"); done_testing(); 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