Compare commits
1 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
5994b54c68 |
|
|
@ -403,6 +403,26 @@ jobs:
|
||||||
killall -TERM etcd
|
killall -TERM etcd
|
||||||
sleep 5
|
sleep 5
|
||||||
|
|
||||||
|
- name: Etcd Member test
|
||||||
|
run: |
|
||||||
|
killall -TERM etcd || true
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib:/usr/local/lib/x86_64-linux-gnu
|
||||||
|
|
||||||
|
# use etcd v3 api
|
||||||
|
export ETCDCTL_API="3"
|
||||||
|
|
||||||
|
|
||||||
|
rm -rf default.etcd
|
||||||
|
/usr/local/bin/etcd &
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
./build/bin/EtcdMemberTest
|
||||||
|
|
||||||
|
killall -TERM etcd
|
||||||
|
sleep 5
|
||||||
|
|
||||||
- name: Check ccache
|
- name: Check ccache
|
||||||
run: |
|
run: |
|
||||||
ccache --show-stats
|
ccache --show-stats
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
set(etcd-cpp-api_VERSION_MAJOR 0)
|
set(etcd-cpp-api_VERSION_MAJOR 0)
|
||||||
set(etcd-cpp-api_VERSION_MINOR 15)
|
set(etcd-cpp-api_VERSION_MINOR 15)
|
||||||
set(etcd-cpp-api_VERSION_PATCH 4)
|
set(etcd-cpp-api_VERSION_PATCH 5)
|
||||||
set(etcd-cpp-api_VERSION ${etcd-cpp-api_VERSION_MAJOR}.${etcd-cpp-api_VERSION_MINOR}.${etcd-cpp-api_VERSION_PATCH})
|
set(etcd-cpp-api_VERSION ${etcd-cpp-api_VERSION_MAJOR}.${etcd-cpp-api_VERSION_MINOR}.${etcd-cpp-api_VERSION_PATCH})
|
||||||
set(CMAKE_PROJECT_HOMEPAGE_URL https://github.com/etcd-cpp-apiv3/etcd-cpp-apiv3)
|
set(CMAKE_PROJECT_HOMEPAGE_URL https://github.com/etcd-cpp-apiv3/etcd-cpp-apiv3)
|
||||||
|
|
||||||
|
|
@ -90,7 +90,7 @@ macro(use_cxx target)
|
||||||
endmacro(use_cxx)
|
endmacro(use_cxx)
|
||||||
|
|
||||||
macro(set_exceptions target)
|
macro(set_exceptions target)
|
||||||
if(BUILD_NO_EXCEPTIONS)
|
if(BUILD_WITH_NO_EXCEPTIONS)
|
||||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
target_compile_options(${target} PRIVATE "-fno-exceptions")
|
target_compile_options(${target} PRIVATE "-fno-exceptions")
|
||||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||||
|
|
@ -252,6 +252,7 @@ if(NOT BUILD_ETCD_CORE_ONLY)
|
||||||
endif()
|
endif()
|
||||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/etcd/v3/action_constants.hpp
|
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/etcd/v3/action_constants.hpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/etcd/v3/Transaction.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/etcd/v3/Transaction.hpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/etcd/v3/Member.hpp
|
||||||
DESTINATION include/etcd/v3)
|
DESTINATION include/etcd/v3)
|
||||||
|
|
||||||
configure_file(etcd-cpp-api-config.in.cmake
|
configure_file(etcd-cpp-api-config.in.cmake
|
||||||
|
|
@ -337,6 +338,7 @@ set(CPACK_DEBIAN_PACKAGE_INSTALL "/usr/lib/lib*.so*"
|
||||||
"/usr/include/etcd/*.hpp"
|
"/usr/include/etcd/*.hpp"
|
||||||
"/usr/include/etcd/v3/action_constants.hpp"
|
"/usr/include/etcd/v3/action_constants.hpp"
|
||||||
"/usr/include/etcd/v3/Transaction.hpp"
|
"/usr/include/etcd/v3/Transaction.hpp"
|
||||||
|
"/usr/include/etcd/v3/Member.hpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
set(CPACK_DEBIAN_PACKAGE_BUILD_NUMBER_PREFIX "")
|
set(CPACK_DEBIAN_PACKAGE_BUILD_NUMBER_PREFIX "")
|
||||||
|
|
|
||||||
|
|
@ -534,10 +534,10 @@ Values can be deleted with the `rm` method passing the key to be deleted as a pa
|
||||||
should point to an existing value. There are conditional variations for deletion too.
|
should point to an existing value. There are conditional variations for deletion too.
|
||||||
|
|
||||||
* `rm(std::string const& key)` unconditionally deletes the given key
|
* `rm(std::string const& key)` unconditionally deletes the given key
|
||||||
* `rm_if(key, value, old_value)` deletes an already existing value but only if the previous
|
* `rm_if(key, old_value)` deletes 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
|
value equals with old_value. If the values does not match returns with "Compare failed" error
|
||||||
(code `ERROR_COMPARE_FAILED`)
|
(code `ERROR_COMPARE_FAILED`)
|
||||||
* `rm_if(key, value, old_index)` deletes an already existing value but only if the index of
|
* `rm_if(key, old_index)` deletes an already existing value but only if the index of
|
||||||
the previous value equals with old_index. If the indices does not match returns with "Compare
|
the previous value equals with old_index. If the indices does not match returns with "Compare
|
||||||
failed" error (code `ERROR_COMPARE_FAILED`)
|
failed" error (code `ERROR_COMPARE_FAILED`)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -630,6 +630,25 @@ class Client {
|
||||||
*/
|
*/
|
||||||
pplx::task<Response> leases();
|
pplx::task<Response> leases();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an etcd member to the etcd cluster, equivalent to `etcdctl member add`.
|
||||||
|
* @param peer_urls is comma separated list of URLs for the new member.
|
||||||
|
* @param is_learner is true if the added member is a learner.
|
||||||
|
*/
|
||||||
|
pplx::task<Response> add_member(std::string const& peer_urls,
|
||||||
|
bool is_learner);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all members, equivalent to `etcdctl member list`.
|
||||||
|
*/
|
||||||
|
pplx::task<Response> list_member();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an etcd member to the etcd cluster, equivalent to `etcdctl member add`.
|
||||||
|
* @param member_id is the ID of the member to be removed.
|
||||||
|
*/
|
||||||
|
pplx::task<Response> remove_member(const uint64_t member_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gains a lock at a key, using a default created lease, using the default
|
* Gains a lock at a key, using a default created lease, using the default
|
||||||
* lease (10 seconds), with keeping alive has already been taken care of by
|
* lease (10 seconds), with keeping alive has already been taken care of by
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "etcd/Value.hpp"
|
#include "etcd/Value.hpp"
|
||||||
|
#include "etcd/v3/Member.hpp"
|
||||||
|
|
||||||
namespace etcdv3 {
|
namespace etcdv3 {
|
||||||
class AsyncWatchAction;
|
class AsyncWatchAction;
|
||||||
|
|
@ -208,6 +209,11 @@ class Response {
|
||||||
*/
|
*/
|
||||||
std::vector<int64_t> const& leases() const;
|
std::vector<int64_t> const& leases() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the member list.
|
||||||
|
*/
|
||||||
|
std::vector<etcdv3::Member> const& members() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Response(const etcdv3::V3Response& response,
|
Response(const etcdv3::V3Response& response,
|
||||||
std::chrono::microseconds const& duration);
|
std::chrono::microseconds const& duration);
|
||||||
|
|
@ -239,6 +245,9 @@ class Response {
|
||||||
// for lease list
|
// for lease list
|
||||||
std::vector<int64_t> _leases;
|
std::vector<int64_t> _leases;
|
||||||
|
|
||||||
|
// for member list
|
||||||
|
std::vector<etcdv3::Member> _members;
|
||||||
|
|
||||||
friend class Client;
|
friend class Client;
|
||||||
friend class SyncClient;
|
friend class SyncClient;
|
||||||
friend class KeepAlive;
|
friend class KeepAlive;
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,9 @@ class AsyncLeaseKeepAliveAction;
|
||||||
class AsyncLeaseTimeToLiveAction;
|
class AsyncLeaseTimeToLiveAction;
|
||||||
class AsyncLeaseLeasesAction;
|
class AsyncLeaseLeasesAction;
|
||||||
class AsyncLockAction;
|
class AsyncLockAction;
|
||||||
|
class AsyncAddMemberAction;
|
||||||
|
class AsyncListMemberAction;
|
||||||
|
class AsyncRemoveMemberAction;
|
||||||
class AsyncUnlockAction;
|
class AsyncUnlockAction;
|
||||||
class AsyncPutAction;
|
class AsyncPutAction;
|
||||||
class AsyncRangeAction;
|
class AsyncRangeAction;
|
||||||
|
|
@ -679,6 +682,24 @@ class SyncClient {
|
||||||
*/
|
*/
|
||||||
Response leases();
|
Response leases();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an etcd member to the etcd cluster, equivalent to `etcdctl member add`.
|
||||||
|
* @param peer_urls is comma separated list of URLs for the new member.
|
||||||
|
* @param is_learner is true if the added member is a learner.
|
||||||
|
*/
|
||||||
|
Response add_member(std::string const& peer_urls, bool is_learner);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all members, equivalent to `etcdctl member list`.
|
||||||
|
*/
|
||||||
|
Response list_member();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a member of an etcd cluster, equivalent to `etcdctl member remove`.
|
||||||
|
* @param member_id is the id of the member to be removed.
|
||||||
|
*/
|
||||||
|
Response remove_member(uint64_t member_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gains a lock at a key, using a default created lease, using the default
|
* Gains a lock at a key, using a default created lease, using the default
|
||||||
* lease (10 seconds), with keeping alive has already been taken care of by
|
* lease (10 seconds), with keeping alive has already been taken care of by
|
||||||
|
|
@ -835,6 +856,11 @@ class SyncClient {
|
||||||
std::shared_ptr<etcdv3::AsyncLeaseTimeToLiveAction> leasetimetolive_internal(
|
std::shared_ptr<etcdv3::AsyncLeaseTimeToLiveAction> leasetimetolive_internal(
|
||||||
int64_t lease_id);
|
int64_t lease_id);
|
||||||
std::shared_ptr<etcdv3::AsyncLeaseLeasesAction> leases_internal();
|
std::shared_ptr<etcdv3::AsyncLeaseLeasesAction> leases_internal();
|
||||||
|
std::shared_ptr<etcdv3::AsyncAddMemberAction> add_member_internal(
|
||||||
|
std::string const& peer_urls, bool is_learner);
|
||||||
|
std::shared_ptr<etcdv3::AsyncListMemberAction> list_member_internal();
|
||||||
|
std::shared_ptr<etcdv3::AsyncRemoveMemberAction> remove_member_internal(
|
||||||
|
const uint64_t member_id);
|
||||||
Response lock_internal(std::string const& key,
|
Response lock_internal(std::string const& key,
|
||||||
std::shared_ptr<etcd::KeepAlive> const& keepalive);
|
std::shared_ptr<etcd::KeepAlive> const& keepalive);
|
||||||
std::shared_ptr<etcdv3::AsyncLockAction> lock_with_lease_internal(
|
std::shared_ptr<etcdv3::AsyncLockAction> lock_with_lease_internal(
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,9 @@ class Value {
|
||||||
int64_t leaseId;
|
int64_t leaseId;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<Value> Values;
|
using Values = std::vector<Value>;
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, const Value& value);
|
||||||
|
|
||||||
class Event {
|
class Event {
|
||||||
public:
|
public:
|
||||||
|
|
@ -122,7 +124,12 @@ class Event {
|
||||||
bool _has_kv, _has_prev_kv;
|
bool _has_kv, _has_prev_kv;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<Event> Events;
|
using Events = std::vector<Event>;
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, const Event::EventType& value);
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, const Event& event);
|
||||||
|
|
||||||
} // namespace etcd
|
} // namespace etcd
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ using grpc::ClientContext;
|
||||||
using grpc::CompletionQueue;
|
using grpc::CompletionQueue;
|
||||||
using grpc::Status;
|
using grpc::Status;
|
||||||
|
|
||||||
|
using etcdserverpb::Cluster;
|
||||||
using etcdserverpb::KV;
|
using etcdserverpb::KV;
|
||||||
using etcdserverpb::Lease;
|
using etcdserverpb::Lease;
|
||||||
using etcdserverpb::Watch;
|
using etcdserverpb::Watch;
|
||||||
|
|
@ -44,9 +45,16 @@ struct ActionParameters {
|
||||||
std::string value;
|
std::string value;
|
||||||
std::string old_value;
|
std::string old_value;
|
||||||
std::string auth_token;
|
std::string auth_token;
|
||||||
|
|
||||||
|
// for cluster management apis
|
||||||
|
std::vector<std::string> peer_urls;
|
||||||
|
bool is_learner;
|
||||||
|
uint64_t member_id;
|
||||||
|
|
||||||
std::chrono::microseconds grpc_timeout = std::chrono::microseconds::zero();
|
std::chrono::microseconds grpc_timeout = std::chrono::microseconds::zero();
|
||||||
KV::Stub* kv_stub;
|
KV::Stub* kv_stub;
|
||||||
Watch::Stub* watch_stub;
|
Watch::Stub* watch_stub;
|
||||||
|
Cluster::Stub* cluster_stub;
|
||||||
Lease::Stub* lease_stub;
|
Lease::Stub* lease_stub;
|
||||||
Lock::Stub* lock_stub;
|
Lock::Stub* lock_stub;
|
||||||
Election::Stub* election_stub;
|
Election::Stub* election_stub;
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,12 @@ using etcdserverpb::LeaseRevokeRequest;
|
||||||
using etcdserverpb::LeaseRevokeResponse;
|
using etcdserverpb::LeaseRevokeResponse;
|
||||||
using etcdserverpb::LeaseTimeToLiveRequest;
|
using etcdserverpb::LeaseTimeToLiveRequest;
|
||||||
using etcdserverpb::LeaseTimeToLiveResponse;
|
using etcdserverpb::LeaseTimeToLiveResponse;
|
||||||
|
using etcdserverpb::MemberAddRequest;
|
||||||
|
using etcdserverpb::MemberAddResponse;
|
||||||
|
using etcdserverpb::MemberListRequest;
|
||||||
|
using etcdserverpb::MemberListResponse;
|
||||||
|
using etcdserverpb::MemberRemoveRequest;
|
||||||
|
using etcdserverpb::MemberRemoveResponse;
|
||||||
using etcdserverpb::PutRequest;
|
using etcdserverpb::PutRequest;
|
||||||
using etcdserverpb::PutResponse;
|
using etcdserverpb::PutResponse;
|
||||||
using etcdserverpb::RangeRequest;
|
using etcdserverpb::RangeRequest;
|
||||||
|
|
@ -103,6 +109,24 @@ class AsyncLeaseKeepAliveResponse : public etcdv3::V3Response {
|
||||||
void ParseResponse(LeaseKeepAliveResponse& resp);
|
void ParseResponse(LeaseKeepAliveResponse& resp);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AsyncMemberAddResponse : public etcdv3::V3Response {
|
||||||
|
public:
|
||||||
|
AsyncMemberAddResponse(){};
|
||||||
|
void ParseResponse(MemberAddResponse& resp);
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncMemberListResponse : public etcdv3::V3Response {
|
||||||
|
public:
|
||||||
|
AsyncMemberListResponse(){};
|
||||||
|
void ParseResponse(MemberListResponse& resp);
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncMemberRemoveResponse : public etcdv3::V3Response {
|
||||||
|
public:
|
||||||
|
AsyncMemberRemoveResponse(){};
|
||||||
|
void ParseResponse(MemberRemoveResponse& resp);
|
||||||
|
};
|
||||||
|
|
||||||
class AsyncLeaseLeasesResponse : public etcdv3::V3Response {
|
class AsyncLeaseLeasesResponse : public etcdv3::V3Response {
|
||||||
public:
|
public:
|
||||||
AsyncLeaseLeasesResponse(){};
|
AsyncLeaseLeasesResponse(){};
|
||||||
|
|
@ -275,6 +299,38 @@ class AsyncLeaseKeepAliveAction : public etcdv3::Action {
|
||||||
friend class etcd::KeepAlive;
|
friend class etcd::KeepAlive;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AsyncAddMemberAction : public etcdv3::Action {
|
||||||
|
public:
|
||||||
|
AsyncAddMemberAction(etcdv3::ActionParameters&& params);
|
||||||
|
AsyncMemberAddResponse ParseResponse();
|
||||||
|
|
||||||
|
private:
|
||||||
|
MemberAddResponse reply;
|
||||||
|
std::unique_ptr<ClientAsyncResponseReader<MemberAddResponse>> response_reader;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncListMemberAction : public etcdv3::Action {
|
||||||
|
public:
|
||||||
|
AsyncListMemberAction(etcdv3::ActionParameters&& params);
|
||||||
|
AsyncMemberListResponse ParseResponse();
|
||||||
|
|
||||||
|
private:
|
||||||
|
MemberListResponse reply;
|
||||||
|
std::unique_ptr<ClientAsyncResponseReader<MemberListResponse>>
|
||||||
|
response_reader;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncRemoveMemberAction : public etcdv3::Action {
|
||||||
|
public:
|
||||||
|
AsyncRemoveMemberAction(etcdv3::ActionParameters&& params);
|
||||||
|
AsyncMemberRemoveResponse ParseResponse();
|
||||||
|
|
||||||
|
private:
|
||||||
|
MemberRemoveResponse reply;
|
||||||
|
std::unique_ptr<ClientAsyncResponseReader<MemberRemoveResponse>>
|
||||||
|
response_reader;
|
||||||
|
};
|
||||||
|
|
||||||
class AsyncLeaseLeasesAction : public etcdv3::Action {
|
class AsyncLeaseLeasesAction : public etcdv3::Action {
|
||||||
public:
|
public:
|
||||||
AsyncLeaseLeasesAction(etcdv3::ActionParameters&& params);
|
AsyncLeaseLeasesAction(etcdv3::ActionParameters&& params);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef __V3_ETCDV3MEMBERS_HPP__
|
||||||
|
#define __V3_ETCDV3MEMBERS_HPP__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace etcdv3 {
|
||||||
|
class Member {
|
||||||
|
public:
|
||||||
|
Member();
|
||||||
|
|
||||||
|
void set_id(uint64_t const& id);
|
||||||
|
uint64_t const& get_id() const;
|
||||||
|
void set_name(std::string const& name);
|
||||||
|
std::string const& get_name() const;
|
||||||
|
void set_peerURLs(std::vector<std::string> const& peerURLs);
|
||||||
|
std::vector<std::string> const& get_peerURLs() const;
|
||||||
|
void set_clientURLs(std::vector<std::string> const& clientURLs);
|
||||||
|
std::vector<std::string> const& get_clientURLs() const;
|
||||||
|
void set_learner(bool isLearner);
|
||||||
|
bool get_learner() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64_t id;
|
||||||
|
std::string name;
|
||||||
|
std::vector<std::string> peerURLs;
|
||||||
|
std::vector<std::string> clientURLs;
|
||||||
|
bool isLearner;
|
||||||
|
};
|
||||||
|
} // namespace etcdv3
|
||||||
|
#endif
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include "proto/v3election.pb.h"
|
#include "proto/v3election.pb.h"
|
||||||
|
|
||||||
#include "etcd/v3/KeyValue.hpp"
|
#include "etcd/v3/KeyValue.hpp"
|
||||||
|
#include "etcd/v3/Member.hpp"
|
||||||
|
|
||||||
namespace etcdv3 {
|
namespace etcdv3 {
|
||||||
class V3Response {
|
class V3Response {
|
||||||
|
|
@ -36,6 +37,7 @@ class V3Response {
|
||||||
uint64_t get_member_id() const;
|
uint64_t get_member_id() const;
|
||||||
uint64_t get_raft_term() const;
|
uint64_t get_raft_term() const;
|
||||||
std::vector<int64_t> const& get_leases() const;
|
std::vector<int64_t> const& get_leases() const;
|
||||||
|
std::vector<etcdv3::Member> const& get_members() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int error_code;
|
int error_code;
|
||||||
|
|
@ -59,6 +61,8 @@ class V3Response {
|
||||||
|
|
||||||
// for lease list
|
// for lease list
|
||||||
std::vector<int64_t> leases;
|
std::vector<int64_t> leases;
|
||||||
|
// for member list
|
||||||
|
std::vector<etcdv3::Member> members;
|
||||||
};
|
};
|
||||||
} // namespace etcdv3
|
} // namespace etcdv3
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,10 @@ extern char const* LEASEKEEPALIVE;
|
||||||
extern char const* LEASETIMETOLIVE;
|
extern char const* LEASETIMETOLIVE;
|
||||||
extern char const* LEASELEASES;
|
extern char const* LEASELEASES;
|
||||||
|
|
||||||
|
extern char const* ADDMEMBER;
|
||||||
|
extern char const* LISTMEMBER;
|
||||||
|
extern char const* REMOVEMEMBER;
|
||||||
|
|
||||||
extern char const* CAMPAIGN_ACTION;
|
extern char const* CAMPAIGN_ACTION;
|
||||||
extern char const* PROCLAIM_ACTION;
|
extern char const* PROCLAIM_ACTION;
|
||||||
extern char const* LEADER_ACTION;
|
extern char const* LEADER_ACTION;
|
||||||
|
|
|
||||||
|
|
@ -494,6 +494,27 @@ pplx::task<etcd::Response> etcd::Client::leases() {
|
||||||
this->client->leases_internal());
|
this->client->leases_internal());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pplx::task<etcd::Response> etcd::Client::add_member(
|
||||||
|
std::string const& peer_urls, bool is_learner) {
|
||||||
|
return etcd::detail::asyncify(
|
||||||
|
static_cast<responser_t<etcdv3::AsyncAddMemberAction>>(Response::create),
|
||||||
|
this->client->add_member_internal(peer_urls, is_learner));
|
||||||
|
}
|
||||||
|
|
||||||
|
pplx::task<etcd::Response> etcd::Client::list_member() {
|
||||||
|
return etcd::detail::asyncify(
|
||||||
|
static_cast<responser_t<etcdv3::AsyncListMemberAction>>(Response::create),
|
||||||
|
this->client->list_member_internal());
|
||||||
|
}
|
||||||
|
|
||||||
|
pplx::task<etcd::Response> etcd::Client::remove_member(
|
||||||
|
const uint64_t member_id) {
|
||||||
|
return etcd::detail::asyncify(
|
||||||
|
static_cast<responser_t<etcdv3::AsyncRemoveMemberAction>>(
|
||||||
|
Response::create),
|
||||||
|
this->client->remove_member_internal(member_id));
|
||||||
|
}
|
||||||
|
|
||||||
pplx::task<etcd::Response> etcd::Client::lock(std::string const& key) {
|
pplx::task<etcd::Response> etcd::Client::lock(std::string const& key) {
|
||||||
static const int DEFAULT_LEASE_TTL_FOR_LOCK =
|
static const int DEFAULT_LEASE_TTL_FOR_LOCK =
|
||||||
10; // see also etcd::SyncClient::lock
|
10; // see also etcd::SyncClient::lock
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ etcd::Response::Response(const etcd::Response& response) {
|
||||||
this->_raft_term = response._raft_term;
|
this->_raft_term = response._raft_term;
|
||||||
|
|
||||||
this->_leases = response._leases;
|
this->_leases = response._leases;
|
||||||
|
this->_members = response._members;
|
||||||
}
|
}
|
||||||
|
|
||||||
etcd::Response::Response(const etcdv3::V3Response& reply,
|
etcd::Response::Response(const etcdv3::V3Response& reply,
|
||||||
|
|
@ -64,6 +65,8 @@ etcd::Response::Response(const etcdv3::V3Response& reply,
|
||||||
|
|
||||||
// lease list
|
// lease list
|
||||||
this->_leases = reply.get_leases();
|
this->_leases = reply.get_leases();
|
||||||
|
// member list
|
||||||
|
this->_members = reply.get_members();
|
||||||
}
|
}
|
||||||
|
|
||||||
etcd::Response::Response(int error_code, std::string const& error_message)
|
etcd::Response::Response(int error_code, std::string const& error_message)
|
||||||
|
|
@ -131,3 +134,7 @@ uint64_t etcd::Response::raft_term() const { return this->_raft_term; }
|
||||||
std::vector<int64_t> const& etcd::Response::leases() const {
|
std::vector<int64_t> const& etcd::Response::leases() const {
|
||||||
return this->_leases;
|
return this->_leases;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<etcdv3::Member> const& etcd::Response::members() const {
|
||||||
|
return this->_members;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
@ -101,6 +102,7 @@ static std::string string_join(std::vector<std::string> const& srcs,
|
||||||
static bool dns_resolve(std::string const& target,
|
static bool dns_resolve(std::string const& target,
|
||||||
std::vector<std::string>& endpoints, bool ipv4 = true) {
|
std::vector<std::string>& endpoints, bool ipv4 = true) {
|
||||||
std::vector<std::string> target_parts;
|
std::vector<std::string> target_parts;
|
||||||
|
bool ipv6_url{false};
|
||||||
{
|
{
|
||||||
size_t rindex = target.rfind(':');
|
size_t rindex = target.rfind(':');
|
||||||
if (rindex == target.npos) {
|
if (rindex == target.npos) {
|
||||||
|
|
@ -110,7 +112,17 @@ static bool dns_resolve(std::string const& target,
|
||||||
#endif
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
target_parts.push_back(target.substr(0, rindex));
|
|
||||||
|
std::string host(target.substr(0, rindex));
|
||||||
|
|
||||||
|
// host format is [ipv6]
|
||||||
|
if (!ipv4 && !host.empty() && host[0] == '[' &&
|
||||||
|
host[host.size() - 1] == ']') {
|
||||||
|
host = target.substr(1, rindex - 2);
|
||||||
|
ipv6_url = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
target_parts.push_back(host);
|
||||||
target_parts.push_back(target.substr(rindex + 1));
|
target_parts.push_back(target.substr(rindex + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,6 +144,16 @@ static bool dns_resolve(std::string const& target,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (ipv6_url) {
|
||||||
|
// check valid ipv6
|
||||||
|
struct sockaddr_in6 sa6;
|
||||||
|
if (inet_pton(AF_INET6, target_parts[0].c_str(), &(sa6.sin6_addr)) == 1) {
|
||||||
|
endpoints.emplace_back(target);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
struct addrinfo hints = {}, *addrs;
|
struct addrinfo hints = {}, *addrs;
|
||||||
hints.ai_family = ipv4 ? AF_INET : AF_INET6;
|
hints.ai_family = ipv4 ? AF_INET : AF_INET6;
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
|
@ -342,6 +364,7 @@ void etcd::SyncClient::TokenAuthenticatorDeleter::operator()(
|
||||||
struct etcd::SyncClient::EtcdServerStubs {
|
struct etcd::SyncClient::EtcdServerStubs {
|
||||||
std::unique_ptr<etcdserverpb::KV::Stub> kvServiceStub;
|
std::unique_ptr<etcdserverpb::KV::Stub> kvServiceStub;
|
||||||
std::unique_ptr<etcdserverpb::Watch::Stub> watchServiceStub;
|
std::unique_ptr<etcdserverpb::Watch::Stub> watchServiceStub;
|
||||||
|
std::unique_ptr<etcdserverpb::Cluster::Stub> clusterServiceStub;
|
||||||
std::unique_ptr<etcdserverpb::Lease::Stub> leaseServiceStub;
|
std::unique_ptr<etcdserverpb::Lease::Stub> leaseServiceStub;
|
||||||
std::unique_ptr<v3lockpb::Lock::Stub> lockServiceStub;
|
std::unique_ptr<v3lockpb::Lock::Stub> lockServiceStub;
|
||||||
std::unique_ptr<v3electionpb::Election::Stub> electionServiceStub;
|
std::unique_ptr<v3electionpb::Election::Stub> electionServiceStub;
|
||||||
|
|
@ -370,6 +393,7 @@ etcd::SyncClient::SyncClient(std::string const& address,
|
||||||
stubs.reset(new EtcdServerStubs{});
|
stubs.reset(new EtcdServerStubs{});
|
||||||
stubs->kvServiceStub = KV::NewStub(this->channel);
|
stubs->kvServiceStub = KV::NewStub(this->channel);
|
||||||
stubs->watchServiceStub = Watch::NewStub(this->channel);
|
stubs->watchServiceStub = Watch::NewStub(this->channel);
|
||||||
|
stubs->clusterServiceStub = Cluster::NewStub(this->channel);
|
||||||
stubs->leaseServiceStub = Lease::NewStub(this->channel);
|
stubs->leaseServiceStub = Lease::NewStub(this->channel);
|
||||||
stubs->lockServiceStub = Lock::NewStub(this->channel);
|
stubs->lockServiceStub = Lock::NewStub(this->channel);
|
||||||
stubs->electionServiceStub = Election::NewStub(this->channel);
|
stubs->electionServiceStub = Election::NewStub(this->channel);
|
||||||
|
|
@ -995,6 +1019,60 @@ etcd::SyncClient::leases_internal() {
|
||||||
return std::make_shared<etcdv3::AsyncLeaseLeasesAction>(std::move(params));
|
return std::make_shared<etcdv3::AsyncLeaseLeasesAction>(std::move(params));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
etcd::Response etcd::SyncClient::add_member(std::string const& peer_urls,
|
||||||
|
bool is_learner) {
|
||||||
|
return Response::create(this->add_member_internal(peer_urls, is_learner));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<etcdv3::AsyncAddMemberAction>
|
||||||
|
etcd::SyncClient::add_member_internal(std::string const& peer_urls,
|
||||||
|
bool is_learner) {
|
||||||
|
etcdv3::ActionParameters params;
|
||||||
|
params.auth_token.assign(this->token_authenticator->renew_if_expired());
|
||||||
|
params.grpc_timeout = this->grpc_timeout;
|
||||||
|
params.cluster_stub = stubs->clusterServiceStub.get();
|
||||||
|
|
||||||
|
std::vector<std::string> peer_urls_vector;
|
||||||
|
std::istringstream iss(peer_urls);
|
||||||
|
std::string peer_url;
|
||||||
|
while (std::getline(iss, peer_url, ',')) {
|
||||||
|
peer_urls_vector.push_back(peer_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
params.is_learner = is_learner;
|
||||||
|
params.peer_urls = peer_urls_vector;
|
||||||
|
|
||||||
|
return std::make_shared<etcdv3::AsyncAddMemberAction>(std::move(params));
|
||||||
|
}
|
||||||
|
|
||||||
|
etcd::Response etcd::SyncClient::list_member() {
|
||||||
|
return Response::create(this->list_member_internal());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<etcdv3::AsyncListMemberAction>
|
||||||
|
etcd::SyncClient::list_member_internal() {
|
||||||
|
etcdv3::ActionParameters params;
|
||||||
|
params.auth_token.assign(this->token_authenticator->renew_if_expired());
|
||||||
|
params.grpc_timeout = this->grpc_timeout;
|
||||||
|
params.cluster_stub = stubs->clusterServiceStub.get();
|
||||||
|
return std::make_shared<etcdv3::AsyncListMemberAction>(std::move(params));
|
||||||
|
}
|
||||||
|
|
||||||
|
etcd::Response etcd::SyncClient::remove_member(const uint64_t member_id) {
|
||||||
|
return Response::create(this->remove_member_internal(member_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<etcdv3::AsyncRemoveMemberAction>
|
||||||
|
etcd::SyncClient::remove_member_internal(const uint64_t member_id) {
|
||||||
|
etcdv3::ActionParameters params;
|
||||||
|
params.auth_token.assign(this->token_authenticator->renew_if_expired());
|
||||||
|
params.grpc_timeout = this->grpc_timeout;
|
||||||
|
params.cluster_stub = stubs->clusterServiceStub.get();
|
||||||
|
params.member_id = member_id;
|
||||||
|
|
||||||
|
return std::make_shared<etcdv3::AsyncRemoveMemberAction>(std::move(params));
|
||||||
|
}
|
||||||
|
|
||||||
etcd::Response etcd::SyncClient::lock(std::string const& key) {
|
etcd::Response etcd::SyncClient::lock(std::string const& key) {
|
||||||
// routines in lock usually will be fast, less than 10 seconds.
|
// routines in lock usually will be fast, less than 10 seconds.
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <cstdint>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
#include "etcd/Value.hpp"
|
#include "etcd/Value.hpp"
|
||||||
|
|
@ -44,6 +45,19 @@ int etcd::Value::ttl() const { return _ttl; }
|
||||||
|
|
||||||
int64_t etcd::Value::lease() const { return leaseId; }
|
int64_t etcd::Value::lease() const { return leaseId; }
|
||||||
|
|
||||||
|
std::ostream& etcd::operator<<(std::ostream& os, const etcd::Value& value) {
|
||||||
|
os << "Event: {";
|
||||||
|
os << "Key: " << value.key() << ", ";
|
||||||
|
os << "Value: " << value.as_string() << ", ";
|
||||||
|
os << "Created: " << value.created_index() << ", ";
|
||||||
|
os << "Modified: " << value.modified_index() << ", ";
|
||||||
|
os << "Version: " << value.version() << ", ";
|
||||||
|
os << "TTL: " << value.ttl() << ", ";
|
||||||
|
os << "Lease: " << value.lease() << ", ";
|
||||||
|
os << "}";
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
etcd::Event::Event(mvccpb::Event const& event) {
|
etcd::Event::Event(mvccpb::Event const& event) {
|
||||||
_has_kv = event.has_kv();
|
_has_kv = event.has_kv();
|
||||||
_has_prev_kv = event.has_prev_kv();
|
_has_prev_kv = event.has_prev_kv();
|
||||||
|
|
@ -73,3 +87,30 @@ bool etcd::Event::has_prev_kv() const { return _has_prev_kv; }
|
||||||
const etcd::Value& etcd::Event::kv() const { return _kv; }
|
const etcd::Value& etcd::Event::kv() const { return _kv; }
|
||||||
|
|
||||||
const etcd::Value& etcd::Event::prev_kv() const { return _prev_kv; }
|
const etcd::Value& etcd::Event::prev_kv() const { return _prev_kv; }
|
||||||
|
|
||||||
|
std::ostream& etcd::operator<<(std::ostream& os,
|
||||||
|
const etcd::Event::EventType& value) {
|
||||||
|
switch (value) {
|
||||||
|
case etcd::Event::EventType::PUT:
|
||||||
|
os << "PUT";
|
||||||
|
break;
|
||||||
|
case etcd::Event::EventType::DELETE_:
|
||||||
|
os << "DELETE";
|
||||||
|
break;
|
||||||
|
case etcd::Event::EventType::INVALID:
|
||||||
|
os << "INVALID";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& etcd::operator<<(std::ostream& os, const etcd::Event& event) {
|
||||||
|
os << "Event type: " << event.event_type();
|
||||||
|
if (event.has_kv()) {
|
||||||
|
os << ", KV: " << event.kv();
|
||||||
|
}
|
||||||
|
if (event.has_prev_kv()) {
|
||||||
|
os << ", Prev KV: " << event.prev_kv();
|
||||||
|
}
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,15 @@
|
||||||
#include <grpc/support/log.h>
|
#include <grpc/support/log.h>
|
||||||
#include <grpcpp/support/status.h>
|
#include <grpcpp/support/status.h>
|
||||||
#include "etcd/v3/action_constants.hpp"
|
#include "etcd/v3/action_constants.hpp"
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#ifndef GPR_ASSERT
|
||||||
|
#define GPR_ASSERT(x) \
|
||||||
|
if (!(x)) { \
|
||||||
|
fprintf(stderr, "%s:%d assert failed\n", __FILE__, __LINE__); \
|
||||||
|
abort(); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
etcdv3::Action::Action(etcdv3::ActionParameters const& params) {
|
etcdv3::Action::Action(etcdv3::ActionParameters const& params) {
|
||||||
parameters = params;
|
parameters = params;
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,43 @@ void etcdv3::AsyncLeaseKeepAliveResponse::ParseResponse(
|
||||||
value.set_ttl(resp.ttl());
|
value.set_ttl(resp.ttl());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void etcdv3::AsyncMemberAddResponse::ParseResponse(MemberAddResponse& resp) {
|
||||||
|
index = resp.header().revision();
|
||||||
|
std::string member_type = "Member";
|
||||||
|
if (resp.member().islearner()) {
|
||||||
|
member_type = "Learner";
|
||||||
|
}
|
||||||
|
std::cout << "Member (" << resp.member().id() << ")"
|
||||||
|
<< " Added to the etcd cluster as " << member_type << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void etcdv3::AsyncMemberListResponse::ParseResponse(MemberListResponse& resp) {
|
||||||
|
index = resp.header().revision();
|
||||||
|
for (auto member : resp.members()) {
|
||||||
|
etcdv3::Member m;
|
||||||
|
m.set_id(member.id());
|
||||||
|
m.set_name(member.name());
|
||||||
|
|
||||||
|
std::vector<std::string> clientUrlsVec, peerUrlsVec;
|
||||||
|
for (const auto& clientUrl : member.clienturls()) {
|
||||||
|
clientUrlsVec.push_back(clientUrl);
|
||||||
|
}
|
||||||
|
for (const auto& peerUrl : member.peerurls()) {
|
||||||
|
peerUrlsVec.push_back(peerUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
m.set_clientURLs(clientUrlsVec);
|
||||||
|
m.set_peerURLs(peerUrlsVec);
|
||||||
|
|
||||||
|
members.push_back(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void etcdv3::AsyncMemberRemoveResponse::ParseResponse(
|
||||||
|
MemberRemoveResponse& resp) {
|
||||||
|
index = resp.header().revision();
|
||||||
|
}
|
||||||
|
|
||||||
void etcdv3::AsyncLeaseLeasesResponse::ParseResponse(
|
void etcdv3::AsyncLeaseLeasesResponse::ParseResponse(
|
||||||
LeaseLeasesResponse& resp) {
|
LeaseLeasesResponse& resp) {
|
||||||
index = resp.header().revision();
|
index = resp.header().revision();
|
||||||
|
|
@ -667,6 +704,81 @@ etcdv3::AsyncLeaseKeepAliveAction::mutable_parameters() {
|
||||||
return this->parameters;
|
return this->parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
etcdv3::AsyncAddMemberAction::AsyncAddMemberAction(
|
||||||
|
etcdv3::ActionParameters&& params)
|
||||||
|
: etcdv3::Action(std::move(params)) {
|
||||||
|
MemberAddRequest add_member_request;
|
||||||
|
|
||||||
|
for (const auto& url : parameters.peer_urls) {
|
||||||
|
add_member_request.add_peerurls(url);
|
||||||
|
}
|
||||||
|
add_member_request.set_islearner(parameters.is_learner);
|
||||||
|
response_reader = parameters.cluster_stub->AsyncMemberAdd(
|
||||||
|
&context, add_member_request, &cq_);
|
||||||
|
response_reader->Finish(&reply, &status, (void*) this);
|
||||||
|
}
|
||||||
|
|
||||||
|
etcdv3::AsyncMemberAddResponse etcdv3::AsyncAddMemberAction::ParseResponse() {
|
||||||
|
AsyncMemberAddResponse add_member_resp;
|
||||||
|
add_member_resp.set_action(etcdv3::ADDMEMBER);
|
||||||
|
|
||||||
|
if (!status.ok()) {
|
||||||
|
add_member_resp.set_error_code(status.error_code());
|
||||||
|
add_member_resp.set_error_message(status.error_message());
|
||||||
|
} else {
|
||||||
|
add_member_resp.ParseResponse(reply);
|
||||||
|
}
|
||||||
|
return add_member_resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
etcdv3::AsyncListMemberAction::AsyncListMemberAction(
|
||||||
|
etcdv3::ActionParameters&& params)
|
||||||
|
: etcdv3::Action(std::move(params)) {
|
||||||
|
MemberListRequest member_list_request;
|
||||||
|
|
||||||
|
response_reader = parameters.cluster_stub->AsyncMemberList(
|
||||||
|
&context, member_list_request, &cq_);
|
||||||
|
response_reader->Finish(&reply, &status, (void*) this);
|
||||||
|
}
|
||||||
|
|
||||||
|
etcdv3::AsyncMemberListResponse etcdv3::AsyncListMemberAction::ParseResponse() {
|
||||||
|
AsyncMemberListResponse list_member_resp;
|
||||||
|
list_member_resp.set_action(etcdv3::LISTMEMBER);
|
||||||
|
|
||||||
|
if (!status.ok()) {
|
||||||
|
list_member_resp.set_error_code(status.error_code());
|
||||||
|
list_member_resp.set_error_message(status.error_message());
|
||||||
|
} else {
|
||||||
|
list_member_resp.ParseResponse(reply);
|
||||||
|
}
|
||||||
|
return list_member_resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
etcdv3::AsyncRemoveMemberAction::AsyncRemoveMemberAction(
|
||||||
|
etcdv3::ActionParameters&& params)
|
||||||
|
: etcdv3::Action(std::move(params)) {
|
||||||
|
MemberRemoveRequest remove_member_request;
|
||||||
|
|
||||||
|
remove_member_request.set_id(parameters.member_id);
|
||||||
|
response_reader = parameters.cluster_stub->AsyncMemberRemove(
|
||||||
|
&context, remove_member_request, &cq_);
|
||||||
|
response_reader->Finish(&reply, &status, (void*) this);
|
||||||
|
}
|
||||||
|
|
||||||
|
etcdv3::AsyncMemberRemoveResponse
|
||||||
|
etcdv3::AsyncRemoveMemberAction::ParseResponse() {
|
||||||
|
AsyncMemberRemoveResponse remove_member_resp;
|
||||||
|
remove_member_resp.set_action(etcdv3::REMOVEMEMBER);
|
||||||
|
|
||||||
|
if (!status.ok()) {
|
||||||
|
remove_member_resp.set_error_code(status.error_code());
|
||||||
|
remove_member_resp.set_error_message(status.error_message());
|
||||||
|
} else {
|
||||||
|
remove_member_resp.ParseResponse(reply);
|
||||||
|
}
|
||||||
|
return remove_member_resp;
|
||||||
|
}
|
||||||
|
|
||||||
etcdv3::AsyncLeaseLeasesAction::AsyncLeaseLeasesAction(
|
etcdv3::AsyncLeaseLeasesAction::AsyncLeaseLeasesAction(
|
||||||
etcdv3::ActionParameters&& params)
|
etcdv3::ActionParameters&& params)
|
||||||
: etcdv3::Action(std::move(params)) {
|
: etcdv3::Action(std::move(params)) {
|
||||||
|
|
@ -994,9 +1106,9 @@ etcdv3::AsyncSetAction::AsyncSetAction(etcdv3::ActionParameters&& params,
|
||||||
// backwards compatibility
|
// backwards compatibility
|
||||||
txn.add_success_range(parameters.key);
|
txn.add_success_range(parameters.key);
|
||||||
if (create) {
|
if (create) {
|
||||||
txn.add_failure_put(parameters.key, parameters.value, parameters.lease_id);
|
|
||||||
} else {
|
|
||||||
txn.add_failure_range(parameters.key);
|
txn.add_failure_range(parameters.key);
|
||||||
|
} else {
|
||||||
|
txn.add_failure_put(parameters.key, parameters.value, parameters.lease_id);
|
||||||
}
|
}
|
||||||
response_reader =
|
response_reader =
|
||||||
parameters.kv_stub->AsyncTxn(&context, *txn.txn_request, &cq_);
|
parameters.kv_stub->AsyncTxn(&context, *txn.txn_request, &cq_);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
#include "etcd/v3/Member.hpp"
|
||||||
|
|
||||||
|
etcdv3::Member::Member() {
|
||||||
|
id = 0;
|
||||||
|
name = "";
|
||||||
|
peerURLs = {};
|
||||||
|
clientURLs = {};
|
||||||
|
isLearner = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void etcdv3::Member::set_id(uint64_t const& id) { this->id = id; }
|
||||||
|
|
||||||
|
void etcdv3::Member::set_name(std::string const& name) { this->name = name; }
|
||||||
|
|
||||||
|
void etcdv3::Member::set_peerURLs(std::vector<std::string> const& peerURLs) {
|
||||||
|
this->peerURLs = peerURLs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void etcdv3::Member::set_clientURLs(
|
||||||
|
std::vector<std::string> const& clientURLs) {
|
||||||
|
this->clientURLs = clientURLs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void etcdv3::Member::set_learner(bool isLearner) {
|
||||||
|
this->isLearner = isLearner;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t const& etcdv3::Member::get_id() const { return id; }
|
||||||
|
|
||||||
|
std::string const& etcdv3::Member::get_name() const { return name; }
|
||||||
|
|
||||||
|
std::vector<std::string> const& etcdv3::Member::get_peerURLs() const {
|
||||||
|
return peerURLs;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> const& etcdv3::Member::get_clientURLs() const {
|
||||||
|
return clientURLs;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool etcdv3::Member::get_learner() const { return isLearner; }
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include "etcd/v3/V3Response.hpp"
|
#include "etcd/v3/V3Response.hpp"
|
||||||
|
#include "etcd/v3/Member.hpp"
|
||||||
#include "etcd/v3/action_constants.hpp"
|
#include "etcd/v3/action_constants.hpp"
|
||||||
|
|
||||||
void etcdv3::V3Response::set_error_code(int code) { error_code = code; }
|
void etcdv3::V3Response::set_error_code(int code) { error_code = code; }
|
||||||
|
|
@ -79,3 +80,7 @@ uint64_t etcdv3::V3Response::get_raft_term() const { return this->raft_term; }
|
||||||
std::vector<int64_t> const& etcdv3::V3Response::get_leases() const {
|
std::vector<int64_t> const& etcdv3::V3Response::get_leases() const {
|
||||||
return this->leases;
|
return this->leases;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<etcdv3::Member> const& etcdv3::V3Response::get_members() const {
|
||||||
|
return this->members;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,10 @@ char const* etcdv3::LEASEKEEPALIVE = "leasekeepalive";
|
||||||
char const* etcdv3::LEASETIMETOLIVE = "leasetimetolive";
|
char const* etcdv3::LEASETIMETOLIVE = "leasetimetolive";
|
||||||
char const* etcdv3::LEASELEASES = "leaseleases";
|
char const* etcdv3::LEASELEASES = "leaseleases";
|
||||||
|
|
||||||
|
char const* etcdv3::ADDMEMBER = "addmember";
|
||||||
|
char const* etcdv3::LISTMEMBER = "listmember";
|
||||||
|
char const* etcdv3::REMOVEMEMBER = "removemember";
|
||||||
|
|
||||||
char const* etcdv3::CAMPAIGN_ACTION = "campaign";
|
char const* etcdv3::CAMPAIGN_ACTION = "campaign";
|
||||||
char const* etcdv3::PROCLAIM_ACTION = "preclaim";
|
char const* etcdv3::PROCLAIM_ACTION = "preclaim";
|
||||||
char const* etcdv3::LEADER_ACTION = "leader";
|
char const* etcdv3::LEADER_ACTION = "leader";
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
#include <cmath>
|
||||||
|
#define CATCH_CONFIG_MAIN
|
||||||
|
#include <catch.hpp>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "etcd/Client.hpp"
|
||||||
|
|
||||||
|
static const std::string etcd_url =
|
||||||
|
etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379");
|
||||||
|
|
||||||
|
pid_t new_etcd_pid = 0;
|
||||||
|
|
||||||
|
pid_t start_etcd_server(const std::string& etcd_path,
|
||||||
|
const std::vector<std::string>& args) {
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (pid == -1) {
|
||||||
|
std::cout << "Failed to fork process" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else if (pid == 0) {
|
||||||
|
std::vector<char*> c_args;
|
||||||
|
c_args.push_back(const_cast<char*>(etcd_path.c_str()));
|
||||||
|
for (const auto& arg : args) {
|
||||||
|
c_args.push_back(const_cast<char*>(arg.c_str()));
|
||||||
|
}
|
||||||
|
c_args.push_back(nullptr);
|
||||||
|
|
||||||
|
if (execvp(etcd_path.c_str(), c_args.data()) == -1) {
|
||||||
|
std::cout << "Failed to exec etcd process: " << std::strerror(errno)
|
||||||
|
<< std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("add member") {
|
||||||
|
etcd::Client etcd(etcd_url);
|
||||||
|
etcd::Response res = etcd.list_member().get();
|
||||||
|
REQUIRE(res.is_ok());
|
||||||
|
CHECK(1 == res.members().size());
|
||||||
|
|
||||||
|
std::string member_name = res.members()[0].get_name();
|
||||||
|
std::string prev_peer_urls = res.members()[0].get_peerURLs()[0];
|
||||||
|
|
||||||
|
// Add a new member
|
||||||
|
std::string peer_urls = "http://127.0.0.1:33691";
|
||||||
|
std::string client_urls = "http://127.0.0.1:33690";
|
||||||
|
bool is_learner = false;
|
||||||
|
res = etcd.add_member(peer_urls, is_learner).get();
|
||||||
|
REQUIRE(res.is_ok());
|
||||||
|
|
||||||
|
// Create the directory for the new etcd server
|
||||||
|
std::string cmd = "mkdir -p /tmp/new_etcd_member";
|
||||||
|
system(cmd.c_str());
|
||||||
|
|
||||||
|
// Start a new etcd server
|
||||||
|
std::vector<std::string> args = {
|
||||||
|
"--name",
|
||||||
|
"new_etcd_member",
|
||||||
|
"--initial-advertise-peer-urls",
|
||||||
|
peer_urls,
|
||||||
|
"--listen-peer-urls",
|
||||||
|
peer_urls,
|
||||||
|
"--initial-cluster",
|
||||||
|
member_name + "=" + prev_peer_urls + ",new_etcd_member=" + peer_urls,
|
||||||
|
"--initial-cluster-state",
|
||||||
|
"existing",
|
||||||
|
"--listen-client-urls",
|
||||||
|
client_urls,
|
||||||
|
"--advertise-client-urls",
|
||||||
|
client_urls,
|
||||||
|
"--data-dir",
|
||||||
|
"/tmp/new_etcd_member",
|
||||||
|
};
|
||||||
|
|
||||||
|
new_etcd_pid = start_etcd_server("/usr/local/bin/etcd", args);
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(30));
|
||||||
|
|
||||||
|
// Check the member's number
|
||||||
|
{
|
||||||
|
etcd::Response res = etcd.list_member().get();
|
||||||
|
REQUIRE(res.is_ok());
|
||||||
|
CHECK(2 == res.members().size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("member remove") {
|
||||||
|
etcd::Client etcd(etcd_url);
|
||||||
|
etcd::Response res = etcd.list_member().get();
|
||||||
|
REQUIRE(res.is_ok());
|
||||||
|
CHECK(2 == res.members().size());
|
||||||
|
|
||||||
|
uint64_t member_id = 0;
|
||||||
|
for (const auto& member : res.members()) {
|
||||||
|
if (member.get_name() == "new_etcd_member") {
|
||||||
|
member_id = member.get_id();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(member_id != 0);
|
||||||
|
// Remove the new member
|
||||||
|
res = etcd.remove_member(member_id).get();
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(30));
|
||||||
|
|
||||||
|
// Check whether the new etcd server is quited
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
pid_t wpid = waitpid(new_etcd_pid, &status, WNOHANG);
|
||||||
|
REQUIRE(wpid == new_etcd_pid);
|
||||||
|
REQUIRE(WIFEXITED(status));
|
||||||
|
REQUIRE(WEXITSTATUS(status) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the directory for the new etcd server
|
||||||
|
std::string cmd = "rm -rf /tmp/new_etcd_member";
|
||||||
|
system(cmd.c_str());
|
||||||
|
|
||||||
|
// Check the member's number
|
||||||
|
{
|
||||||
|
etcd::Response res = etcd.list_member().get();
|
||||||
|
REQUIRE(res.is_ok());
|
||||||
|
CHECK(1 == res.members().size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,9 @@ static const std::string etcd_v4_url =
|
||||||
etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379");
|
etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379");
|
||||||
static const std::string etcd_v6_url =
|
static const std::string etcd_v6_url =
|
||||||
etcdv3::detail::resolve_etcd_endpoints("http://::1:2379");
|
etcdv3::detail::resolve_etcd_endpoints("http://::1:2379");
|
||||||
|
// http://[ipv6]:port url
|
||||||
|
static const std::string etcd_ipv6_url =
|
||||||
|
etcdv3::detail::resolve_etcd_endpoints("http://[::1]:2379");
|
||||||
|
|
||||||
TEST_CASE("test ipv4 connection") {
|
TEST_CASE("test ipv4 connection") {
|
||||||
std::cout << "ipv4 endpoints: " << etcd_v4_url << std::endl;
|
std::cout << "ipv4 endpoints: " << etcd_v4_url << std::endl;
|
||||||
|
|
@ -20,4 +23,8 @@ TEST_CASE("test ipv6 connection") {
|
||||||
std::cout << "ipv6 endpoints: " << etcd_v6_url << std::endl;
|
std::cout << "ipv6 endpoints: " << etcd_v6_url << std::endl;
|
||||||
etcd::Client etcd(etcd_v6_url);
|
etcd::Client etcd(etcd_v6_url);
|
||||||
REQUIRE(etcd.head().get().is_ok());
|
REQUIRE(etcd.head().get().is_ok());
|
||||||
|
|
||||||
|
std::cout << "ipv6 endpoints: " << etcd_ipv6_url << std::endl;
|
||||||
|
etcd::Client etcd1(etcd_ipv6_url);
|
||||||
|
REQUIRE(etcd1.head().get().is_ok());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ TEST_CASE("sync operations") {
|
||||||
// add
|
// add
|
||||||
CHECK(0 == etcd.add("/test/key1", "42").error_code());
|
CHECK(0 == etcd.add("/test/key1", "42").error_code());
|
||||||
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS ==
|
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS ==
|
||||||
etcd.add("/test/key1", "42").error_code()); // Key already exists
|
etcd.add("/test/key1", "41").error_code()); // Key already exists
|
||||||
CHECK("42" == etcd.get("/test/key1").value().as_string());
|
CHECK("42" == etcd.get("/test/key1").value().as_string());
|
||||||
|
|
||||||
// modify
|
// modify
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,41 @@ TEST_CASE("create two watcher") {
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("using two watcher") {
|
||||||
|
etcd::SyncClient etcd(etcd_url);
|
||||||
|
|
||||||
|
int watched1 = 0;
|
||||||
|
int watched2 = 0;
|
||||||
|
|
||||||
|
etcd::Watcher w1(
|
||||||
|
etcd, "/test/def",
|
||||||
|
[&](etcd::Response const& resp) {
|
||||||
|
std::cout << "w1 called: " << resp.events().at(0).event_type() << " on "
|
||||||
|
<< resp.events().at(0).kv().key() << std::endl;
|
||||||
|
++watched1;
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
etcd::Watcher w2(
|
||||||
|
etcd, "/test",
|
||||||
|
[&](etcd::Response const& resp) {
|
||||||
|
std::cout << "w2 called: " << resp.events().at(0).event_type() << " on "
|
||||||
|
<< resp.events().at(0).kv().key() << std::endl;
|
||||||
|
++watched2;
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||||
|
|
||||||
|
etcd.put("/test/def/xxx", "42");
|
||||||
|
etcd.put("/test/abc", "42");
|
||||||
|
etcd.rm("/test/def/xxx");
|
||||||
|
etcd.rm("/test/abc");
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||||
|
CHECK(2 == watched1);
|
||||||
|
CHECK(4 == watched2);
|
||||||
|
}
|
||||||
|
|
||||||
// TEST_CASE("request cancellation")
|
// TEST_CASE("request cancellation")
|
||||||
// {
|
// {
|
||||||
// etcd::Client etcd(etcd_url);
|
// etcd::Client etcd(etcd_url);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue