#include "command-line.h"
#include "json.h"
+#include "jsonrpc.h"
#include "ovsdb-data.h"
#include "ovsdb-error.h"
+#include "ovsdb-idl.h"
#include "ovsdb-types.h"
#include "ovsdb/column.h"
#include "ovsdb/condition.h"
#include "ovsdb/file.h"
+#include "ovsdb/log.h"
#include "ovsdb/ovsdb.h"
#include "ovsdb/query.h"
#include "ovsdb/row.h"
#include "ovsdb/transaction.h"
#include "ovsdb/trigger.h"
#include "poll-loop.h"
+#include "stream.h"
#include "svec.h"
+#include "tests/idltest.h"
#include "timeval.h"
#include "util.h"
#include "vlog.h"
parse_options(int argc, char *argv[])
{
static struct option long_options[] = {
+ {"timeout", required_argument, 0, 't'},
{"verbose", optional_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0},
char *short_options = long_options_to_short_options(long_options);
for (;;) {
- int c = getopt_long(argc, argv, short_options, long_options, NULL);
+ unsigned long int timeout;
+ int c;
+
+ c = getopt_long(argc, argv, short_options, long_options, NULL);
if (c == -1) {
break;
}
switch (c) {
+ case 't':
+ timeout = strtoul(optarg, NULL, 10);
+ if (timeout <= 0) {
+ ovs_fatal(0, "value %s on -t or --timeout is not at least 1",
+ optarg);
+ } else {
+ time_alarm(timeout);
+ }
+ break;
+
case 'h':
usage();
{
printf("%s: Open vSwitch database test utility\n"
"usage: %s [OPTIONS] COMMAND [ARG...]\n\n"
- " file-io FILE FLAGS COMMAND...\n"
+ " log-io FILE FLAGS COMMAND...\n"
" open FILE with FLAGS, run COMMANDs\n"
" parse-atomic-type TYPE\n"
" parse TYPE as OVSDB atomic type, and re-serialize\n"
" executes each TRANSACTION on an initially empty database\n"
" the specified SCHEMA. A TRANSACTION of the form\n"
" [\"advance\", NUMBER] advances NUMBER milliseconds in\n"
- " simulated time, for causing triggers to time out.\n",
+ " simulated time, for causing triggers to time out.\n"
+ " idl SERVER [TRANSACTION...]\n"
+ " connect to SERVER and dump the contents of the database\n"
+ " as seen initially by the IDL implementation and after\n"
+ " executing each TRANSACTION. (Each TRANSACTION must modify\n"
+ " the database or this command will hang.)\n",
program_name, program_name);
vlog_usage();
printf("\nOther options:\n"
+ " -t, --timeout=SECS give up after SECS seconds\n"
" -h, --help display this help message\n");
exit(EXIT_SUCCESS);
}
/* Command implementations. */
static void
-do_file_io(int argc, char *argv[])
+do_log_io(int argc, char *argv[])
{
const char *name = argv[1];
char *mode = argv[2];
struct ovsdb_error *error;
- struct ovsdb_file *file;
+ struct ovsdb_log *log;
char *save_ptr = NULL;
const char *token;
int flags;
}
}
- check_ovsdb_error(ovsdb_file_open(name, flags, &file));
+ check_ovsdb_error(ovsdb_log_open(name, flags, &log));
printf("%s: open successful\n", name);
for (i = 3; i < argc; i++) {
if (!strcmp(command, "read")) {
struct json *json;
- error = ovsdb_file_read(file, &json);
+ error = ovsdb_log_read(log, &json);
if (!error) {
printf("%s: read: ", name);
if (json) {
print_and_free_json(json);
} else {
- printf("end of file\n");
+ printf("end of log\n");
}
continue;
}
} else if (!strncmp(command, "write:", 6)) {
struct json *json = parse_json(command + 6);
- error = ovsdb_file_write(file, json);
+ error = ovsdb_log_write(log, json);
json_destroy(json);
} else if (!strcmp(command, "commit")) {
- error = ovsdb_file_commit(file);
+ error = ovsdb_log_commit(log);
} else {
- ovs_fatal(0, "unknown file-io command \"%s\"", command);
+ ovs_fatal(0, "unknown log-io command \"%s\"", command);
}
if (error) {
char *s = ovsdb_error_to_string(error);
}
}
- ovsdb_file_close(file);
+ ovsdb_log_close(log);
}
static void
json = parse_json(argv[1]);
check_ovsdb_error(ovsdb_schema_from_json(json, &schema));
json_destroy(json);
- db = ovsdb_create(NULL, schema);
+ db = ovsdb_create(schema);
for (i = 2; i < argc; i++) {
struct json *params, *result;
json = parse_json(argv[1]);
check_ovsdb_error(ovsdb_schema_from_json(json, &schema));
json_destroy(json);
- db = ovsdb_create(NULL, schema);
+ db = ovsdb_create(schema);
list_init(&completions);
now = 0;
static void
do_transact_commit(int argc UNUSED, char *argv[] UNUSED)
{
- ovsdb_txn_commit(do_transact_txn);
+ ovsdb_txn_commit(do_transact_txn, false);
do_transact_txn = NULL;
}
" \"j\": {\"type\": \"integer\"}}}}}");
check_ovsdb_error(ovsdb_schema_from_json(json, &schema));
json_destroy(json);
- do_transact_db = ovsdb_create(NULL, schema);
+ do_transact_db = ovsdb_create(schema);
do_transact_table = ovsdb_get_table(do_transact_db, "mytable");
assert(do_transact_table != NULL);
ovsdb_destroy(do_transact_db); /* Also destroys 'schema'. */
}
+static int
+compare_link1(const void *a_, const void *b_)
+{
+ const struct idltest_link1 *const *ap = a_;
+ const struct idltest_link1 *const *bp = b_;
+ const struct idltest_link1 *a = *ap;
+ const struct idltest_link1 *b = *bp;
+
+ return a->i < b->i ? -1 : a->i > b->i;
+}
+
+static void
+print_idl(struct ovsdb_idl *idl, int step)
+{
+ const struct idltest_simple *s;
+ const struct idltest_link1 *l1;
+ const struct idltest_link2 *l2;
+ int n = 0;
+
+ IDLTEST_SIMPLE_FOR_EACH (s, idl) {
+ size_t i;
+
+ printf("%03d: i=%"PRId64" r=%g b=%s s=%s u="UUID_FMT" ia=[",
+ step, s->i, s->r, s->b ? "true" : "false",
+ s->s, UUID_ARGS(&s->u));
+ for (i = 0; i < s->n_ia; i++) {
+ printf("%s%"PRId64, i ? " " : "", s->ia[i]);
+ }
+ printf("] ra=[");
+ for (i = 0; i < s->n_ra; i++) {
+ printf("%s%g", i ? " " : "", s->ra[i]);
+ }
+ printf("] ba=[");
+ for (i = 0; i < s->n_ba; i++) {
+ printf("%s%s", i ? " " : "", s->ba[i] ? "true" : "false");
+ }
+ printf("] sa=[");
+ for (i = 0; i < s->n_sa; i++) {
+ printf("%s%s", i ? " " : "", s->sa[i]);
+ }
+ printf("] ua=[");
+ for (i = 0; i < s->n_ua; i++) {
+ printf("%s"UUID_FMT, i ? " " : "", UUID_ARGS(&s->ua[i]));
+ }
+ printf("] uuid="UUID_FMT"\n", UUID_ARGS(&s->header_.uuid));
+ n++;
+ }
+ IDLTEST_LINK1_FOR_EACH (l1, idl) {
+ struct idltest_link1 **links;
+ size_t i;
+
+ printf("%03d: i=%"PRId64" k=", step, l1->i);
+ if (l1->k) {
+ printf("%"PRId64, l1->k->i);
+ }
+ printf(" ka=[");
+ links = xmemdup(l1->ka, l1->n_ka * sizeof *l1->ka);
+ qsort(links, l1->n_ka, sizeof *links, compare_link1);
+ for (i = 0; i < l1->n_ka; i++) {
+ printf("%s%"PRId64, i ? " " : "", links[i]->i);
+ }
+ free(links);
+ printf("] l2=");
+ if (l1->l2) {
+ printf("%"PRId64, l1->l2->i);
+ }
+ printf(" uuid="UUID_FMT"\n", UUID_ARGS(&l1->header_.uuid));
+ n++;
+ }
+ IDLTEST_LINK2_FOR_EACH (l2, idl) {
+ printf("%03d: i=%"PRId64" l1=", step, l2->i);
+ if (l2->l1) {
+ printf("%"PRId64, l2->l1->i);
+ }
+ printf(" uuid="UUID_FMT"\n", UUID_ARGS(&l2->header_.uuid));
+ n++;
+ }
+ if (!n) {
+ printf("%03d: empty\n", step);
+ }
+}
+
+static unsigned int
+print_updated_idl(struct ovsdb_idl *idl, struct jsonrpc *rpc,
+ int step, unsigned int seqno)
+{
+ for (;;) {
+ unsigned int new_seqno;
+
+ if (rpc) {
+ jsonrpc_run(rpc);
+ }
+ ovsdb_idl_run(idl);
+ new_seqno = ovsdb_idl_get_seqno(idl);
+ if (new_seqno != seqno) {
+ print_idl(idl, step);
+ return new_seqno;
+ }
+
+ if (rpc) {
+ jsonrpc_wait(rpc);
+ }
+ ovsdb_idl_wait(idl);
+ poll_block();
+ }
+}
+
+static void
+parse_uuids(const struct json *json, struct ovsdb_symbol_table *symtab,
+ size_t *n)
+{
+ struct uuid uuid;
+
+ if (json->type == JSON_STRING && uuid_from_string(&uuid, json->u.string)) {
+ char *name = xasprintf("#%d#", *n);
+ fprintf(stderr, "%s = "UUID_FMT"\n", name, UUID_ARGS(&uuid));
+ ovsdb_symbol_table_put(symtab, name, &uuid, false);
+ free(name);
+ *n += 1;
+ } else if (json->type == JSON_ARRAY) {
+ size_t i;
+
+ for (i = 0; i < json->u.array.n; i++) {
+ parse_uuids(json->u.array.elems[i], symtab, n);
+ }
+ } else if (json->type == JSON_OBJECT) {
+ const struct shash_node *node;
+
+ SHASH_FOR_EACH (node, json_object(json)) {
+ parse_uuids(node->data, symtab, n);
+ }
+ }
+}
+
+static void
+substitute_uuids(struct json *json, const struct ovsdb_symbol_table *symtab)
+{
+ if (json->type == JSON_STRING) {
+ const struct ovsdb_symbol *symbol;
+
+ symbol = ovsdb_symbol_table_get(symtab, json->u.string);
+ if (symbol) {
+ free(json->u.string);
+ json->u.string = xasprintf(UUID_FMT, UUID_ARGS(&symbol->uuid));
+ }
+ } else if (json->type == JSON_ARRAY) {
+ size_t i;
+
+ for (i = 0; i < json->u.array.n; i++) {
+ substitute_uuids(json->u.array.elems[i], symtab);
+ }
+ } else if (json->type == JSON_OBJECT) {
+ const struct shash_node *node;
+
+ SHASH_FOR_EACH (node, json_object(json)) {
+ substitute_uuids(node->data, symtab);
+ }
+ }
+}
+
+static const struct idltest_simple *
+idltest_find_simple(struct ovsdb_idl *idl, int i)
+{
+ const struct idltest_simple *s;
+
+ IDLTEST_SIMPLE_FOR_EACH (s, idl) {
+ if (s->i == i) {
+ return s;
+ }
+ }
+ return NULL;
+}
+
+static void
+idl_set(struct ovsdb_idl *idl, char *commands, int step)
+{
+ char *cmd, *save_ptr1 = NULL;
+ struct ovsdb_idl_txn *txn;
+ enum ovsdb_idl_txn_status status;
+
+ txn = ovsdb_idl_txn_create(idl);
+ for (cmd = strtok_r(commands, ",", &save_ptr1); cmd;
+ cmd = strtok_r(NULL, ",", &save_ptr1)) {
+ char *save_ptr2 = NULL;
+ char *name, *arg1, *arg2, *arg3;
+
+ name = strtok_r(cmd, " ", &save_ptr2);
+ arg1 = strtok_r(NULL, " ", &save_ptr2);
+ arg2 = strtok_r(NULL, " ", &save_ptr2);
+ arg3 = strtok_r(NULL, " ", &save_ptr2);
+
+ if (!strcmp(name, "set")) {
+ const struct idltest_simple *s;
+
+ if (!arg3) {
+ ovs_fatal(0, "\"set\" command requires 3 arguments");
+ }
+
+ s = idltest_find_simple(idl, atoi(arg1));
+ if (!s) {
+ ovs_fatal(0, "\"set\" command asks for nonexistent "
+ "i=%d", atoi(arg1));
+ }
+
+ if (!strcmp(arg2, "b")) {
+ idltest_simple_set_b(s, atoi(arg3));
+ } else if (!strcmp(arg2, "s")) {
+ idltest_simple_set_s(s, arg3);
+ } else if (!strcmp(arg2, "u")) {
+ struct uuid uuid;
+ uuid_from_string(&uuid, arg3);
+ idltest_simple_set_u(s, uuid);
+ } else if (!strcmp(arg2, "r")) {
+ idltest_simple_set_r(s, atof(arg3));
+ } else {
+ ovs_fatal(0, "\"set\" command asks for unknown column %s",
+ arg2);
+ }
+ } else if (!strcmp(name, "insert")) {
+ struct idltest_simple *s;
+
+ if (!arg1 || arg2) {
+ ovs_fatal(0, "\"set\" command requires 1 argument");
+ }
+
+ s = idltest_simple_insert(txn);
+ idltest_simple_set_i(s, atoi(arg1));
+ } else if (!strcmp(name, "delete")) {
+ const struct idltest_simple *s;
+
+ if (!arg1 || arg2) {
+ ovs_fatal(0, "\"set\" command requires 1 argument");
+ }
+
+ s = idltest_find_simple(idl, atoi(arg1));
+ if (!s) {
+ ovs_fatal(0, "\"set\" command asks for nonexistent "
+ "i=%d", atoi(arg1));
+ }
+ idltest_simple_delete(s);
+ } else {
+ ovs_fatal(0, "unknown command %s", name);
+ }
+ }
+
+ while ((status = ovsdb_idl_txn_commit(txn)) == TXN_INCOMPLETE) {
+ ovsdb_idl_run(idl);
+ ovsdb_idl_wait(idl);
+ ovsdb_idl_txn_wait(txn);
+ poll_block();
+ }
+ printf("%03d: commit, status=%s\n",
+ step, ovsdb_idl_txn_status_to_string(status));
+ ovsdb_idl_txn_destroy(txn);
+}
+
+static void
+do_idl(int argc, char *argv[])
+{
+ struct jsonrpc *rpc;
+ struct ovsdb_idl *idl;
+ unsigned int seqno = 0;
+ struct ovsdb_symbol_table *symtab;
+ size_t n_uuids = 0;
+ int step = 0;
+ int error;
+ int i;
+
+ idl = ovsdb_idl_create(argv[1], &idltest_idl_class);
+ if (argc > 2) {
+ struct stream *stream;
+
+ error = stream_open_block(argv[1], &stream);
+ if (error) {
+ ovs_fatal(error, "failed to connect to \"%s\"", argv[1]);
+ }
+ rpc = jsonrpc_open(stream);
+ } else {
+ rpc = NULL;
+ }
+
+ symtab = ovsdb_symbol_table_create();
+ for (i = 2; i < argc; i++) {
+ struct jsonrpc_msg *request, *reply;
+ int error;
+
+ seqno = print_updated_idl(idl, rpc, step++, seqno);
+
+ if (!strcmp(argv[i], "reconnect")) {
+ printf("%03d: reconnect\n", step++);
+ ovsdb_idl_force_reconnect(idl);
+ } else if (argv[i][0] != '[') {
+ idl_set(idl, argv[i], step++);
+ } else {
+ struct json *json = parse_json(argv[i]);
+ substitute_uuids(json, symtab);
+ request = jsonrpc_create_request("transact", json, NULL);
+ error = jsonrpc_transact_block(rpc, request, &reply);
+ if (error) {
+ ovs_fatal(error, "jsonrpc transaction failed");
+ }
+ printf("%03d: ", step++);
+ if (reply->result) {
+ parse_uuids(reply->result, symtab, &n_uuids);
+ }
+ json_destroy(reply->id);
+ reply->id = NULL;
+ print_and_free_json(jsonrpc_msg_to_json(reply));
+ }
+ }
+ ovsdb_symbol_table_destroy(symtab);
+
+ if (rpc) {
+ jsonrpc_close(rpc);
+ }
+ print_updated_idl(idl, NULL, step++, seqno);
+ ovsdb_idl_destroy(idl);
+ printf("%03d: done\n", step);
+}
+
static struct command all_commands[] = {
- { "file-io", 2, INT_MAX, do_file_io },
+ { "log-io", 2, INT_MAX, do_log_io },
{ "parse-atomic-type", 1, 1, do_parse_atomic_type },
{ "parse-type", 1, 1, do_parse_type },
{ "parse-atoms", 2, INT_MAX, do_parse_atoms },
{ "transact", 1, INT_MAX, do_transact },
{ "execute", 2, INT_MAX, do_execute },
{ "trigger", 2, INT_MAX, do_trigger },
+ { "idl", 1, INT_MAX, do_idl },
{ "help", 0, INT_MAX, do_help },
{ NULL, 0, 0, NULL },
};