Skip to content

Commit

Permalink
Merge pull request flux-framework#66 from garlick/flux-kvs-types
Browse files Browse the repository at this point in the history
flux-kvs usability improvements
  • Loading branch information
grondo committed Oct 16, 2014
2 parents 084ec7a + c3a6f47 commit c6442fb
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 40 deletions.
9 changes: 7 additions & 2 deletions doc/cmd/flux-kvs.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,19 @@ COMMANDS
Retrieve the value stored under 'key'. If nothing has been stored under
'key', display an error message.

*type* 'key' ['key...']::
Display the JSON type of the value under key: 'null', 'boolean', 'double',
'int', 'object', 'array', or 'string'. If nothing has been stored under
'key', display an error message.

*put* 'key=value' ['key=value...']::
Store 'value' under 'key' and commit it. If it already has a value,
overwrite it.

*dir* 'key'::
*dir* ['key']::
Display all keys and their values under the directory 'key'.
If 'key' does not exist or is not a directory, display an error message.
If 'key' is ".", the entire KVS namespace is dumped.
If 'key' is not provided, "." (root of the namespace) is assumed.

*unlink* 'key' ['key...']::
Remove 'key' from the KVS and commit the change. If 'key' represents
Expand Down
1 change: 1 addition & 0 deletions doc/cmd/spell.en.pws
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,4 @@ tty
uri
usefile
secdir
boolean
124 changes: 104 additions & 20 deletions src/cmd/flux-kvs.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ static const struct option longopts[] = {
};

void cmd_get (flux_t h, int argc, char **argv);
void cmd_type (flux_t h, int argc, char **argv);
void cmd_put (flux_t h, int argc, char **argv);
void cmd_unlink (flux_t h, int argc, char **argv);
void cmd_link (flux_t h, int argc, char **argv);
Expand All @@ -63,6 +64,7 @@ void usage (void)
{
fprintf (stderr,
"Usage: flux-kvs get key [key...]\n"
" flux-kvs type key [key...]\n"
" flux-kvs put key=val [key=val...]\n"
" flux-kvs unlink key [key...]\n"
" flux-kvs link target link_name\n"
Expand All @@ -72,7 +74,7 @@ void usage (void)
" flux-kvs watch-dir key\n"
" flux-kvs copy-tokvs key file\n"
" flux-kvs copy-fromkvs key file\n"
" flux-kvs dir key\n"
" flux-kvs dir [key]\n"
" flux-kvs version\n"
" flux-kvs wait version\n"
" flux-kvs dropcache\n"
Expand Down Expand Up @@ -108,6 +110,8 @@ int main (int argc, char *argv[])

if (!strcmp (cmd, "get"))
cmd_get (h, argc - optind, argv + optind);
else if (!strcmp (cmd, "type"))
cmd_type (h, argc - optind, argv + optind);
else if (!strcmp (cmd, "put"))
cmd_put (h, argc - optind, argv + optind);
else if (!strcmp (cmd, "unlink"))
Expand Down Expand Up @@ -144,6 +148,45 @@ int main (int argc, char *argv[])
return 0;
}

void cmd_type (flux_t h, int argc, char **argv)
{
JSON o;
int i;

if (argc == 0)
msg_exit ("get-type: specify one or more keys");
for (i = 0; i < argc; i++) {
if (kvs_get (h, argv[i], &o) < 0)
err_exit ("%s", argv[i]);
const char *type = "unknown";
switch (json_object_get_type (o)) {
case json_type_null:
type = "null";
break;
case json_type_boolean:
type = "boolean";
break;
case json_type_double:
type = "double";
break;
case json_type_int:
type = "int";
break;
case json_type_object:
type = "object";
break;
case json_type_array:
type = "array";
break;
case json_type_string:
type = "string";
break;
}
printf ("%s\n", type);
Jput (o);
}
}

void cmd_get (flux_t h, int argc, char **argv)
{
JSON o;
Expand All @@ -154,8 +197,28 @@ void cmd_get (flux_t h, int argc, char **argv)
for (i = 0; i < argc; i++) {
if (kvs_get (h, argv[i], &o) < 0)
err_exit ("%s", argv[i]);
else
printf ("%s\n", Jtostr (o));
switch (json_object_get_type (o)) {
case json_type_null:
printf ("nil\n");
break;
case json_type_boolean:
printf ("%s\n", json_object_get_boolean (o) ? "true" : "false");
break;
case json_type_double:
printf ("%f\n", json_object_get_double (o));
break;
case json_type_int:
printf ("%d\n", json_object_get_int (o));
break;
case json_type_string:
printf ("%s\n", json_object_get_string (o));
break;
case json_type_array:
case json_type_object:
default:
printf ("%s\n", Jtostr (o));
break;
}
Jput (o);
}
}
Expand Down Expand Up @@ -360,11 +423,39 @@ void cmd_copy_fromkvs (flux_t h, int argc, char **argv)
free (buf);
}


