diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 8079393..d0d9990 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -166,9 +166,6 @@ jobs: echo "Run the etcd test ........................." ./build/bin/EtcdTest - echo "Run the etcd lock test ........................." - ./build/bin/LockTest - echo "Run the etcd memory leak test ........................." ./build/bin/MemLeakTest @@ -178,11 +175,63 @@ jobs: echo "Run the etcd election test ........................." ./build/bin/ElectionTest - killall -TERM etcd + killall -TERM etcd || true sleep 5 + - name: Lock Test + if: false + 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 + + echo "Run the etcd lock test ........................." + ./build/bin/LockTest + + killall -TERM etcd || true + sleep 5 + + - name: Lock Tests with Debug + if: true + uses: sighingnow/action-tmate@master + with: + script-to-run: | + killall -TERM etcd || true + sleep 5 + + # enable coredump for debugging + ulimit -c unlimited + + 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 + + echo "Run the etcd lock test ........................." + ./build/bin/LockTest + + killall -TERM etcd || true + sleep 5 + - name: Authentication 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 @@ -219,11 +268,14 @@ jobs: /usr/local/bin/etcdctl auth disable --user="root" --password="root" || true fi - killall -TERM etcd + killall -TERM etcd || true sleep 5 - name: Transport Security and Authentication 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 diff --git a/.github/workflows/centos-latest.yml b/.github/workflows/centos-latest.yml index d32df19..068a03b 100644 --- a/.github/workflows/centos-latest.yml +++ b/.github/workflows/centos-latest.yml @@ -80,9 +80,11 @@ jobs: - name: Install cpprestsdk run: | + export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib:/usr/local/lib64 + mkdir -p build cd build - git clone https://github.com/microsoft/cpprestsdk.git + git clone https://github.com/microsoft/cpprestsdk.git --depth=1 mkdir -p cpprestsdk/build cd cpprestsdk/build cmake .. -DCMAKE_BUILD_TYPE=Debug \ diff --git a/README.md b/README.md index ab59383..0c09f4d 100644 --- a/README.md +++ b/README.md @@ -240,8 +240,8 @@ printf 'root\nroot\n' | /usr/local/bin/etcdctl user add root Etcd [transport security](https://etcd.io/docs/v3.4.0/op-guide/security/) and certificate based authentication have been supported as well. The `Client::Client` could accept arguments `ca` , -`cert` and `key` for CA cert, cert and private key files for the SSL/TLS transport and authentication. -Note that the later arguments `cert` and `key` could be empty strings or omitted if you just need +`cert` and `privkey` for CA cert, cert and private key files for the SSL/TLS transport and authentication. +Note that the later arguments `cert` and `privkey` could be empty strings or omitted if you just need secure transport and don't enable certificate-based client authentication (using the `--client-cert-auth` arguments when launching etcd server). diff --git a/etcd/Client.hpp b/etcd/Client.hpp index dc8a841..898fa17 100644 --- a/etcd/Client.hpp +++ b/etcd/Client.hpp @@ -169,32 +169,32 @@ namespace etcd * * @param etcd_url is the url of the etcd server to connect to, like "http://127.0.0.1:2379", * or multiple url, seperated by ',' or ';'. - * @param ca root CA file for SSL/TLS connection. - * @param cert cert chain file for SSL/TLS authentication, could be empty string. - * @param key private key file for SSL/TLS authentication, could be empty string. + * @param ca root CA file for SSL/TLS connection. + * @param cert cert chain file for SSL/TLS authentication, could be empty string. + * @param privkey private key file for SSL/TLS authentication, could be empty string. * @param load_balancer is the load balance strategy, can be one of round_robin/pick_first/grpclb/xds. */ Client(std::string const & etcd_url, std::string const & ca, std::string const & cert, - std::string const & key, + std::string const & privkey, std::string const & target_name_override, - std::string const & load_balancer); + std::string const & load_balancer = "round_robin"); /** * Constructs an etcd client object. * * @param etcd_url is the url of the etcd server to connect to, like "http://127.0.0.1:2379", * or multiple url, seperated by ',' or ';'. - * @param ca root CA file for SSL/TLS connection. - * @param cert cert chain file for SSL/TLS authentication, could be empty string. - * @param key private key file for SSL/TLS authentication, could be empty string. + * @param ca root CA file for SSL/TLS connection. + * @param cert cert chain file for SSL/TLS authentication, could be empty string. + * @param privkey private key file for SSL/TLS authentication, could be empty string. * @param arguments user provided grpc channel arguments. */ Client(std::string const & etcd_url, std::string const & ca, std::string const & cert, - std::string const & key, + std::string const & privkey, std::string const & target_name_override, #if defined(WITH_GRPC_CHANNEL_CLASS) grpc::ChannelArguments const & arguments @@ -208,9 +208,9 @@ namespace etcd * * @param etcd_url is the url of the etcd server to connect to, like "http://127.0.0.1:2379", * or multiple url, seperated by ',' or ';'. - * @param ca root CA file for SSL/TLS connection. - * @param cert cert chain file for SSL/TLS authentication, could be empty string. - * @param key private key file for SSL/TLS authentication, could be empty string. + * @param ca root CA file for SSL/TLS connection. + * @param cert cert chain file for SSL/TLS authentication, could be empty string. + * @param privkey private key file for SSL/TLS authentication, could be empty string. * @param target_name_override Override the target host name if you want to pass multiple address * for load balancing with SSL, and there's no DNS. The @target_name_override@ must exist in the * SANS of your SSL certificate. @@ -219,7 +219,7 @@ namespace etcd static Client *WithSSL(std::string const & etcd_url, std::string const & ca, std::string const & cert = "", - std::string const & key = "", + std::string const & privkey = "", std::string const & target_name_override = "", std::string const & load_balancer = "round_robin"); @@ -228,9 +228,9 @@ namespace etcd * * @param etcd_url is the url of the etcd server to connect to, like "http://127.0.0.1:2379", * or multiple url, seperated by ',' or ';'. - * @param ca root CA file for SSL/TLS connection. - * @param cert cert chain file for SSL/TLS authentication, could be empty string. - * @param key private key file for SSL/TLS authentication, could be empty string. + * @param ca root CA file for SSL/TLS connection. + * @param cert cert chain file for SSL/TLS authentication, could be empty string. + * @param privkey private key file for SSL/TLS authentication, could be empty string. * @param target_name_override Override the target host name if you want to pass multiple address * for load balancing with SSL, and there's no DNS. The @target_name_override@ must exist in the * SANS of your SSL certificate. @@ -244,7 +244,7 @@ namespace etcd #endif std::string const & ca, std::string const & cert = "", - std::string const & key = "", + std::string const & privkey = "", std::string const & target_name_override = ""); ~Client(); diff --git a/etcd/KeepAlive.hpp b/etcd/KeepAlive.hpp index a65ecdb..36b586f 100644 --- a/etcd/KeepAlive.hpp +++ b/etcd/KeepAlive.hpp @@ -55,6 +55,13 @@ namespace etcd std::function const &handler, int ttl, int64_t lease_id = 0, int const auth_token_ttl = 300); + KeepAlive(std::string const & address, + std::string const & ca, + std::string const & cert, + std::string const & privkey, + std::function const &handler, + int ttl, int64_t lease_id = 0, + std::string const & target_name_override = ""); KeepAlive(KeepAlive const &) = delete; KeepAlive(KeepAlive &&) = delete; diff --git a/etcd/SyncClient.hpp b/etcd/SyncClient.hpp index 96770e7..aaa8840 100644 --- a/etcd/SyncClient.hpp +++ b/etcd/SyncClient.hpp @@ -224,32 +224,32 @@ namespace etcd * * @param etcd_url is the url of the etcd server to connect to, like "http://127.0.0.1:2379", * or multiple url, seperated by ',' or ';'. - * @param ca root CA file for SSL/TLS connection. - * @param cert cert chain file for SSL/TLS authentication, could be empty string. - * @param key private key file for SSL/TLS authentication, could be empty string. + * @param ca root CA file for SSL/TLS connection. + * @param cert cert chain file for SSL/TLS authentication, could be empty string. + * @param privkey private key file for SSL/TLS authentication, could be empty string. * @param load_balancer is the load balance strategy, can be one of round_robin/pick_first/grpclb/xds. */ SyncClient(std::string const & etcd_url, std::string const & ca, std::string const & cert, - std::string const & key, + std::string const & privkey, std::string const & target_name_override, - std::string const & load_balancer); + std::string const & load_balancer = "round_robin"); /** * Constructs an etcd client object. * * @param etcd_url is the url of the etcd server to connect to, like "http://127.0.0.1:2379", * or multiple url, seperated by ',' or ';'. - * @param ca root CA file for SSL/TLS connection. - * @param cert cert chain file for SSL/TLS authentication, could be empty string. - * @param key private key file for SSL/TLS authentication, could be empty string. + * @param ca root CA file for SSL/TLS connection. + * @param cert cert chain file for SSL/TLS authentication, could be empty string. + * @param privkey private key file for SSL/TLS authentication, could be empty string. * @param arguments user provided grpc channel arguments. */ SyncClient(std::string const & etcd_url, std::string const & ca, std::string const & cert, - std::string const & key, + std::string const & privkey, std::string const & target_name_override, #if defined(WITH_GRPC_CHANNEL_CLASS) grpc::ChannelArguments const & arguments @@ -264,9 +264,9 @@ namespace etcd * * @param etcd_url is the url of the etcd server to connect to, like "http://127.0.0.1:2379", * or multiple url, seperated by ',' or ';'. - * @param ca root CA file for SSL/TLS connection. - * @param cert cert chain file for SSL/TLS authentication, could be empty string. - * @param key private key file for SSL/TLS authentication, could be empty string. + * @param ca root CA file for SSL/TLS connection. + * @param cert cert chain file for SSL/TLS authentication, could be empty string. + * @param privkey private key file for SSL/TLS authentication, could be empty string. * @param target_name_override Override the target host name if you want to pass multiple address * for load balancing with SSL, and there's no DNS. The @target_name_override@ must exist in the * SANS of your SSL certificate. @@ -275,7 +275,7 @@ namespace etcd static SyncClient *WithSSL(std::string const & etcd_url, std::string const & ca, std::string const & cert = "", - std::string const & key = "", + std::string const & privkey = "", std::string const & target_name_override = "", std::string const & load_balancer = "round_robin"); @@ -284,9 +284,9 @@ namespace etcd * * @param etcd_url is the url of the etcd server to connect to, like "http://127.0.0.1:2379", * or multiple url, seperated by ',' or ';'. - * @param ca root CA file for SSL/TLS connection. - * @param cert cert chain file for SSL/TLS authentication, could be empty string. - * @param key private key file for SSL/TLS authentication, could be empty string. + * @param ca root CA file for SSL/TLS connection. + * @param cert cert chain file for SSL/TLS authentication, could be empty string. + * @param privkey private key file for SSL/TLS authentication, could be empty string. * @param target_name_override Override the target host name if you want to pass multiple address * for load balancing with SSL, and there's no DNS. The @target_name_override@ must exist in the * SANS of your SSL certificate. @@ -300,7 +300,7 @@ namespace etcd #endif std::string const & ca, std::string const & cert = "", - std::string const & key = "", + std::string const & privkey = "", std::string const & target_name_override = ""); ~SyncClient(); diff --git a/etcd/Watcher.hpp b/etcd/Watcher.hpp index afc6f5f..4d81d53 100644 --- a/etcd/Watcher.hpp +++ b/etcd/Watcher.hpp @@ -67,6 +67,20 @@ namespace etcd std::string const & key, std::string const &range_end, int64_t fromIndex, std::function callback, int const auth_token_ttl = 300); + Watcher(std::string const & address, + std::string const & ca, + std::string const & cert, + std::string const & privkey, + std::string const & key, int64_t fromIndex, + std::function callback, bool recursive=false, + std::string const & target_name_override = ""); + Watcher(std::string const & address, + std::string const & ca, + std::string const & cert, + std::string const & privkey, + std::string const & key, std::string const &range_end, int64_t fromIndex, + std::function callback, + std::string const & target_name_override = ""); Watcher(Watcher const &) = delete; Watcher(Watcher &&) = delete; diff --git a/src/Client.cpp b/src/Client.cpp index fa19412..001fd3f 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -157,18 +157,18 @@ etcd::Client *etcd::Client::WithUser(std::string const & etcd_url, etcd::Client::Client(std::string const & address, std::string const & ca, std::string const & cert, - std::string const & key, + std::string const & privkey, std::string const & target_name_override, std::string const & load_balancer) { this->own_client = true; - this->client = new SyncClient(address, ca, cert, key, target_name_override, load_balancer); + this->client = new SyncClient(address, ca, cert, privkey, target_name_override, load_balancer); } etcd::Client::Client(std::string const & address, std::string const & ca, std::string const & cert, - std::string const & key, + std::string const & privkey, std::string const & target_name_override, #if defined(WITH_GRPC_CHANNEL_CLASS) grpc::ChannelArguments const & arguments @@ -179,16 +179,16 @@ etcd::Client::Client(std::string const & address, ) { this->own_client = true; - this->client = new SyncClient(address, ca, cert, key, target_name_override, arguments); + this->client = new SyncClient(address, ca, cert, privkey, target_name_override, arguments); } etcd::Client *etcd::Client::WithSSL(std::string const & etcd_url, std::string const & ca, std::string const & cert, - std::string const & key, + std::string const & privkey, std::string const & target_name_override, std::string const & load_balancer) { - return new etcd::Client(etcd_url, ca, cert, key, target_name_override, load_balancer); + return new etcd::Client(etcd_url, ca, cert, privkey, target_name_override, load_balancer); } etcd::Client *etcd::Client::WithSSL(std::string const & etcd_url, @@ -199,9 +199,9 @@ etcd::Client *etcd::Client::WithSSL(std::string const & etcd_url, #endif std::string const & ca, std::string const & cert, - std::string const & key, + std::string const & privkey, std::string const & target_name_override) { - return new etcd::Client(etcd_url, ca, cert, key, target_name_override, arguments); + return new etcd::Client(etcd_url, ca, cert, privkey, target_name_override, arguments); } etcd::Client::~Client() { diff --git a/src/KeepAlive.cpp b/src/KeepAlive.cpp index 6de6679..0d71cb9 100644 --- a/src/KeepAlive.cpp +++ b/src/KeepAlive.cpp @@ -59,6 +59,16 @@ etcd::KeepAlive::KeepAlive(std::string const & address, KeepAlive(SyncClient(address, username, password, auth_token_ttl), ttl, lease_id) { } +etcd::KeepAlive::KeepAlive(std::string const & address, + std::string const & ca, + std::string const & cert, + std::string const & privkey, + std::function const &handler, + int ttl, int64_t lease_id, + std::string const & target_name_override): + KeepAlive(SyncClient(address, ca, cert, privkey, target_name_override), ttl, lease_id) { +} + etcd::KeepAlive::KeepAlive(SyncClient const &client, std::function const &handler, int ttl, int64_t lease_id): diff --git a/src/SyncClient.cpp b/src/SyncClient.cpp index 68f7505..6dd1000 100644 --- a/src/SyncClient.cpp +++ b/src/SyncClient.cpp @@ -383,7 +383,7 @@ etcd::SyncClient *etcd::SyncClient::WithUser(std::string const & etcd_url, etcd::SyncClient::SyncClient(std::string const & address, std::string const & ca, std::string const & cert, - std::string const & key, + std::string const & privkey, std::string const & target_name_override, std::string const & load_balancer) { @@ -393,7 +393,7 @@ etcd::SyncClient::SyncClient(std::string const & address, grpc_args.SetMaxSendMessageSize(std::numeric_limits::max()); grpc_args.SetMaxReceiveMessageSize(std::numeric_limits::max()); std::shared_ptr creds = grpc::SslCredentials( - etcd::detail::make_ssl_credentials(ca, cert, key)); + etcd::detail::make_ssl_credentials(ca, cert, privkey)); grpc_args.SetLoadBalancingPolicyName(load_balancer); if (!target_name_override.empty()) { grpc_args.SetString(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, target_name_override); @@ -413,7 +413,7 @@ etcd::SyncClient::SyncClient(std::string const & address, etcd::SyncClient::SyncClient(std::string const & address, std::string const & ca, std::string const & cert, - std::string const & key, + std::string const & privkey, std::string const & target_name_override, #if defined(WITH_GRPC_CHANNEL_CLASS) grpc::ChannelArguments const & arguments @@ -429,7 +429,7 @@ etcd::SyncClient::SyncClient(std::string const & address, grpc_args.SetMaxSendMessageSize(std::numeric_limits::max()); grpc_args.SetMaxReceiveMessageSize(std::numeric_limits::max()); std::shared_ptr creds = grpc::SslCredentials( - etcd::detail::make_ssl_credentials(ca, cert, key)); + etcd::detail::make_ssl_credentials(ca, cert, privkey)); if (!target_name_override.empty()) { grpc_args.SetString(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, target_name_override); } @@ -448,10 +448,10 @@ etcd::SyncClient::SyncClient(std::string const & address, etcd::SyncClient *etcd::SyncClient::WithSSL(std::string const & etcd_url, std::string const & ca, std::string const & cert, - std::string const & key, + std::string const & privkey, std::string const & target_name_override, std::string const & load_balancer) { - return new etcd::SyncClient(etcd_url, ca, cert, key, target_name_override, load_balancer); + return new etcd::SyncClient(etcd_url, ca, cert, privkey, target_name_override, load_balancer); } etcd::SyncClient *etcd::SyncClient::WithSSL(std::string const & etcd_url, @@ -462,9 +462,9 @@ etcd::SyncClient *etcd::SyncClient::WithSSL(std::string const & etcd_url, #endif std::string const & ca, std::string const & cert, - std::string const & key, + std::string const & privkey, std::string const & target_name_override) { - return new etcd::SyncClient(etcd_url, ca, cert, key, target_name_override, arguments); + return new etcd::SyncClient(etcd_url, ca, cert, privkey, target_name_override, arguments); } etcd::SyncClient::~SyncClient() { diff --git a/src/Watcher.cpp b/src/Watcher.cpp index 9d9f799..e40abda 100644 --- a/src/Watcher.cpp +++ b/src/Watcher.cpp @@ -94,6 +94,26 @@ etcd::Watcher::Watcher(std::string const & address, Watcher(SyncClient(address, username, password, auth_token_ttl), key, range_end, fromIndex, callback) { } +etcd::Watcher::Watcher(std::string const & address, + std::string const & ca, + std::string const & cert, + std::string const & privkey, + std::string const & key, int64_t fromIndex, + std::function callback, bool recursive, + std::string const & target_name_override): + Watcher(SyncClient(address, ca, cert, privkey, target_name_override), key, fromIndex, callback, recursive) { +} + +etcd::Watcher::Watcher(std::string const & address, + std::string const & ca, + std::string const & cert, + std::string const & privkey, + std::string const & key, std::string const & range_end, int64_t fromIndex, + std::function callback, + std::string const & target_name_override): + Watcher(SyncClient(address, ca, cert, privkey, target_name_override), key, range_end, fromIndex, callback) { +} + etcd::Watcher::~Watcher() { this->Cancel();