diff --git a/README.md b/README.md index be923cf..eb3cb62 100644 --- a/README.md +++ b/README.md @@ -181,8 +181,6 @@ this case since the response has been already arrived (we are inside the callbac // ... your code can continue here without any delay ``` -## etcd operations - ### Multiple endpoints Connecting to multiple endpoints is supported: @@ -364,6 +362,46 @@ Note that the timeout value is the "timeout" when waiting for responses upon the It doesn't means the timeout between issuing a `.set()` method getting the `etcd::Response`, as in the async mode the such a time duration is unpredictable and the gRPC timeout should be enough to avoid deadly waiting (e.g., waiting for a `lock()`). +### Error code in responses + +The `class etcd::Response` may yield an error code and error message when error occurs, + +```cpp + int error_code() const; + std::string const & error_message() const; + + bool is_ok() const; +``` + +The error code would be `0` when succeed, otherwise the error code might be + +```cpp + extern const int ERROR_GRPC_OK; + extern const int ERROR_GRPC_CANCELLED; + extern const int ERROR_GRPC_UNKNOWN; + extern const int ERROR_GRPC_INVALID_ARGUMENT; + extern const int ERROR_GRPC_DEADLINE_EXCEEDED; + extern const int ERROR_GRPC_NOT_FOUND; + extern const int ERROR_GRPC_ALREADY_EXISTS; + extern const int ERROR_GRPC_PERMISSION_DENIED; + extern const int ERROR_GRPC_UNAUTHENTICATED; + extern const int ERROR_GRPC_RESOURCE_EXHAUSTED; + extern const int ERROR_GRPC_FAILED_PRECONDITION; + extern const int ERROR_GRPC_ABORTED; + extern const int ERROR_GRPC_OUT_OF_RANGE; + extern const int ERROR_GRPC_UNIMPLEMENTED; + extern const int ERROR_GRPC_INTERNAL; + extern const int ERROR_GRPC_UNAVAILABLE; + extern const int ERROR_GRPC_DATA_LOSS; + + extern const int ERROR_KEY_NOT_FOUND; + extern const int ERROR_COMPARE_FAILED; + extern const int ERROR_KEY_ALREADY_EXISTS; + extern const int ERROR_ACTION_CANCELLED; +``` + +## Etcd operations + ### Reading a value You can read a value with the `get()` method of the client instance. The only parameter is the @@ -434,7 +472,7 @@ some specific conditions. * `add(key, value)` creates a new value if it's key does not exists and returns a "Key already exists" error otherwise (error code `ERROR_KEY_ALREADY_EXISTS`) -* `modify(key, value)` modifies an already existing value or returns a "Key not found" error +* `modify(key, value)` modifies an already existing value or returns a "etcd-cpp-apiv3: key not found" error otherwise (error code `KEY_NOT_FOUND`) * `modify_if(key, value, old_value)` modifies an already existing value but only if the previous value equals with old_value. If the values does not match returns with "Compare failed" error diff --git a/etcd/Client.hpp b/etcd/Client.hpp index 174a869..8554ef1 100644 --- a/etcd/Client.hpp +++ b/etcd/Client.hpp @@ -16,7 +16,6 @@ namespace etcd { - // FIXME /** * Client is responsible for maintaining a connection towards an etcd server. * Etcd operations can be reached via the methods of the client. diff --git a/etcd/Response.hpp b/etcd/Response.hpp index 56b9b26..5f4384e 100644 --- a/etcd/Response.hpp +++ b/etcd/Response.hpp @@ -63,9 +63,9 @@ namespace etcd } template - static etcd::Response create(std::function()> callfn) + static etcd::Response create(std::function()> fn) { - auto call = callfn(); + auto call = fn(); call->waitForResponse(); auto v3resp = call->ParseResponse(); @@ -76,9 +76,9 @@ namespace etcd } template - static etcd::Response create(std::function()> callfn) + static etcd::Response create(std::function()> fn) { - auto call = callfn(); + auto call = fn(); call->waitForResponse(); auto v3resp = call->ParseResponse(); @@ -92,6 +92,16 @@ namespace etcd Response(const Response &); + /** + * Returns the error code received from the etcd server. In case of success the error code is 0. + */ + int error_code() const; + + /** + * Returns the string representation of the error code + */ + std::string const & error_message() const; + /** * Returns true if this is a successful response */ @@ -102,21 +112,11 @@ namespace etcd */ bool is_network_unavailable() const; - /** - * Returns the error code received from the etcd server. In case of success the error code is 0. - */ - int error_code() const; - /** * Check whether the response contains a grpc TIMEOUT error. */ bool is_grpc_timeout() const; - /** - * Returns the string representation of the error code - */ - std::string const & error_message() const; - /** * Returns the action type of the operation that this response belongs to. */ @@ -200,6 +200,7 @@ namespace etcd protected: Response(const etcdv3::V3Response& response, std::chrono::microseconds const& duration); + Response(int error_code, std::string const& error_message); Response(int error_code, char const * error_message); int _error_code; diff --git a/etcd/SyncClient.hpp b/etcd/SyncClient.hpp index aaa8840..30e6cef 100644 --- a/etcd/SyncClient.hpp +++ b/etcd/SyncClient.hpp @@ -68,7 +68,6 @@ namespace etcd class Watcher; class Client; - // FIXME /** * Client is responsible for maintaining a connection towards an etcd server. * Etcd operations can be reached via the methods of the client. diff --git a/etcd/v3/action_constants.hpp b/etcd/v3/action_constants.hpp index 8c4d29a..d1728a4 100644 --- a/etcd/v3/action_constants.hpp +++ b/etcd/v3/action_constants.hpp @@ -41,6 +41,24 @@ namespace etcdv3 extern char const * ELECTION_OBSERVE_CREATE; + extern const int ERROR_GRPC_OK; + extern const int ERROR_GRPC_CANCELLED; + extern const int ERROR_GRPC_UNKNOWN; + extern const int ERROR_GRPC_INVALID_ARGUMENT; + extern const int ERROR_GRPC_DEADLINE_EXCEEDED; + extern const int ERROR_GRPC_NOT_FOUND; + extern const int ERROR_GRPC_ALREADY_EXISTS; + extern const int ERROR_GRPC_PERMISSION_DENIED; + extern const int ERROR_GRPC_UNAUTHENTICATED; + extern const int ERROR_GRPC_RESOURCE_EXHAUSTED; + extern const int ERROR_GRPC_FAILED_PRECONDITION; + extern const int ERROR_GRPC_ABORTED; + extern const int ERROR_GRPC_OUT_OF_RANGE; + extern const int ERROR_GRPC_UNIMPLEMENTED; + extern const int ERROR_GRPC_INTERNAL; + extern const int ERROR_GRPC_UNAVAILABLE; + extern const int ERROR_GRPC_DATA_LOSS; + extern const int ERROR_KEY_NOT_FOUND; extern const int ERROR_COMPARE_FAILED; extern const int ERROR_KEY_ALREADY_EXISTS; diff --git a/src/Response.cpp b/src/Response.cpp index f485fbf..6b8365b 100644 --- a/src/Response.cpp +++ b/src/Response.cpp @@ -67,6 +67,13 @@ etcd::Response::Response(const etcdv3::V3Response& reply, std::chrono::microseco _raft_term = reply.get_raft_term(); } +etcd::Response::Response(int error_code, std::string const& error_message) + : _error_code(error_code), + _error_message(error_message), + _index(0) +{ +} + etcd::Response::Response(int error_code, char const * error_message) : _error_code(error_code), _error_message(error_message), @@ -84,21 +91,6 @@ std::string const & etcd::Response::error_message() const return _error_message; } -bool etcd::Response::is_grpc_timeout() const -{ - return _error_code == grpc::StatusCode::DEADLINE_EXCEEDED; -} - -int64_t etcd::Response::index() const -{ - return _index; -} - -std::string const & etcd::Response::action() const -{ - return _action; -} - bool etcd::Response::is_ok() const { return error_code() == 0; @@ -109,6 +101,21 @@ bool etcd::Response::is_network_unavailable() const return error_code() == ::grpc::StatusCode::UNAVAILABLE; } +bool etcd::Response::is_grpc_timeout() const +{ + return _error_code == grpc::StatusCode::DEADLINE_EXCEEDED; +} + +std::string const & etcd::Response::action() const +{ + return _action; +} + +int64_t etcd::Response::index() const +{ + return _index; +} + etcd::Value const & etcd::Response::value() const { return _value; diff --git a/src/SyncClient.cpp b/src/SyncClient.cpp index d8f193f..76ec094 100644 --- a/src/SyncClient.cpp +++ b/src/SyncClient.cpp @@ -530,7 +530,7 @@ etcd::Response etcd::SyncClient::set(std::string const & key, std::string const auto res = this->leasegrant(ttl); if(!res.is_ok()) { - return etcd::Response(res.error_code(), res.error_message().c_str()); + return etcd::Response(res.error_code(), res.error_message()); } else { @@ -565,7 +565,7 @@ etcd::Response etcd::SyncClient::add(std::string const & key, std::string const auto res = this->leasegrant(ttl); if(!res.is_ok()) { - return etcd::Response(res.error_code(), res.error_message().c_str()); + return etcd::Response(res.error_code(), res.error_message()); } else { @@ -614,7 +614,7 @@ etcd::Response etcd::SyncClient::modify(std::string const & key, std::string con auto res = leasegrant(ttl); if(!res.is_ok()) { - return etcd::Response(res.error_code(), res.error_message().c_str()); + return etcd::Response(res.error_code(), res.error_message()); } else { @@ -649,7 +649,7 @@ etcd::Response etcd::SyncClient::modify_if(std::string const & key, std::string auto res = leasegrant(ttl); if(!res.is_ok()) { - return etcd::Response(res.error_code(), res.error_message().c_str()); + return etcd::Response(res.error_code(), res.error_message()); } else { @@ -673,7 +673,7 @@ etcd::Response etcd::SyncClient::modify_if(std::string const & key, std::string auto res = leasegrant(ttl); if(!res.is_ok()) { - return etcd::Response(res.error_code(), res.error_message().c_str()); + return etcd::Response(res.error_code(), res.error_message()); } else { diff --git a/src/v3/AsyncCompareAndDeleteAction.cpp b/src/v3/AsyncCompareAndDeleteAction.cpp index 1045709..f4253d4 100644 --- a/src/v3/AsyncCompareAndDeleteAction.cpp +++ b/src/v3/AsyncCompareAndDeleteAction.cpp @@ -51,7 +51,7 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncCompareAndDeleteAction::ParseResponse() if(!reply.succeeded()) { txn_resp.set_error_code(ERROR_COMPARE_FAILED); - txn_resp.set_error_message("Compare failed"); + txn_resp.set_error_message("etcd-cpp-apiv3: compare failed"); } } diff --git a/src/v3/AsyncCompareAndSwapAction.cpp b/src/v3/AsyncCompareAndSwapAction.cpp index 43e9b69..82d003d 100644 --- a/src/v3/AsyncCompareAndSwapAction.cpp +++ b/src/v3/AsyncCompareAndSwapAction.cpp @@ -53,7 +53,7 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncCompareAndSwapAction::ParseResponse() if(!reply.succeeded() && !txn_resp.get_error_code()) { txn_resp.set_error_code(ERROR_COMPARE_FAILED); - txn_resp.set_error_message("Compare failed"); + txn_resp.set_error_message("etcd-cpp-apiv3: compare failed"); } } diff --git a/src/v3/AsyncDeleteResponse.cpp b/src/v3/AsyncDeleteResponse.cpp index fa4b3d3..f504e3a 100644 --- a/src/v3/AsyncDeleteResponse.cpp +++ b/src/v3/AsyncDeleteResponse.cpp @@ -9,7 +9,7 @@ void etcdv3::AsyncDeleteResponse::ParseResponse(std::string const& key, bool pre if(resp.prev_kvs_size() == 0) { error_code = etcdv3::ERROR_KEY_NOT_FOUND; - error_message = "Key not found"; + error_message = "etcd-cpp-apiv3: key not found"; } else { diff --git a/src/v3/AsyncRangeResponse.cpp b/src/v3/AsyncRangeResponse.cpp index b3ab92e..2dfa73b 100644 --- a/src/v3/AsyncRangeResponse.cpp +++ b/src/v3/AsyncRangeResponse.cpp @@ -8,7 +8,7 @@ void etcdv3::AsyncRangeResponse::ParseResponse(RangeResponse& resp, bool prefix) if(resp.kvs_size() == 0 && !prefix) { error_code = etcdv3::ERROR_KEY_NOT_FOUND; - error_message = "Key not found"; + error_message = "etcd-cpp-apiv3: key not found"; return; } else diff --git a/src/v3/AsyncSetAction.cpp b/src/v3/AsyncSetAction.cpp index 9ae2c29..e09c023 100644 --- a/src/v3/AsyncSetAction.cpp +++ b/src/v3/AsyncSetAction.cpp @@ -44,7 +44,7 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncSetAction::ParseResponse() if(!reply.succeeded() && isCreate) { txn_resp.set_error_code(etcdv3::ERROR_KEY_ALREADY_EXISTS); - txn_resp.set_error_message("Key already exists"); + txn_resp.set_error_message("etcd-cpp-apiv3: key already exists"); } } return txn_resp; diff --git a/src/v3/AsyncTxnAction.cpp b/src/v3/AsyncTxnAction.cpp index ef1b116..6d2d07c 100644 --- a/src/v3/AsyncTxnAction.cpp +++ b/src/v3/AsyncTxnAction.cpp @@ -30,7 +30,7 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncTxnAction::ParseResponse() if(!reply.succeeded() && !txn_resp.get_error_code()) { txn_resp.set_error_code(ERROR_COMPARE_FAILED); - txn_resp.set_error_message("compare failed"); + txn_resp.set_error_message("etcd-cpp-apiv3: compare failed"); } } diff --git a/src/v3/AsyncUpdateAction.cpp b/src/v3/AsyncUpdateAction.cpp index 587b3fe..00ff7bc 100644 --- a/src/v3/AsyncUpdateAction.cpp +++ b/src/v3/AsyncUpdateAction.cpp @@ -43,7 +43,7 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncUpdateAction::ParseResponse() else { txn_resp.set_error_code(etcdv3::ERROR_KEY_NOT_FOUND); - txn_resp.set_error_message("Key not found"); + txn_resp.set_error_message("etcd-cpp-apiv3: key not found"); } } return txn_resp; diff --git a/src/v3/action_constants.cpp b/src/v3/action_constants.cpp index 2baa6cf..a212ffe 100644 --- a/src/v3/action_constants.cpp +++ b/src/v3/action_constants.cpp @@ -40,6 +40,24 @@ char const * etcdv3::WATCH_WRITES_DONE = "watch writes done"; char const * etcdv3::ELECTION_OBSERVE_CREATE = "observe create"; +const int etcdv3::ERROR_GRPC_OK = 0; +const int etcdv3::ERROR_GRPC_CANCELLED = 1; +const int etcdv3::ERROR_GRPC_UNKNOWN = 2; +const int etcdv3::ERROR_GRPC_INVALID_ARGUMENT = 3; +const int etcdv3::ERROR_GRPC_DEADLINE_EXCEEDED = 4; +const int etcdv3::ERROR_GRPC_NOT_FOUND = 5; +const int etcdv3::ERROR_GRPC_ALREADY_EXISTS = 6; +const int etcdv3::ERROR_GRPC_PERMISSION_DENIED = 7; +const int etcdv3::ERROR_GRPC_UNAUTHENTICATED = 16; +const int etcdv3::ERROR_GRPC_RESOURCE_EXHAUSTED = 8; +const int etcdv3::ERROR_GRPC_FAILED_PRECONDITION = 9; +const int etcdv3::ERROR_GRPC_ABORTED = 10; +const int etcdv3::ERROR_GRPC_OUT_OF_RANGE = 11; +const int etcdv3::ERROR_GRPC_UNIMPLEMENTED = 12; +const int etcdv3::ERROR_GRPC_INTERNAL = 13; +const int etcdv3::ERROR_GRPC_UNAVAILABLE = 14; +const int etcdv3::ERROR_GRPC_DATA_LOSS = 15; + const int etcdv3::ERROR_KEY_NOT_FOUND = 100; const int etcdv3::ERROR_COMPARE_FAILED = 101; const int etcdv3::ERROR_KEY_ALREADY_EXISTS = 105; diff --git a/tst/AuthTest.cpp b/tst/AuthTest.cpp index 9efc91f..8862688 100644 --- a/tst/AuthTest.cpp +++ b/tst/AuthTest.cpp @@ -29,7 +29,7 @@ TEST_CASE("add a new key after authenticate") CHECK(0 < resp.index()); CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd->add("/test/key1", "43").get().error_code()); // Key already exists CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd->add("/test/key1", "42").get().error_code()); // Key already exists - CHECK("Key already exists" == etcd->add("/test/key1", "42").get().error_message()); + CHECK("etcd-cpp-apiv3: key already exists" == etcd->add("/test/key1", "42").get().error_message()); } TEST_CASE("read a value from etcd") diff --git a/tst/EtcdTest.cpp b/tst/EtcdTest.cpp index 13e483e..ca99497 100644 --- a/tst/EtcdTest.cpp +++ b/tst/EtcdTest.cpp @@ -31,7 +31,7 @@ TEST_CASE("add a new key") CHECK(0 < resp.index()); CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd.add("/test/key1", "43").get().error_code()); // Key already exists CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd.add("/test/key1", "42").get().error_code()); // Key already exists - CHECK("Key already exists" == etcd.add("/test/key1", "42").get().error_message()); + CHECK("etcd-cpp-apiv3: key already exists" == etcd.add("/test/key1", "42").get().error_message()); } TEST_CASE("read a value from etcd") @@ -98,13 +98,13 @@ TEST_CASE("atomic compare-and-swap") res = etcd.modify_if("/test/key1", "44", "42").get(); CHECK(!res.is_ok()); CHECK(etcd::ERROR_COMPARE_FAILED == res.error_code()); - CHECK("Compare failed" == res.error_message()); + CHECK("etcd-cpp-apiv3: compare failed" == res.error_message()); // modify fails the second time res = etcd.modify_if("/test/key222", "44", "42").get(); CHECK(!res.is_ok()); CHECK(etcd::ERROR_KEY_NOT_FOUND == res.error_code()); - CHECK("Key not found" == res.error_message()); + CHECK("etcd-cpp-apiv3: key not found" == res.error_message()); } TEST_CASE("delete a value") @@ -113,7 +113,7 @@ TEST_CASE("delete a value") etcd::Response resp = etcd.rm("/test/key11111").get(); CHECK(!resp.is_ok()); CHECK(etcd::ERROR_KEY_NOT_FOUND == resp.error_code()); - CHECK("Key not found" == resp.error_message()); + CHECK("etcd-cpp-apiv3: key not found" == resp.error_message()); int64_t index = etcd.get("/test/key1").get().index(); int64_t create_index = etcd.get("/test/key1").get().value().created_index(); @@ -145,7 +145,7 @@ TEST_CASE("atomic compare-and-delete based on prevValue") etcd::Response res = etcd.rm_if("/test/key1", "43").get(); CHECK(!res.is_ok()); CHECK(etcd::ERROR_COMPARE_FAILED == res.error_code()); - CHECK("Compare failed" == res.error_message()); + CHECK("etcd-cpp-apiv3: compare failed" == res.error_message()); res = etcd.rm_if("/test/key1", "42").get(); REQUIRE(res.is_ok()); @@ -161,7 +161,7 @@ TEST_CASE("atomic compare-and-delete based on prevIndex") etcd::Response res = etcd.rm_if("/test/key1", index - 1).get(); CHECK(!res.is_ok()); CHECK(etcd::ERROR_COMPARE_FAILED == res.error_code()); - CHECK("Compare failed" == res.error_message()); + CHECK("etcd-cpp-apiv3: compare failed" == res.error_message()); res = etcd.rm_if("/test/key1", index).get(); REQUIRE(res.is_ok()); @@ -185,7 +185,7 @@ TEST_CASE("deep atomic compare-and-swap") res = etcd.modify_if("/test/key1", "44", "42").get(); CHECK(!res.is_ok()); CHECK(etcd::ERROR_COMPARE_FAILED == res.error_code()); - CHECK("Compare failed" == res.error_message()); + CHECK("etcd-cpp-apiv3: compare failed" == res.error_message()); // succes with the correct index res = etcd.modify_if("/test/key1", "44", index).get(); @@ -197,7 +197,7 @@ TEST_CASE("deep atomic compare-and-swap") res = etcd.modify_if("/test/key1", "45", index).get(); CHECK(!res.is_ok()); CHECK(etcd::ERROR_COMPARE_FAILED == res.error_code()); - CHECK("Compare failed" == res.error_message()); + CHECK("etcd-cpp-apiv3: compare failed" == res.error_message()); } TEST_CASE("list a directory") @@ -295,12 +295,12 @@ TEST_CASE("delete a directory") resp = etcd.rmdir("/test/dirnotfound", true).get(); CHECK(!resp.is_ok()); CHECK(etcd::ERROR_KEY_NOT_FOUND == resp.error_code()); - CHECK("Key not found" == resp.error_message()); + CHECK("etcd-cpp-apiv3: key not found" == resp.error_message()); resp = etcd.rmdir("/test/new_dir", false).get(); CHECK(!resp.is_ok()); CHECK(etcd::ERROR_KEY_NOT_FOUND == resp.error_code()); - CHECK("Key not found" == resp.error_message()); + CHECK("etcd-cpp-apiv3: key not found" == resp.error_message()); } TEST_CASE("delete by range") diff --git a/tst/SecurityChannelTest.cpp b/tst/SecurityChannelTest.cpp index fda754e..89001d7 100644 --- a/tst/SecurityChannelTest.cpp +++ b/tst/SecurityChannelTest.cpp @@ -32,7 +32,7 @@ TEST_CASE("add a new key after authenticate") CHECK(0 < resp.index()); CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd->add("/test/key1", "43").get().error_code()); // Key already exists CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd->add("/test/key1", "42").get().error_code()); // Key already exists - CHECK("Key already exists" == etcd->add("/test/key1", "42").get().error_message()); + CHECK("etcd-cpp-apiv3: key already exists" == etcd->add("/test/key1", "42").get().error_message()); } TEST_CASE("read a value from etcd")