static void dump_kvs_val (const char *key, JSON o)
{
switch (json_object_get_type (o)) {
case json_type_null:
printf ("%s = nil\n", key);
break;
case json_type_boolean:
printf ("%s = %s\n", key, json_object_get_boolean (o)
? "true" : "false");
break;
case json_type_double:
printf ("%s = %f\n", key, json_object_get_double (o));
break;
case json_type_int:
printf ("%s = %d\n", key, json_object_get_int (o));
break;
case json_type_string:
printf ("%s = %s\n", key, json_object_get_string (o));
break;
case json_type_array:
case json_type_object:
default:
printf ("%s = %s\n", key, Jtostr (o));
break;
}
}

static void dump_kvs_dir (flux_t h, const char *path)
{
kvsdir_t dir;
kvsitr_t itr;
const char *name, *js;
const char *name;
char *key;

if (kvs_get_dir (h, &dir, "%s", path) < 0)
Expand All @@ -375,29 +466,19 @@ static void dump_kvs_dir (flux_t h, const char *path)
key = kvsdir_key_at (dir, name);
if (kvsdir_issymlink (dir, name)) {
char *link;

if (kvs_get_symlink (h, key, &link) < 0)
err_exit ("%s", key);
printf ("%s -> %s\n", key, link);
free (link);

} else if (kvsdir_isdir (dir, name)) {
dump_kvs_dir (h, key);

} else {
json_object *o;
int len, max;

JSON o;
if (kvs_get (h, key, &o) < 0)
err_exit ("%s", key);
js = json_object_to_json_string_ext (o, JSON_C_TO_STRING_PLAIN);
len = strlen (js);
max = 80 - strlen (key) - 4;
if (len > max)
printf ("%s = %.*s ...\n", key, max - 4, js);
else
printf ("%s = %s\n", key, js);
json_object_put (o);
dump_kvs_val (key, o);
Jput (o);
}
free (key);
}
Expand Down Expand Up @@ -434,9 +515,12 @@ void cmd_watch_dir (flux_t h, int argc, char **argv)

void cmd_dir (flux_t h, int argc, char **argv)
{
if (argc != 1)
msg_exit ("dir: specify one directory");
dump_kvs_dir (h, argv[0]);
if (argc == 0)
dump_kvs_dir (h, ".");
else if (argc == 1)
dump_kvs_dir (h, argv[0]);
else
msg_exit ("dir: specify zero or one directory");
}

