Commit 6681443a authored by Sebastien Gougeaud's avatar Sebastien Gougeaud Committed by Thomas Leibovici
Browse files

cli: add metadata option to 'phobos object list'



Add a metadata option to the 'phobos object list' command, which
retrieves the oid if they contain the given metadata.

Change-Id: I8c773957531355fa8e79983f15427dde6fed0585
Signed-off-by: default avatarSebastien Gougeaud <sebastien.gougeaud@cea.fr>
Reviewed-on: https://gerrit.ccc.ocre.cea.fr/gerrit/c/phobos/+/6876

Tested-by: default avatarJenkins s8open_nr <s8open_nr@ccc.ocre.cea.fr>
Reviewed-by: default avatarThomas Leibovici <thomas.leibovici@cea.fr>
Reviewed-by: default avatarQuentin Bouget <quentin.bouget@cea.fr>
parent c04d184b
......@@ -235,6 +235,11 @@ Regular Expressions (ERE). As defined in [PostgreSQL manual](https://www.postgre
PSQL also accepts Advanced Regular Expressions (ARE), but we will not maintain
this feature as ARE is not a POSIX standard.
The option '-m' applies a filter on user metadata
```
phobos object list -m user=foo,test=abd
```
## Device and media management
### Listing resources
Any device or media can be listed using the 'list' operation. For instance,
......
......@@ -35,6 +35,7 @@ Other operators are available. They are used as such:
- $LIKE: pattern matching, wildcard is '%'
- $REGEXP: posix regexp matching
- $INJSON: json inclusion test
- $KVINJSON: json key-value inclusion test
- $XJSON: json existence test
== Boolean combinators ==
......
......@@ -562,6 +562,9 @@ class ObjectListOptHandler(PatternListOptHandler):
help="attributes to output, comma-separated, "
"choose from {" + " ".join(attrs) + "} "
"default: %(default)s)")
parser.add_argument('-m', '--metadata', type=lambda t: t.split(','),
help="filter on metadata, comma-separated "
"'key=value' parameters")
class TapeAddOptHandler(MediaAddOptHandler):
"""Specific version of the 'add' command for tapes, with extra-options."""
......@@ -638,6 +641,14 @@ class ObjectOptHandler(BaseResourceOptHandler):
if self.params.get('pattern'):
kwargs["pattern"] = self.params.get('pattern')
if self.params.get('metadata'):
kwargs["metadata"] = self.params.get('metadata')
for metadata in kwargs["metadata"]:
if not '=' in metadata:
self.logger.error("Metadata parameter '%s' must be a "
"'key=value'", metadata)
sys.exit(os.EX_USAGE)
objs = self.client.objects.get(**kwargs)
if len(objs) > 0:
......
......@@ -53,7 +53,8 @@ FILTER_OPERATORS = (
('__like', '$LIKE'),
('__regexp', '$REGEXP'),
('__jcontain', '$INJSON'),
('__jexist', '$XJSON')
('__jkeyval', '$KVINJSON'),
('__jexist', '$XJSON'),
)
OBJECT_PREFIXES = {
......@@ -192,6 +193,7 @@ class BaseEntityManager(object):
# by the dss filter
kwargs = self.convert_kwargs('tags', 'tags__jexist', **kwargs)
kwargs = self.convert_kwargs('pattern', 'oid__regexp', **kwargs)
kwargs = self.convert_kwargs('metadata', 'user_md__jkeyval', **kwargs)
filt = dss_filter(self.wrapped_ident, **kwargs)
if filt is not None:
......
......@@ -108,6 +108,7 @@ class CLIParametersTest(unittest.TestCase):
self.check_cmdline_valid(['object', 'list', '-o', '*'])
self.check_cmdline_valid(['object', 'list', '-o', 'oid'])
self.check_cmdline_valid(['object', 'list', '-o', 'all', '"obj.*"'])
self.check_cmdline_valid(['object', 'list', '-m', 'user=foo,test=abd'])
# Test invalid object and invalid verb
self.check_cmdline_exit(['voynichauthor', 'list'], code=2)
......
......@@ -1382,10 +1382,23 @@ static inline bool key_is_logical_op(const char *key)
!g_ascii_strcasecmp(key, "$OR");
}
static int insert_string(GString *qry, const char *strval, bool is_idx)
/**
* This enum is used to define the type of the string value retrieved from the
* DSS filter.
*/
enum strvalue_type {
STRVAL_DEFAULT = 0, /* default string value */
STRVAL_INDEX = 1, /* index of an array */
STRVAL_KEYVAL = 2 /* key/value pair in an array */
};
static int insert_string(GString *qry, const char *strval,
enum strvalue_type type)
{
size_t esc_len = strlen(strval) * 2 + 1;
char *esc_str;
char *esc_val;
int rc = 0;
esc_str = malloc(esc_len);
if (!esc_str)
......@@ -1398,23 +1411,33 @@ static int insert_string(GString *qry, const char *strval, bool is_idx)
*/
PQescapeString(esc_str, strval, esc_len);
if (is_idx)
switch (type) {
case STRVAL_INDEX:
g_string_append_printf(qry, "array['%s']", esc_str);
else
break;
case STRVAL_KEYVAL:
esc_val = strchr(esc_str, '=');
assert(esc_val);
*esc_val++ = '\0';
g_string_append_printf(qry, "'{\"%s\": \"%s\"}'", esc_str, esc_val);
break;
default:
g_string_append_printf(qry, "'%s'", esc_str);
}
free(esc_str);
return 0;
return rc;
}
static int json2sql_object_begin(struct saj_parser *parser, const char *key,
json_t *value, void *priv)
{
const char *current_key = saj_parser_key(parser);
const char *field_impl;
GString *str = priv;
bool str_index = false;
int rc;
const char *current_key = saj_parser_key(parser);
enum strvalue_type type = STRVAL_DEFAULT;
const char *field_impl;
GString *str = priv;
int rc;
/* out-of-context: nothing to do */
if (!key)
......@@ -1449,7 +1472,10 @@ static int json2sql_object_begin(struct saj_parser *parser, const char *key,
g_string_append(str, " ~ ");
} else if (!g_ascii_strcasecmp(current_key, "$INJSON")) {
g_string_append(str, " @> ");
str_index = true;
type = STRVAL_INDEX;
} else if (!g_ascii_strcasecmp(current_key, "$KVINJSON")) {
g_string_append(str, " @> ");
type = STRVAL_KEYVAL;
} else if (!g_ascii_strcasecmp(current_key, "$XJSON")) {
g_string_append(str, " ? ");
} else {
......@@ -1458,7 +1484,7 @@ static int json2sql_object_begin(struct saj_parser *parser, const char *key,
switch (json_typeof(value)) {
case JSON_STRING:
rc = insert_string(str, json_string_value(value), str_index);
rc = insert_string(str, json_string_value(value), type);
if (rc)
LOG_RETURN(rc, "Cannot insert string into SQL query");
break;
......
......@@ -134,6 +134,8 @@ echo "**** TESTS: DSS_GET OBJECT ****"
test_check_get "object" 'all'
test_check_get "object" '{"$LIKE": {"DSS::OBJ::oid": "012%"}}'
test_check_get "object" '{"$LIKE": {"DSS::OBJ::oid": "koéèê^!$£}[<>à@\\"}}'
test_check_get "object" \
'{"$KVINJSON": {"DSS::OBJ::user_md": "test=abc"}}'
echo "**** TESTS: DSS_GET LAYOUT ****"
test_check_get "layout" 'all'
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment