Skip to content

Commit 5cd3b60

Browse files
authored
Add cluster APIs. (etcdv3#8)
Add cluster APIs.
1 parent 5abece8 commit 5cd3b60

File tree

5 files changed

+581
-8
lines changed

5 files changed

+581
-8
lines changed

build.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use tonic_build;
2-
31
fn main() {
42
let proto_root = "proto";
53
println!("cargo:rerun-if-changed={}", proto_root);

examples/cluster.rs

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//! Cluster example.
2+
3+
use etcd_client::*;
4+
5+
#[tokio::main]
6+
async fn main() -> Result<(), Error> {
7+
let mut client = Client::connect(["localhost:2379"], None).await?;
8+
9+
// add a member
10+
let resp = client.member_add(["localhost:2520"], None).await?;
11+
println!("add one member with cluster is as {:?}", resp.member());
12+
let member = resp.member();
13+
let id = member.unwrap().id();
14+
15+
// promote a learner
16+
let resp = client.member_promote(id).await?;
17+
println!("member list with current cluster is {:?}", resp.members());
18+
19+
// list all members
20+
let resp = client.member_list().await?;
21+
let member_list = resp.members();
22+
println!(
23+
"member id is {:?}, url is {:?}",
24+
member_list[0].id(),
25+
member_list[0].peer_urls()
26+
);
27+
println!(
28+
"member id is {:?}, url is {:?}",
29+
member_list[1].id(),
30+
member_list[1].peer_urls()
31+
);
32+
println!(
33+
"member id is {:?}, url is {:?}",
34+
member_list[2].id(),
35+
member_list[2].peer_urls()
36+
);
37+
38+
// remove the added member
39+
let _resp = client.member_remove(id).await?;
40+
println!("remove a member with id {:?}", id);
41+
Ok(())
42+
}

src/client.rs

+86-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ use crate::rpc::auth::{
99
UserAddResponse, UserChangePasswordResponse, UserDeleteResponse, UserGetResponse,
1010
UserGrantRoleResponse, UserListResponse, UserRevokeRoleResponse,
1111
};
12+
use crate::rpc::cluster::{
13+
ClusterClient, MemberAddOptions, MemberAddResponse, MemberListResponse, MemberPromoteResponse,
14+
MemberRemoveResponse, MemberUpdateResponse,
15+
};
1216
use crate::rpc::kv::{
1317
CompactionOptions, CompactionResponse, DeleteOptions, DeleteResponse, GetOptions, GetResponse,
1418
KvClient, PutOptions, PutResponse, Txn, TxnResponse,
@@ -27,6 +31,8 @@ use tonic::metadata::{Ascii, MetadataValue};
2731
use tonic::transport::Channel;
2832
use tonic::Interceptor;
2933

34+
const HTTP_PREFIX: &str = "http://";
35+
3036
/// Asynchronous `etcd` client using v3 API.
3137
pub struct Client {
3238
kv: KvClient,
@@ -35,6 +41,7 @@ pub struct Client {
3541
lock: LockClient,
3642
auth: AuthClient,
3743
maintenance: MaintenanceClient,
44+
cluster: ClusterClient,
3845
}
3946

4047
impl Client {
@@ -43,8 +50,6 @@ impl Client {
4350
endpoints: S,
4451
options: Option<ConnectOptions>,
4552
) -> Result<Self> {
46-
const HTTP_PREFIX: &str = "http://";
47-
4853
let endpoints = {
4954
let mut eps = Vec::new();
5055
for e in endpoints.as_ref() {
@@ -90,6 +95,7 @@ impl Client {
9095
let lease = LeaseClient::new(channel.clone(), interceptor.clone());
9196
let lock = LockClient::new(channel.clone(), interceptor.clone());
9297
let auth = AuthClient::new(channel.clone(), interceptor.clone());
98+
let cluster = ClusterClient::new(channel.clone(), interceptor.clone());
9399
let maintenance = MaintenanceClient::new(channel, interceptor);
94100

95101
Ok(Self {
@@ -99,6 +105,7 @@ impl Client {
99105
lock,
100106
auth,
101107
maintenance,
108+
cluster,
102109
})
103110
}
104111

@@ -397,6 +404,55 @@ impl Client {
397404
pub async fn snapshot(&mut self) -> Result<SnapshotStreaming> {
398405
self.maintenance.snapshot().await
399406
}
407+
408+
/// Adds current connected server as a member.
409+
#[inline]
410+
pub async fn member_add<E: AsRef<str>, S: AsRef<[E]>>(
411+
&mut self,
412+
urls: S,
413+
options: Option<MemberAddOptions>,
414+
) -> Result<MemberAddResponse> {
415+
let mut eps = Vec::new();
416+
for e in urls.as_ref() {
417+
let e = e.as_ref();
418+
let url = if e.starts_with(HTTP_PREFIX) {
419+
e.to_string()
420+
} else {
421+
HTTP_PREFIX.to_owned() + e
422+
};
423+
eps.push(url);
424+
}
425+
426+
self.cluster.member_add(eps, options).await
427+
}
428+
429+
/// Remove a member.
430+
#[inline]
431+
pub async fn member_remove(&mut self, id: u64) -> Result<MemberRemoveResponse> {
432+
self.cluster.member_remove(id).await
433+
}
434+
435+
/// Updates the member.
436+
#[inline]
437+
pub async fn member_update(
438+
&mut self,
439+
id: u64,
440+
url: impl Into<Vec<String>>,
441+
) -> Result<MemberUpdateResponse> {
442+
self.cluster.member_update(id, url).await
443+
}
444+
445+
/// Promotes the member.
446+
#[inline]
447+
pub async fn member_promote(&mut self, id: u64) -> Result<MemberPromoteResponse> {
448+
self.cluster.member_promote(id).await
449+
}
450+
451+
/// Lists members.
452+
#[inline]
453+
pub async fn member_list(&mut self) -> Result<MemberListResponse> {
454+
self.cluster.member_list().await
455+
}
400456
}
401457

402458
/// Options for `Connect` operation.
@@ -773,8 +829,8 @@ mod tests {
773829
Ok(())
774830
}
775831

776-
#[tokio::test]
777832
#[ignore]
833+
#[tokio::test]
778834
async fn test_auth() -> Result<()> {
779835
let mut client = get_client().await?;
780836
client.auth_enable().await?;
@@ -1084,4 +1140,31 @@ mod tests {
10841140
}
10851141
Ok(())
10861142
}
1143+
1144+
#[ignore]
1145+
#[tokio::test]
1146+
async fn test_cluster() -> Result<()> {
1147+
let node1 = "localhost:2520";
1148+
let node2 = "localhost:2530";
1149+
let node3 = "localhost:2540";
1150+
let mut client = get_client().await?;
1151+
let resp = client
1152+
.member_add([node1], Some(MemberAddOptions::new().with_is_learner()))
1153+
.await?;
1154+
let id1 = resp.member().unwrap().id();
1155+
1156+
let resp = client.member_add([node2], None).await?;
1157+
let id2 = resp.member().unwrap().id();
1158+
let resp = client.member_add([node3], None).await?;
1159+
let id3 = resp.member().unwrap().id();
1160+
1161+
let resp = client.member_list().await?;
1162+
let members: Vec<_> = resp.members().iter().map(|member| member.id()).collect();
1163+
assert!(members.contains(&id1));
1164+
assert!(members.contains(&id2));
1165+
assert!(members.contains(&id3));
1166+
1167+
client.member_remove(id1).await?;
1168+
Ok(())
1169+
}
10871170
}

src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ pub use crate::rpc::auth::{
1313
UserChangePasswordResponse, UserDeleteResponse, UserGetResponse, UserGrantRoleResponse,
1414
UserListResponse, UserRevokeRoleResponse,
1515
};
16+
pub use crate::rpc::cluster::{
17+
Member, MemberAddOptions, MemberAddResponse, MemberListResponse, MemberPromoteResponse,
18+
MemberRemoveResponse, MemberUpdateResponse,
19+
};
1620
pub use crate::rpc::kv::{
1721
CompactionOptions, CompactionResponse, Compare, CompareOp, DeleteOptions, DeleteResponse,
1822
GetOptions, GetResponse, PutOptions, PutResponse, SortOrder, SortTarget, Txn, TxnOp,

0 commit comments

Comments
 (0)