/*
Expand Down
64 changes: 46 additions & 18 deletions t/t1000-kvs-basic.t
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ test_kvs_key() {
#fi
}

test_kvs_type () {
flux kvs type "$1" >output
echo "$2" >expected
test_cmp output expected
}

test_expect_success 'kvs: get a nonexistent key' '
test_must_fail flux kvs get NOT.A.KEY
'
Expand All @@ -35,6 +41,9 @@ test_expect_success 'kvs: get a nonexistent key' '
test_expect_success 'kvs: integer put' '
flux kvs put $KEY=42
'
test_expect_success 'kvs: integer type' '
test_kvs_type $KEY int
'
test_expect_success 'kvs: integer get' '
test_kvs_key $KEY 42
'
Expand All @@ -44,46 +53,65 @@ test_expect_success 'kvs: unlink works' '
'
test_expect_success 'kvs: value can be empty' '
flux kvs put $KEY= &&
test_kvs_key $KEY "\"\""
test_kvs_key $KEY "" &&
test_kvs_type $KEY string
'
KEY=$TEST.b.c.d
DIR=$TEST.b.c
test_expect_success 'kvs: string put' '
flux kvs put $KEY="Hello world"
'
test_expect_success 'kvs: string get' '
test_kvs_key $KEY "\"Hello world\""
test_expect_success 'kvs: string type' '
test_kvs_type $KEY string
'
test_expect_success 'kvs: unlink works' '
flux kvs unlink $KEY &&
test_must_fail flux kvs get $KEY
test_expect_success 'kvs: string get' '
test_kvs_key $KEY "Hello world"
'
test_expect_success 'kvs: boolean put (true)' '
flux kvs put $KEY=true
'
test_expect_success 'kvs: boolean type' '
test_kvs_type $KEY boolean
'
test_expect_success 'kvs: boolean get (true)' '
test_kvs_key $KEY true
'
test_expect_success 'kvs: unlink works' '
flux kvs unlink $KEY &&
test_must_fail flux kvs get $KEY
'
test_expect_success 'kvs: boolean put (false)' '
flux kvs put $KEY=false
'
test_expect_success 'kvs: boolean type' '
test_kvs_type $KEY boolean
'
test_expect_success 'kvs: boolean get (false)' '
test_kvs_key $KEY false
'
test_expect_success 'kvs: unlink works' '
flux kvs unlink $KEY &&
test_must_fail flux kvs get $KEY
'
test_expect_success 'kvs: put double' '
flux kvs put $KEY=3.14159
'
test_expect_success 'kvs: double type' '
test_kvs_type $KEY double
'
test_expect_success 'kvs: get double' '
test_kvs_key $KEY 3.141590
'
test_expect_success 'kvs: array put' '
flux kvs put $KEY="[1,3,5,7]"
'
test_expect_success 'kvs: array type' '
test_kvs_type $KEY array
'
test_expect_success 'kvs: array get' '
test_kvs_key $KEY "[ 1, 3, 5, 7 ]"
'
test_expect_success 'kvs: object put' '
flux kvs put $KEY="{\"a\":42}"
'
test_expect_success 'kvs: object type' '
test_kvs_type $KEY object
'
test_expect_success 'kvs: object get' '
test_kvs_key $KEY "{ \"a\": 42 }"
'
test_expect_success 'kvs: try to retrieve key as directory should fail' '
test_must_fail flux kvs dir $KEY
'
Expand Down Expand Up @@ -113,7 +141,7 @@ test_expect_success 'kvs: put values in a directory then retrieve them' '
$DIR.a = 69
$DIR.b = 70
$DIR.c = 3.140000
$DIR.d = "snerg"
$DIR.d = snerg
$DIR.e = true
EOF
test_cmp expected output
Expand All @@ -126,7 +154,7 @@ test_expect_success 'kvs: create a dir with keys and subdir' '
$DIR.a = 69
$DIR.b = 70
$DIR.c.d.e.f.g = 3.140000
$DIR.d = "snerg"
$DIR.d = snerg
$DIR.e = true
EOF
test_cmp expected output
Expand All @@ -140,7 +168,7 @@ test_expect_success 'kvs: directory with multiple subdirs' '
$DIR.a = 69
$DIR.b.c.d.e.f.g = 70
$DIR.c.a.b = 3.140000
$DIR.d = "snerg"
$DIR.d = snerg
$DIR.e = true
EOF
test_cmp expected output
Expand All @@ -154,7 +182,7 @@ test_expect_success 'kvs: symlink: works' '
flux kvs put $TARGET=\"foo\" &&
flux kvs link $TARGET $TEST.Q &&
OUTPUT=$(flux kvs get $TEST.Q) &&
test "$OUTPUT" = "\"foo\""
test "$OUTPUT" = "foo"
'
test_expect_success 'kvs: symlink: path resolution when intermediate component is a symlink' '
flux kvs unlink $TEST &&
Expand Down

0 comments on commit c6442fb

Please sign in to comment.