Beispiel #1
0
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);
}
Beispiel #2
0
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;
}
Beispiel #4
0
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;
    }
}
Beispiel #5
0
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();
            }
        }
Beispiel #6
0
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;
    }
}