[prev in list] [next in list] [prev in thread] [next in thread]
List: openvswitch-dev
Subject: [ovs-dev] [PATCH 2/3] ovsdb: Add support for "enum" constraints.
From: blp () nicira ! com (Ben Pfaff)
Date: 2010-02-24 0:08:44
Message-ID: 1266970125-25402-2-git-send-email-blp () nicira ! com
[Download RAW message or body]
Some of the uses for the formerly supported regular expression constraints
were simply to constraint values to those in a set of allowed values.
This commit adds support for that kind of simple enumeration constraint.
---
lib/ovsdb-data.c | 52 +++++++++++++----
lib/ovsdb-data.h | 7 ++-
lib/ovsdb-parser.h | 2 +
lib/ovsdb-types.c | 62 ++++++++++++++++++-
lib/ovsdb-types.h | 6 ++
ovsdb/SPECS | 8 +++
ovsdb/mutation.c | 2 +-
ovsdb/ovsdb-idlc.in | 140 +++++++++++++++++++++++++++++++++++++++++++-
tests/ovs-vsctl.at | 3 +
tests/ovsdb-data.at | 75 +++++++++++++++++++++++-
tests/ovsdb-types.at | 15 +++++
vswitchd/vswitch.ovsschema | 6 +-
12 files changed, 356 insertions(+), 22 deletions(-)
diff --git a/lib/ovsdb-data.c b/lib/ovsdb-data.c
index 9d8eab8..42fdf1e 100644
--- a/lib/ovsdb-data.c
+++ b/lib/ovsdb-data.c
@@ -590,6 +590,25 @@ struct ovsdb_error *
ovsdb_atom_check_constraints(const union ovsdb_atom *atom,
const struct ovsdb_base_type *base)
{
+ if (base->enum_
+ && ovsdb_datum_find_key(base->enum_, atom, base->type) == UINT_MAX) {
+ struct ovsdb_error *error;
+ struct ds actual = DS_EMPTY_INITIALIZER;
+ struct ds valid = DS_EMPTY_INITIALIZER;
+
+ ovsdb_atom_to_string(atom, base->type, &actual);
+ ovsdb_datum_to_string(base->enum_,
+ ovsdb_base_type_get_enum_type(base->type),
+ &valid);
+ error = ovsdb_error("constraint violation",
+ "%s is not one of the allowed values (%s)",
+ ds_cstr(&actual), ds_cstr(&valid));
+ ds_destroy(&actual);
+ ds_destroy(&valid);
+
+ return error;
+ }
+
switch (base->type) {
case OVSDB_TYPE_VOID:
NOT_REACHED();
@@ -777,7 +796,7 @@ ovsdb_datum_swap(struct ovsdb_datum *a, struct ovsdb_datum *b)
}
struct ovsdb_datum_sort_cbdata {
- const struct ovsdb_type *type;
+ enum ovsdb_atomic_type key_type;
struct ovsdb_datum *datum;
};
@@ -788,7 +807,7 @@ ovsdb_datum_sort_compare_cb(size_t a, size_t b, void *cbdata_)
return ovsdb_atom_compare_3way(&cbdata->datum->keys[a],
&cbdata->datum->keys[b],
- cbdata->type->key.type);
+ cbdata->key_type);
}
static void
@@ -797,13 +816,13 @@ ovsdb_datum_sort_swap_cb(size_t a, size_t b, void *cbdata_)
struct ovsdb_datum_sort_cbdata *cbdata = cbdata_;
ovsdb_atom_swap(&cbdata->datum->keys[a], &cbdata->datum->keys[b]);
- if (cbdata->type->value.type != OVSDB_TYPE_VOID) {
+ if (cbdata->datum->values) {
ovsdb_atom_swap(&cbdata->datum->values[a], &cbdata->datum->values[b]);
}
}
struct ovsdb_error *
-ovsdb_datum_sort(struct ovsdb_datum *datum, const struct ovsdb_type *type)
+ovsdb_datum_sort(struct ovsdb_datum *datum, enum ovsdb_atomic_type key_type)
{
if (datum->n < 2) {
return NULL;
@@ -811,15 +830,15 @@ ovsdb_datum_sort(struct ovsdb_datum *datum, const struct \
ovsdb_type *type) struct ovsdb_datum_sort_cbdata cbdata;
size_t i;
- cbdata.type = type;
+ cbdata.key_type = key_type;
cbdata.datum = datum;
sort(datum->n, ovsdb_datum_sort_compare_cb, ovsdb_datum_sort_swap_cb,
&cbdata);
for (i = 0; i < datum->n - 1; i++) {
if (ovsdb_atom_equals(&datum->keys[i], &datum->keys[i + 1],
- type->key.type)) {
- if (ovsdb_type_is_map(type)) {
+ key_type)) {
+ if (datum->values) {
return ovsdb_error(NULL, "map contains duplicate key");
} else {
return ovsdb_error(NULL, "set contains duplicate");
@@ -831,6 +850,16 @@ ovsdb_datum_sort(struct ovsdb_datum *datum, const struct \
ovsdb_type *type) }
}
+void
+ovsdb_datum_sort_assert(struct ovsdb_datum *datum,
+ enum ovsdb_atomic_type key_type)
+{
+ struct ovsdb_error *error = ovsdb_datum_sort(datum, key_type);
+ if (error) {
+ NOT_REACHED();
+ }
+}
+
/* Checks that each of the atoms in 'datum' conforms to the constraints
* specified by its 'type'. Returns an error if a constraint is violated,
* otherwise a null pointer.
@@ -931,7 +960,7 @@ ovsdb_datum_from_json(struct ovsdb_datum *datum,
datum->n++;
}
- error = ovsdb_datum_sort(datum, type);
+ error = ovsdb_datum_sort(datum, type->key.type);
if (error) {
goto error;
}
@@ -1128,7 +1157,7 @@ ovsdb_datum_from_string(struct ovsdb_datum *datum,
goto error;
}
- dberror = ovsdb_datum_sort(datum, type);
+ dberror = ovsdb_datum_sort(datum, type->key.type);
if (dberror) {
ovsdb_error_destroy(dberror);
if (ovsdb_type_is_map(type)) {
@@ -1424,7 +1453,7 @@ ovsdb_datum_union(struct ovsdb_datum *a, const struct \
ovsdb_datum *b, if (n != a->n) {
struct ovsdb_error *error;
a->n = n;
- error = ovsdb_datum_sort(a, type);
+ error = ovsdb_datum_sort(a, type->key.type);
assert(!error);
}
}
@@ -1452,8 +1481,7 @@ ovsdb_datum_subtract(struct ovsdb_datum *a, const struct \
ovsdb_type *a_type, }
}
if (changed) {
- struct ovsdb_error *error = ovsdb_datum_sort(a, a_type);
- assert(!error);
+ ovsdb_datum_sort_assert(a, a_type->key.type);
}
}
diff --git a/lib/ovsdb-data.h b/lib/ovsdb-data.h
index 063536b..a5c49f9 100644
--- a/lib/ovsdb-data.h
+++ b/lib/ovsdb-data.h
@@ -122,7 +122,12 @@ void ovsdb_datum_swap(struct ovsdb_datum *, struct ovsdb_datum \
*);
/* Checking and maintaining invariants. */
struct ovsdb_error *ovsdb_datum_sort(struct ovsdb_datum *,
- const struct ovsdb_type *);
+ enum ovsdb_atomic_type key_type)
+ WARN_UNUSED_RESULT;
+
+void ovsdb_datum_sort_assert(struct ovsdb_datum *,
+ enum ovsdb_atomic_type key_type);
+
struct ovsdb_error *ovsdb_datum_check_constraints(
const struct ovsdb_datum *, const struct ovsdb_type *)
WARN_UNUSED_RESULT;
diff --git a/lib/ovsdb-parser.h b/lib/ovsdb-parser.h
index a27563a..d6270bb 100644
--- a/lib/ovsdb-parser.h
+++ b/lib/ovsdb-parser.h
@@ -49,6 +49,8 @@ enum ovsdb_parser_types {
OP_INTEGER = 1 << JSON_INTEGER, /* 123. */
OP_NONINTEGER = 1 << JSON_REAL, /* 123.456. */
OP_STRING = 1 << JSON_STRING, /* "..." */
+ OP_ANY = (OP_NULL | OP_FALSE | OP_TRUE | OP_OBJECT | OP_ARRAY
+ | OP_INTEGER | OP_NONINTEGER | OP_STRING),
OP_BOOLEAN = OP_FALSE | OP_TRUE,
OP_NUMBER = OP_INTEGER | OP_NONINTEGER,
diff --git a/lib/ovsdb-types.c b/lib/ovsdb-types.c
index 5da7145..df18ee5 100644
--- a/lib/ovsdb-types.c
+++ b/lib/ovsdb-types.c
@@ -22,6 +22,7 @@
#include "dynamic-string.h"
#include "json.h"
+#include "ovsdb-data.h"
#include "ovsdb-error.h"
#include "ovsdb-parser.h"
@@ -115,6 +116,7 @@ void
ovsdb_base_type_init(struct ovsdb_base_type *base, enum ovsdb_atomic_type type)
{
base->type = type;
+ base->enum_ = NULL;
switch (base->type) {
case OVSDB_TYPE_VOID:
@@ -151,12 +153,37 @@ ovsdb_base_type_init(struct ovsdb_base_type *base, enum \
ovsdb_atomic_type type) }
}
+/* Returns the type of the 'enum_' member for an ovsdb_base_type whose 'type'
+ * is 'atomic_type'. */
+const struct ovsdb_type *
+ovsdb_base_type_get_enum_type(enum ovsdb_atomic_type atomic_type)
+{
+ static struct ovsdb_type *types[OVSDB_N_TYPES];
+
+ if (!types[atomic_type]) {
+ struct ovsdb_type *type;
+
+ types[atomic_type] = type = xmalloc(sizeof *type);
+ ovsdb_base_type_init(&type->key, atomic_type);
+ ovsdb_base_type_init(&type->value, OVSDB_TYPE_VOID);
+ type->n_min = 1;
+ type->n_max = UINT_MAX;
+ }
+ return types[atomic_type];
+}
+
void
ovsdb_base_type_clone(struct ovsdb_base_type *dst,
const struct ovsdb_base_type *src)
{
*dst = *src;
+ if (src->enum_) {
+ dst->enum_ = xmalloc(sizeof *dst->enum_);
+ ovsdb_datum_clone(dst->enum_, src->enum_,
+ ovsdb_base_type_get_enum_type(dst->type));
+ }
+
switch (dst->type) {
case OVSDB_TYPE_VOID:
case OVSDB_TYPE_INTEGER:
@@ -183,6 +210,12 @@ void
ovsdb_base_type_destroy(struct ovsdb_base_type *base)
{
if (base) {
+ if (base->enum_) {
+ ovsdb_datum_destroy(base->enum_,
+ ovsdb_base_type_get_enum_type(base->type));
+ free(base->enum_);
+ }
+
switch (base->type) {
case OVSDB_TYPE_VOID:
case OVSDB_TYPE_INTEGER:
@@ -237,6 +270,10 @@ ovsdb_base_type_is_valid(const struct ovsdb_base_type *base)
bool
ovsdb_base_type_has_constraints(const struct ovsdb_base_type *base)
{
+ if (base->enum_) {
+ return true;
+ }
+
switch (base->type) {
case OVSDB_TYPE_VOID:
NOT_REACHED();
@@ -298,7 +335,7 @@ ovsdb_base_type_from_json(struct ovsdb_base_type *base,
{
struct ovsdb_parser parser;
struct ovsdb_error *error;
- const struct json *type;
+ const struct json *type, *enum_;
if (json->type == JSON_STRING) {
error = ovsdb_atomic_type_from_json(&base->type, json);
@@ -322,7 +359,18 @@ ovsdb_base_type_from_json(struct ovsdb_base_type *base,
}
ovsdb_base_type_init(base, base->type);
- if (base->type == OVSDB_TYPE_INTEGER) {
+
+ enum_ = ovsdb_parser_member(&parser, "enum", OP_ANY | OP_OPTIONAL);
+ if (enum_) {
+ base->enum_ = xmalloc(sizeof *base->enum_);
+ error = ovsdb_datum_from_json(
+ base->enum_, ovsdb_base_type_get_enum_type(base->type),
+ enum_, NULL);
+ if (error) {
+ free(base->enum_);
+ base->enum_ = NULL;
+ }
+ } else if (base->type == OVSDB_TYPE_INTEGER) {
const struct json *min, *max;
min = ovsdb_parser_member(&parser, "minInteger",
@@ -395,6 +443,14 @@ ovsdb_base_type_to_json(const struct ovsdb_base_type *base)
json = json_object_create();
json_object_put_string(json, "type",
ovsdb_atomic_type_to_string(base->type));
+
+ if (base->enum_) {
+ const struct ovsdb_type *type;
+
+ type = ovsdb_base_type_get_enum_type(base->type);
+ json_object_put(json, "enum", ovsdb_datum_to_json(base->enum_, type));
+ }
+
switch (base->type) {
case OVSDB_TYPE_VOID:
NOT_REACHED();
@@ -528,7 +584,7 @@ ovsdb_type_to_english(const struct ovsdb_type *type)
struct ovsdb_error *
ovsdb_type_from_json(struct ovsdb_type *type, const struct json *json)
{
- type->value.type = OVSDB_TYPE_VOID;
+ ovsdb_base_type_init(&type->value, OVSDB_TYPE_VOID);
type->n_min = 1;
type->n_max = 1;
diff --git a/lib/ovsdb-types.h b/lib/ovsdb-types.h
index 0ef596a..6f1727e 100644
--- a/lib/ovsdb-types.h
+++ b/lib/ovsdb-types.h
@@ -46,6 +46,11 @@ struct json *ovsdb_atomic_type_to_json(enum ovsdb_atomic_type);
struct ovsdb_base_type {
enum ovsdb_atomic_type type;
+
+ /* If nonnull, a datum with keys of type 'type' that expresses all the
+ * valid values for this base_type. */
+ struct ovsdb_datum *enum_;
+
union {
struct ovsdb_integer_constraints {
int64_t min; /* minInteger or INT64_MIN. */
@@ -90,6 +95,7 @@ void ovsdb_base_type_destroy(struct ovsdb_base_type *);
bool ovsdb_base_type_is_valid(const struct ovsdb_base_type *);
bool ovsdb_base_type_has_constraints(const struct ovsdb_base_type *);
void ovsdb_base_type_clear_constraints(struct ovsdb_base_type *);
+const struct ovsdb_type *ovsdb_base_type_get_enum_type(enum ovsdb_atomic_type);
struct ovsdb_error *ovsdb_base_type_from_json(struct ovsdb_base_type *,
const struct json *)
diff --git a/ovsdb/SPECS b/ovsdb/SPECS
index adc6dd2..e5cc21b 100644
--- a/ovsdb/SPECS
+++ b/ovsdb/SPECS
@@ -173,6 +173,7 @@ is represented by <database-schema>, as described below.
<atomic-type> or a JSON object with the following members:
"type": <atomic-type> required
+ "enum": <value> optional
"minInteger": <integer> optional, integers only
"maxInteger": <integer> optional, integers only
"minReal": <real> optional, reals only
@@ -184,6 +185,13 @@ is represented by <database-schema>, as described below.
An <atomic-type> by itself is equivalent to a JSON object with a
single member "type" whose value is the <atomic-type>.
+ "enum" may be specified as a <value> whose type is a set of one
+ or more values specified for the member "type". If "enum" is
+ specified, then the valid values of the <base-type> are limited to
+ those in the <value>.
+
+ "enum" is mutually exclusive with the following constraints.
+
If "type" is "integer", then "minInteger" or "maxInteger" or both
may also be specified, restricting the valid integer range. If
both are specified, then the maxInteger must be greater than or
diff --git a/ovsdb/mutation.c b/ovsdb/mutation.c
index 72d7d0c..9f09d59 100644
--- a/ovsdb/mutation.c
+++ b/ovsdb/mutation.c
@@ -310,7 +310,7 @@ mutate_scalar(const struct ovsdb_type *dst_type, struct \
ovsdb_datum *dst, }
}
- error = ovsdb_datum_sort(dst, dst_type);
+ error = ovsdb_datum_sort(dst, dst_type->key.type);
if (error) {
ovsdb_error_destroy(error);
return ovsdb_error("constraint violation",
diff --git a/ovsdb/ovsdb-idlc.in b/ovsdb/ovsdb-idlc.in
index c314d61..2426e2d 100755
--- a/ovsdb/ovsdb-idlc.in
+++ b/ovsdb/ovsdb-idlc.in
@@ -18,7 +18,7 @@ class Error(Exception):
def getMember(json, name, validTypes, description, default=None):
if name in json:
member = json[name]
- if type(member) not in validTypes:
+ if len(validTypes) and type(member) not in validTypes:
raise Error("%s: type mismatch for '%s' member"
% (description, name))
return member
@@ -108,13 +108,89 @@ def escapeCString(src):
dst += c
return dst
+class UUID:
+ x = "[0-9a-fA-f]"
+ uuidRE = re.compile("^(%s{8})-(%s{4})-(%s{4})-(%s{4})-(%s{4})(%s{8})$"
+ % (x, x, x, x, x, x))
+
+ def __init__(self, value):
+ self.value = value
+
+ @staticmethod
+ def fromString(s):
+ if not uuidRE.match(s):
+ raise Error("%s is not a valid UUID" % s)
+ return UUID(s)
+
+ @staticmethod
+ def fromJson(json):
+ if UUID.isValidJson(json):
+ return UUID(json[1])
+ else:
+ raise Error("%s is not valid JSON for a UUID" % json)
+
+ @staticmethod
+ def isValidJson(json):
+ return len(json) == 2 and json[0] == "uuid" and uuidRE.match(json[1])
+
+ def toJson(self):
+ return ["uuid", self.value]
+
+ def cInitUUID(self, var):
+ m = re.match(self.value)
+ return ["%s.parts[0] = 0x%s;" % (var, m.group(1)),
+ "%s.parts[1] = 0x%s%s;" % (var, m.group(2), m.group(3)),
+ "%s.parts[2] = 0x%s%s;" % (var, m.group(4), m.group(5)),
+ "%s.parts[3] = 0x%s;" % (var, m.group(6))]
+
+class Atom:
+ def __init__(self, type, value):
+ self.type = type
+ self.value = value
+
+ @staticmethod
+ def fromJson(type_, json):
+ if ((type_ == 'integer' and type(json) in [int, long])
+ or (type_ == 'real' and type(json) in [int, long, float])
+ or (type_ == 'boolean' and json in [True, False])
+ or (type_ == 'string' and type(json) in [str, unicode])):
+ return Atom(type_, json)
+ elif type_ == 'uuid':
+ return UUID.fromJson(json)
+ else:
+ raise Error("%s is not valid JSON for type %s" % (json, type_))
+
+ def toJson(self):
+ if self.type == 'uuid':
+ return self.value.toString()
+ else:
+ return self.value
+
+ def cInitAtom(self, var):
+ if self.type == 'integer':
+ return ['%s.integer = %d;' % (var, self.value)]
+ elif self.type == 'real':
+ return ['%s.real = %.15g;' % (var, self.value)]
+ elif self.type == 'boolean':
+ if self.value:
+ return ['%s.boolean = true;']
+ else:
+ return ['%s.boolean = false;']
+ elif self.type == 'string':
+ return ['%s.string = xstrdup("%s");'
+ % (var, escapeCString(self.value))]
+ elif self.type == 'uuid':
+ return self.value.cInitUUID(var)
+
class BaseType:
def __init__(self, type,
+ enum=None,
refTable=None,
minInteger=None, maxInteger=None,
minReal=None, maxReal=None,
minLength=None, maxLength=None):
self.type = type
+ self.enum = enum
self.refTable = refTable
self.minInteger = minInteger
self.maxInteger = maxInteger
@@ -129,6 +205,10 @@ class BaseType:
return BaseType(json)
else:
atomicType = mustGetMember(json, 'type', [unicode], description)
+ enum = getMember(json, 'enum', [], description)
+ if enum:
+ enumType = Type(atomicType, None, 0, 'unlimited')
+ enum = Datum.fromJson(enumType, enum)
refTable = getMember(json, 'refTable', [unicode], description)
minInteger = getMember(json, 'minInteger', [int, long], description)
maxInteger = getMember(json, 'maxInteger', [int, long], description)
@@ -136,7 +216,7 @@ class BaseType:
maxReal = getMember(json, 'maxReal', [int, long, float], description)
minLength = getMember(json, 'minLength', [int], description)
maxLength = getMember(json, 'minLength', [int], description)
- return BaseType(atomicType, refTable, minInteger, maxInteger, minReal, \
maxReal, minLength, maxLength) + return BaseType(atomicType, enum, \
refTable, minInteger, maxInteger, minReal, maxReal, minLength, maxLength)
def toEnglish(self):
if self.type == 'uuid' and self.refTable:
@@ -179,6 +259,10 @@ class BaseType:
stmts = []
stmts.append('ovsdb_base_type_init(&%s, OVSDB_TYPE_%s);' % (
var, self.type.upper()),)
+ if self.enum:
+ stmts.append("%s.enum_ = xmalloc(sizeof *%s.enum_);"
+ % (var, var))
+ stmts += self.enum.cInitDatum("%s.enum_" % var)
if self.type == 'integer':
if self.minInteger != None:
stmts.append('%s.u.integer.min = %d;' % (var, self.minInteger))
@@ -284,6 +368,58 @@ class Type:
initMax = "%s%s.n_max = %s;" % (indent, var, max)
return "\n".join((initKey, initValue, initMin, initMax))
+class Datum:
+ def __init__(self, type, values):
+ self.type = type
+ self.values = values
+
+ @staticmethod
+ def fromJson(type_, json):
+ if not type_.value:
+ if len(json) == 2 and json[0] == "set":
+ values = []
+ for atomJson in json[1]:
+ values += [Atom.fromJson(type_.key, atomJson)]
+ else:
+ values = [Atom.fromJson(type_.key, json)]
+ else:
+ if len(json) != 2 or json[0] != "map":
+ raise Error("%s is not valid JSON for a map" % json)
+ values = []
+ for pairJson in json[1]:
+ values += [(Atom.fromJson(type_.key, pairJson[0]),
+ Atom.fromJson(type_.value, pairJson[1]))]
+ return Datum(type_, values)
+
+ def cInitDatum(self, var):
+ if len(self.values) == 0:
+ return ["ovsdb_datum_init_empty(%s);" % var]
+
+ s = ["%s->n = %d;" % (var, len(self.values))]
+ s += ["%s->keys = xmalloc(%d * sizeof *%s->keys);"
+ % (var, len(self.values), var)]
+
+ for i in range(len(self.values)):
+ key = self.values[i]
+ if self.type.value:
+ key = key[0]
+ s += key.cInitAtom("%s->keys[%d]" % (var, i))
+
+ if self.type.value:
+ s += ["%s->values = xmalloc(%d * sizeof *%s->values);"
+ % (var, len(self.values), var)]
+ for i in range(len(self.values)):
+ value = self.values[i][1]
+ s += key.cInitAtom("%s->values[%d]" % (var, i))
+ else:
+ s += ["%s->values = NULL;" % var]
+
+ if len(self.values) > 1:
+ s += ["ovsdb_datum_sort_assert(%s, OVSDB_TYPE_%s);"
+ % (var, self.type.key.upper())]
+
+ return s
+
def parseSchema(filename):
return DbSchema.fromJson(json.load(open(filename, "r")))
diff --git a/tests/ovs-vsctl.at b/tests/ovs-vsctl.at
index 07244a8..045b1c3 100644
--- a/tests/ovs-vsctl.at
+++ b/tests/ovs-vsctl.at
@@ -590,6 +590,9 @@ AT_CHECK([RUN_OVS_VSCTL([set b br0 flood_vlans=-1])],
AT_CHECK([RUN_OVS_VSCTL([set b br0 flood_vlans=4096])],
[1], [], [ovs-vsctl: constraint violation: 4096 is not in the valid range 0 to \
4095 (inclusive) ], [OVS_VSCTL_CLEANUP])
+AT_CHECK([RUN_OVS_VSCTL([set c br1 'connection-mode=xyz'])],
+ [1], [], [[ovs-vsctl: constraint violation: xyz is not one of the allowed values \
([in-band, out-of-band]) +]], [OVS_VSCTL_CLEANUP])
AT_CHECK([RUN_OVS_VSCTL([set c br1 connection-mode:x=y])],
[1], [], [ovs-vsctl: cannot specify key to set for non-map column connection_mode
], [OVS_VSCTL_CLEANUP])
diff --git a/tests/ovsdb-data.at b/tests/ovsdb-data.at
index 031eee0..4bfd909 100644
--- a/tests/ovsdb-data.at
+++ b/tests/ovsdb-data.at
@@ -198,7 +198,80 @@ OVSDB_CHECK_NEGATIVE([uuids must be valid],
[parse-atom-strings '[["uuid"]]' '1234-5678'],
["1234-5678" is not a valid UUID])
-AT_BANNER([OVSDB -- atoms with constraints])
+AT_BANNER([OVSDB -- atoms with enum constraints])
+
+OVSDB_CHECK_POSITIVE([integer atom enum],
+ [[parse-atoms '[{"type": "integer", "enum": ["set", [1, 6, 8, 10]]}]' \
+ '[0]' \
+ '[1]' \
+ '[2]' \
+ '[3]' \
+ '[6]' \
+ '[7]' \
+ '[8]' \
+ '[9]' \
+ '[10]' \
+ '[11]']],
+ [[constraint violation: 0 is not one of the allowed values ([1, 6, 8, 10])
+1
+constraint violation: 2 is not one of the allowed values ([1, 6, 8, 10])
+constraint violation: 3 is not one of the allowed values ([1, 6, 8, 10])
+6
+constraint violation: 7 is not one of the allowed values ([1, 6, 8, 10])
+8
+constraint violation: 9 is not one of the allowed values ([1, 6, 8, 10])
+10
+constraint violation: 11 is not one of the allowed values ([1, 6, 8, 10])]])
+
+OVSDB_CHECK_POSITIVE([real atom enum],
+ [[parse-atoms '[{"type": "real", "enum": ["set", [-1.5, 1.5]]}]' \
+ '[-2]' \
+ '[-1]' \
+ '[-1.5]' \
+ '[0]' \
+ '[1]' \
+ '[1.5]' \
+ '[2]']],
+ [[constraint violation: -2 is not one of the allowed values ([-1.5, 1.5])
+constraint violation: -1 is not one of the allowed values ([-1.5, 1.5])
+-1.5
+constraint violation: 0 is not one of the allowed values ([-1.5, 1.5])
+constraint violation: 1 is not one of the allowed values ([-1.5, 1.5])
+1.5
+constraint violation: 2 is not one of the allowed values ([-1.5, 1.5])]])
+
+OVSDB_CHECK_POSITIVE([boolean atom enum],
+ [[parse-atoms '[{"type": "boolean", "enum": false}]' \
+ '[false]' \
+ '[true]']],
+ [[false
+constraint violation: true is not one of the allowed values ([false])]])
+
+OVSDB_CHECK_POSITIVE([string atom enum],
+ [[parse-atoms '[{"type": "string", "enum": ["set", ["abc", "def"]]}]' \
+ '[""]' \
+ '["ab"]' \
+ '["abc"]' \
+ '["def"]' \
+ '["defg"]' \
+ '["DEF"]']],
+ [[constraint violation: "" is not one of the allowed values ([abc, def])
+constraint violation: ab is not one of the allowed values ([abc, def])
+"abc"
+"def"
+constraint violation: defg is not one of the allowed values ([abc, def])
+constraint violation: DEF is not one of the allowed values ([abc, def])]])
+
+OVSDB_CHECK_POSITIVE([uuid atom enum],
+ [[parse-atoms '[{"type": "uuid", "enum": ["set", [["uuid", \
"6d53a6dd-2da7-4924-9927-97f613812382"], ["uuid", \
"52cbc842-137a-4db5-804f-9f34106a0ba3"]]]}]' \ + '["uuid", \
"6d53a6dd-2da7-4924-9927-97f613812382"]' \ + '["uuid", \
"52cbc842-137a-4db5-804f-9f34106a0ba3"]' \ + '["uuid", \
"dab2a6b2-6094-4f43-a7ef-4c0f0608f176"]']], + \
[[["uuid","6d53a6dd-2da7-4924-9927-97f613812382"] \
+["uuid","52cbc842-137a-4db5-804f-9f34106a0ba3"] +constraint violation: \
dab2a6b2-6094-4f43-a7ef-4c0f0608f176 is not one of the allowed values \
([52cbc842-137a-4db5-804f-9f34106a0ba3, 6d53a6dd-2da7-4924-9927-97f613812382])]]) +
+AT_BANNER([OVSDB -- atoms with other constraints])
OVSDB_CHECK_POSITIVE([integers >= 5],
[[parse-atoms '[{"type": "integer", "minInteger": 5}]' \
diff --git a/tests/ovsdb-types.at b/tests/ovsdb-types.at
index 2d98183..7122e9d 100644
--- a/tests/ovsdb-types.at
+++ b/tests/ovsdb-types.at
@@ -15,6 +15,9 @@ OVSDB_CHECK_NEGATIVE([void is not a valid atomic-type],
AT_BANNER([OVSDB -- base types])
+OVSDB_CHECK_POSITIVE([integer enum],
+ [[parse-base-type '{"type": "integer", "enum": ["set", [-1, 4, 5]]}' ]],
+ [[{"enum":["set",[-1,4,5]],"type":"integer"}]])
OVSDB_CHECK_POSITIVE([integer >= 5],
[[parse-base-type '{"type": "integer", "minInteger": 5}' ]],
[{"minInteger":5,"type":"integer"}])
@@ -28,6 +31,9 @@ OVSDB_CHECK_NEGATIVE([integer max may not be less than min],
[[parse-base-type '{"type": "integer", "minInteger": 5, "maxInteger": 3}']],
[minInteger exceeds maxInteger])
+OVSDB_CHECK_POSITIVE([real enum],
+ [[parse-base-type '{"type": "real", "enum": ["set", [1.5, 0, 2.75]]}' ]],
+ [[{"enum":["set",[0,1.5,2.75]],"type":"real"}]])
OVSDB_CHECK_POSITIVE([real >= -1.5],
[[parse-base-type '{"type": "real", "minReal": -1.5}']],
[{"minReal":-1.5,"type":"real"}])
@@ -43,7 +49,13 @@ OVSDB_CHECK_NEGATIVE([real max may not be less than min],
OVSDB_CHECK_POSITIVE([boolean],
[[parse-base-type '[{"type": "boolean"}]' ]], ["boolean"])
+OVSDB_CHECK_POSITIVE([boolean enum],
+ [[parse-base-type '{"type": "boolean", "enum": true}' ]],
+ [[{"enum":true,"type":"boolean"}]])
+OVSDB_CHECK_POSITIVE([string enum],
+ [[parse-base-type '{"type": "string", "enum": ["set", ["def", "abc"]]}']],
+ [[{"enum":["set",["abc","def"]],"type":"string"}]])
OVSDB_CHECK_POSITIVE([string minLength],
[[parse-base-type '{"type": "string", "minLength": 1}']],
[{"minLength":1,"type":"string"}])
@@ -60,6 +72,9 @@ OVSDB_CHECK_NEGATIVE([maxLength must not be negative],
[[parse-base-type '{"type": "string", "maxLength": -1}']],
[maxLength out of valid range 0 to 4294967295])
+OVSDB_CHECK_POSITIVE([uuid enum],
+ [[parse-base-type '{"type": "uuid", "enum": ["uuid", \
"36bf19c0-ad9d-4232-bb85-b3d73dfe2123"]}' ]], + \
[[{"enum":["uuid","36bf19c0-ad9d-4232-bb85-b3d73dfe2123"],"type":"uuid"}]]) \
OVSDB_CHECK_POSITIVE([uuid refTable], [[parse-base-type '{"type": "uuid", \
"refTable": "myTable"}' ]], [{"refTable":"myTable","type":"uuid"}])
diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema
index b75c100..ac42edf 100644
--- a/vswitchd/vswitch.ovsschema
+++ b/vswitchd/vswitch.ovsschema
@@ -245,7 +245,8 @@
"type": {"key": "integer", "min": 0, "max": 1}},
"fail_mode": {
"comment": "Either \"standalone\" or \"secure\", or empty to use the \
implementation's default.",
- "type": {"key": {"type": "string"},
+ "type": {"key": {"type": "string",
+ "enum": ["set", ["standalone", "secure"]]},
"min": 0, "max": 1}},
"discover_accept_regex": {
"comment": "If \"target\" is \"discover\", a POSIX extended regular \
expression against which the discovered controller location is validated. If not \
specified, the default is implementation-specific.", @@ -255,7 +256,8 @@
"type": {"key": "boolean", "min": 0, "max": 1}},
"connection_mode": {
"comment": "Either \"in-band\" or \"out-of-band\". If not specified, the \
default is implementation-specific.",
- "type": {"key": {"type": "string"},
+ "type": {"key": {"type": "string",
+ "enum": ["set", ["in-band", "out-of-band"]]},
"min": 0, "max": 1}},
"local_ip": {
"comment": "If \"target\" is not \"discover\", the IP address to configure \
on the local port.",
--
1.6.6.1
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic