static void fetch_dbs(struct jsonrpc *rpc, struct svec *dbs) { struct jsonrpc_msg *request, *reply; size_t i; request = jsonrpc_create_request("list_dbs", json_array_create_empty(), NULL); check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply); if (reply->result->type != JSON_ARRAY) { ovs_fatal(0, "list_dbs response is not array"); } for (i = 0; i < reply->result->u.array.n; i++) { const struct json *name = reply->result->u.array.elems[i]; if (name->type != JSON_STRING) { ovs_fatal(0, "list_dbs response %"PRIuSIZE" is not string", i); } svec_add(dbs, name->u.string); } jsonrpc_msg_destroy(reply); svec_sort(dbs); }
static void table_print_json__(const struct table *table, const struct table_style *style) { struct json *json, *headings, *data; size_t x, y; char *s; json = json_object_create(); if (table->caption) { json_object_put_string(json, "caption", table->caption); } if (table->timestamp) { char *s = table_format_timestamp__(); json_object_put_string(json, "time", s); free(s); } headings = json_array_create_empty(); for (x = 0; x < table->n_columns; x++) { const struct column *column = &table->columns[x]; json_array_add(headings, json_string_create(column->heading)); } json_object_put(json, "headings", headings); data = json_array_create_empty(); for (y = 0; y < table->n_rows; y++) { struct json *row = json_array_create_empty(); for (x = 0; x < table->n_columns; x++) { const struct cell *cell = table_cell__(table, y, x); if (cell->text) { json_array_add(row, json_string_create(cell->text)); } else if (cell->json) { json_array_add(row, json_clone(cell->json)); } else { json_array_add(row, json_null_create()); } } json_array_add(data, row); } json_object_put(json, "data", data); s = json_to_string(json, style->json_flags); json_destroy(json); puts(s); free(s); }
struct json * ovsdb_execute(struct ovsdb *db, const struct ovsdb_session *session, const struct json *params, long long int elapsed_msec, long long int *timeout_msec) { struct ovsdb_execution x; struct ovsdb_error *error; struct json *results; size_t n_operations; size_t i; if (params->type != JSON_ARRAY || !params->u.array.n || params->u.array.elems[0]->type != JSON_STRING || strcmp(params->u.array.elems[0]->u.string, db->schema->name)) { if (params->type != JSON_ARRAY) { error = ovsdb_syntax_error(params, NULL, "array expected"); } else { error = ovsdb_syntax_error(params, NULL, "database name expected " "as first parameter"); } results = ovsdb_error_to_json(error); ovsdb_error_destroy(error); return results; } x.db = db; x.session = session; x.txn = ovsdb_txn_create(db); x.symtab = ovsdb_symbol_table_create(); x.durable = false; x.elapsed_msec = elapsed_msec; x.timeout_msec = LLONG_MAX; results = NULL; results = json_array_create_empty(); n_operations = params->u.array.n - 1; error = NULL; for (i = 1; i <= n_operations; i++) { struct json *operation = params->u.array.elems[i]; struct ovsdb_error *parse_error; struct ovsdb_parser parser; struct json *result; const struct json *op; /* Parse and execute operation. */ ovsdb_parser_init(&parser, operation, "ovsdb operation %"PRIuSIZE" of %"PRIuSIZE, i, n_operations); op = ovsdb_parser_member(&parser, "op", OP_ID); result = json_object_create(); if (op) { const char *op_name = json_string(op); ovsdb_operation_executor *executor = lookup_executor(op_name); if (executor) { error = executor(&x, &parser, result); } else { ovsdb_parser_raise_error(&parser, "No operation \"%s\"", op_name); } } else { ovs_assert(ovsdb_parser_has_error(&parser)); } /* A parse error overrides any other error. * An error overrides any other result. */ parse_error = ovsdb_parser_finish(&parser); if (parse_error) { ovsdb_error_destroy(error); error = parse_error; } if (error) { json_destroy(result); result = ovsdb_error_to_json(error); } if (error && !strcmp(ovsdb_error_get_tag(error), "not supported") && timeout_msec) { ovsdb_txn_abort(x.txn); *timeout_msec = x.timeout_msec; json_destroy(result); json_destroy(results); results = NULL; goto exit; } /* Add result to array. */ json_array_add(results, result); if (error) { break; } } if (!error) { error = ovsdb_txn_commit(x.txn, x.durable); if (error) { json_array_add(results, ovsdb_error_to_json(error)); } } else { ovsdb_txn_abort(x.txn); } while (json_array(results)->n < n_operations) { json_array_add(results, json_null_create()); } exit: ovsdb_error_destroy(error); ovsdb_symbol_table_destroy(x.symtab); return results; }
void jsonrpc_session_run(struct jsonrpc_session *s) { if (s->pstream) { struct stream *stream; int error; error = pstream_accept(s->pstream, &stream); if (!error) { if (s->rpc || s->stream) { VLOG_INFO_RL(&rl, "%s: new connection replacing active connection", reconnect_get_name(s->reconnect)); jsonrpc_session_disconnect(s); } reconnect_connected(s->reconnect, time_msec()); s->rpc = jsonrpc_open(stream); } else if (error != EAGAIN) { reconnect_listen_error(s->reconnect, time_msec(), error); pstream_close(s->pstream); s->pstream = NULL; } } if (s->rpc) { size_t backlog; int error; backlog = jsonrpc_get_backlog(s->rpc); jsonrpc_run(s->rpc); if (jsonrpc_get_backlog(s->rpc) < backlog) { /* Data previously caught in a queue was successfully sent (or * there's an error, which we'll catch below.) * * We don't count data that is successfully sent immediately as * activity, because there's a lot of queuing downstream from us, * which means that we can push a lot of data into a connection * that has stalled and won't ever recover. */ reconnect_activity(s->reconnect, time_msec()); } error = jsonrpc_get_status(s->rpc); if (error) { reconnect_disconnected(s->reconnect, time_msec(), error); jsonrpc_session_disconnect(s); s->last_error = error; } } else if (s->stream) { int error; stream_run(s->stream); error = stream_connect(s->stream); if (!error) { reconnect_connected(s->reconnect, time_msec()); s->rpc = jsonrpc_open(s->stream); s->stream = NULL; } else if (error != EAGAIN) { reconnect_connect_failed(s->reconnect, time_msec(), error); stream_close(s->stream); s->stream = NULL; s->last_error = error; } } switch (reconnect_run(s->reconnect, time_msec())) { case RECONNECT_CONNECT: jsonrpc_session_connect(s); break; case RECONNECT_DISCONNECT: reconnect_disconnected(s->reconnect, time_msec(), 0); jsonrpc_session_disconnect(s); break; case RECONNECT_PROBE: if (s->rpc) { struct json *params; struct jsonrpc_msg *request; params = json_array_create_empty(); request = jsonrpc_create_request("echo", params, NULL); json_destroy(request->id); request->id = json_string_create("echo"); jsonrpc_send(s->rpc, request); } break; } }
void replication_run(void) { if (!session) { return; } jsonrpc_session_run(session); for (int i = 0; jsonrpc_session_is_connected(session) && i < 50; i++) { struct jsonrpc_msg *msg; unsigned int seqno; seqno = jsonrpc_session_get_seqno(session); if (seqno != session_seqno || state == RPL_S_INIT) { session_seqno = seqno; request_ids_clear(); struct jsonrpc_msg *request; request = jsonrpc_create_request("list_dbs", json_array_create_empty(), NULL); request_ids_add(request->id, NULL); jsonrpc_session_send(session, request); replication_dbs_destroy(); replication_dbs = replication_db_clone(&local_dbs); state = RPL_S_DB_REQUESTED; VLOG_DBG("Send list_dbs request"); } msg = jsonrpc_session_recv(session); if (!msg) { continue; } if (msg->type == JSONRPC_NOTIFY && state != RPL_S_ERR && !strcmp(msg->method, "update")) { if (msg->params->type == JSON_ARRAY && msg->params->u.array.n == 2 && msg->params->u.array.elems[0]->type == JSON_STRING) { char *db_name = msg->params->u.array.elems[0]->u.string; struct ovsdb *db = find_db(db_name); if (db) { struct ovsdb_error *error; error = process_notification(msg->params->u.array.elems[1], db); if (error) { ovsdb_error_assert(error); state = RPL_S_ERR; } } } } else if (msg->type == JSONRPC_REPLY) { struct ovsdb *db; if (!request_ids_lookup_and_free(msg->id, &db)) { VLOG_WARN("received unexpected reply"); goto next; } switch (state) { case RPL_S_DB_REQUESTED: if (msg->result->type != JSON_ARRAY) { struct ovsdb_error *error; error = ovsdb_error("list-dbs failed", "list_dbs response is not array"); ovsdb_error_assert(error); state = RPL_S_ERR; } else { size_t i; for (i = 0; i < msg->result->u.array.n; i++) { const struct json *name = msg->result->u.array.elems[i]; if (name->type == JSON_STRING) { /* Send one schema request for each remote DB. */ const char *db_name = json_string(name); struct ovsdb *db = find_db(db_name); if (db) { struct jsonrpc_msg *request = jsonrpc_create_request( "get_schema", json_array_create_1( json_string_create(db_name)), NULL); request_ids_add(request->id, db); jsonrpc_session_send(session, request); } } } VLOG_DBG("Send schema requests"); state = RPL_S_SCHEMA_REQUESTED; } break; case RPL_S_SCHEMA_REQUESTED: { struct ovsdb_schema *schema; struct ovsdb_error *error; error = ovsdb_schema_from_json(msg->result, &schema); if (error) { ovsdb_error_assert(error); state = RPL_S_ERR; } if (db != find_db(schema->name)) { /* Unexpected schema. */ VLOG_WARN("unexpected schema %s", schema->name); state = RPL_S_ERR; } else if (!ovsdb_schema_equal(schema, db->schema)) { /* Schmea version mismatch. */ VLOG_INFO("Schema version mismatch, %s not replicated", schema->name); shash_find_and_delete(replication_dbs, schema->name); } ovsdb_schema_destroy(schema); /* After receiving schemas, reset the local databases that * will be monitored and send out monitor requests for them. */ if (hmap_is_empty(&request_ids)) { struct shash_node *node, *next; SHASH_FOR_EACH_SAFE (node, next, replication_dbs) { db = node->data; struct ovsdb_error *error = reset_database(db); if (error) { const char *db_name = db->schema->name; shash_find_and_delete(replication_dbs, db_name); ovsdb_error_assert(error); VLOG_WARN("Failed to reset database, " "%s not replicated.", db_name); } } if (shash_is_empty(replication_dbs)) { VLOG_WARN("Nothing to replicate."); state = RPL_S_ERR; } else { SHASH_FOR_EACH (node, replication_dbs) { db = node->data; struct ovsdb *db = node->data; struct jsonrpc_msg *request = create_monitor_request(db); request_ids_add(request->id, db); jsonrpc_session_send(session, request); VLOG_DBG("Send monitor requests"); state = RPL_S_MONITOR_REQUESTED; } } } break; } case RPL_S_MONITOR_REQUESTED: { /* Reply to monitor requests. */ struct ovsdb_error *error; error = process_notification(msg->result, db); if (error) { ovsdb_error_assert(error); state = RPL_S_ERR; } else { /* Transition to replicating state after receiving * all replies of "monitor" requests. */ if (hmap_is_empty(&request_ids)) { VLOG_DBG("Listening to monitor updates"); state = RPL_S_REPLICATING; } } break; } case RPL_S_ERR: /* Ignore all messages */ break; case RPL_S_INIT: case RPL_S_REPLICATING: default: OVS_NOT_REACHED(); } }
void jsonrpc_session_run(struct jsonrpc_session *s) { if (s->pstream) { struct stream *stream; int error; error = pstream_accept(s->pstream, &stream); if (!error) { if (s->rpc || s->stream) { VLOG_INFO_RL(&rl, "%s: new connection replacing active connection", reconnect_get_name(s->reconnect)); jsonrpc_session_disconnect(s); } reconnect_connected(s->reconnect, time_msec()); s->rpc = jsonrpc_open(stream); } else if (error != EAGAIN) { reconnect_listen_error(s->reconnect, time_msec(), error); pstream_close(s->pstream); s->pstream = NULL; } } if (s->rpc) { int error; jsonrpc_run(s->rpc); error = jsonrpc_get_status(s->rpc); if (error) { reconnect_disconnected(s->reconnect, time_msec(), error); jsonrpc_session_disconnect(s); } } else if (s->stream) { int error; stream_run(s->stream); error = stream_connect(s->stream); if (!error) { reconnect_connected(s->reconnect, time_msec()); s->rpc = jsonrpc_open(s->stream); s->stream = NULL; } else if (error != EAGAIN) { reconnect_connect_failed(s->reconnect, time_msec(), error); stream_close(s->stream); s->stream = NULL; } } switch (reconnect_run(s->reconnect, time_msec())) { case RECONNECT_CONNECT: jsonrpc_session_connect(s); break; case RECONNECT_DISCONNECT: reconnect_disconnected(s->reconnect, time_msec(), 0); jsonrpc_session_disconnect(s); break; case RECONNECT_PROBE: if (s->rpc) { struct json *params; struct jsonrpc_msg *request; params = json_array_create_empty(); request = jsonrpc_create_request("echo", params, NULL); json_destroy(request->id); request->id = json_string_create("echo"); jsonrpc_send(s->rpc, request); } break; } }