Skip to content

Commit

Permalink
feat: implement etcd client
Browse files Browse the repository at this point in the history
Create a new internal_etcd interface witch contains all methods
related to the ETCD client.

Signed-off-by: GridexX <[email protected]>
  • Loading branch information
GridexX committed Aug 23, 2022
1 parent ee4dec7 commit b92d9c1
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 1 deletion.
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion controller/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
etcd-client = "0.9"
actix-web = "4.1.0"
serde = { version = "1.0.139", features = ["derive"] }
tonic = "0.7.2"
proto = { path = "../../proto" }
log = "0.4.0"
tokio = { version = "1.20.0", features = ["rt-multi-thread"] }
tokio = { version = "1.20.0", features = ["rt-multi-thread", "macros"] }
131 changes: 131 additions & 0 deletions controller/lib/src/etcd_client/interface.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
use etcd_client::{Client, DeleteResponse, Error, GetOptions, PutResponse};
use log::{debug, error, info};

pub struct EtcdInterface {
client: Client,
}

impl EtcdInterface {
pub async fn new(address: String) -> Self {
info!("Starting ETCD client on {}", address);
EtcdInterface {
client: Client::connect([address], None).await.unwrap(),
}
}

pub async fn get(&mut self, key: &str) -> Result<String, Error> {
if let Some(kv) = self.client.get(key, None).await?.kvs().first() {
let res = kv.value_str();
info!(
"Retrieving value in ETCD : Key \"{}\" is associated with value \"{}\"",
key,
res.as_ref().unwrap()
);
res.map(|s| s.to_string())
} else {
Err(Error::from(std::io::Error::new(
std::io::ErrorKind::NotFound,
"Key not found",
)))
}
}
pub async fn put(&mut self, key: &str, value: &str) -> Result<PutResponse, Error> {
info!(
"Inserting value in ETCD : Key \"{}\" associated with value \"{}\"",
key, value
);
self.client.put(key, value, None).await
}
pub async fn patch(&mut self, key: &str, value: &str) -> Result<PutResponse, Error> {
match self.get(key).await {
Ok(_) => {
info!(
"Updating value in ETCD : Key \"{}\" associated with new value \"{}\"",
key, value
);
self.client.put(key, value, None).await
}
Err(err) => Err(err),
}
}
pub async fn delete(&mut self, key: &str) -> Result<DeleteResponse, Error> {
if let Some(_) = self.client.get(key, None).await?.kvs().first() {
info!("Deleting value in ETCD : Key \"{}\" ", key);
self.client.delete(key, None).await
} else {
Err(Error::from(std::io::Error::new(
std::io::ErrorKind::NotFound,
"Key not found",
)))
}
}

pub async fn get_all(&mut self) -> Result<Vec<String>, Error> {
info!("Retrieving all keys in ETCD");
let resp = self
.client
.get("", Some(GetOptions::new().with_all_keys()))
.await?;

let mut values: Vec<String> = vec![];
for kv in resp.kvs() {
let value = kv.value_str()?;
values.push(value.to_string())
}
Ok(values)
}
}

#[cfg(test)]
mod tests {

use crate::internal_etcd::interface::EtcdInterface;
use etcd_client::Error;

#[tokio::test]
async fn test_value_insertion() -> Result<(), Error> {
let mut etcd_client = EtcdInterface::new("localhost:2379".to_string()).await;
let _res = etcd_client.put("foo", "bar").await?;
let resp = etcd_client.get("foo").await?;
assert_eq!(resp, "bar");
Ok(())
}

#[tokio::test]
async fn test_value_modification() -> Result<(), Error> {
let mut etcd_client = EtcdInterface::new("localhost:2379".to_string()).await;
etcd_client.put("foo", "bar").await?;
let _res = etcd_client.patch("foo", "baz").await?;
let resp = etcd_client.get("foo").await?;
assert_eq!(resp, "baz");
Ok(())
}
#[tokio::test]
async fn test_value_deletion() -> Result<(), Error> {
let mut etcd_client = EtcdInterface::new("localhost:2379".to_string()).await;
let _res = etcd_client.put("foo", "bar").await?;
let _res = etcd_client.delete("foo").await?;
let err = etcd_client.get("foo").await;
assert!(err.is_err());
Ok(())
}
#[tokio::test]
async fn test_value_deletion_doesnt_exists() -> Result<(), Error> {
let mut etcd_client = EtcdInterface::new("localhost:2379".to_string()).await;
let _res = etcd_client.put("foo", "bar").await?;
let err = etcd_client.delete("foo2").await;
assert!(err.is_err());
Ok(())
}

#[tokio::test]
async fn test_function_get_all() -> Result<(), Error> {
let mut etcd_client = EtcdInterface::new("localhost:2379".to_string()).await;
let _res = etcd_client.put("bar", "foo").await;
let _res = etcd_client.put("hello", "world").await;
let values = etcd_client.get_all().await?;
assert_eq!(values[0], "foo");
assert_eq!(values[1], "world");
Ok(())
}
}
1 change: 1 addition & 0 deletions controller/lib/src/etcd_client/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod interface;
1 change: 1 addition & 0 deletions controller/lib/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod etcd_client;
pub mod external_api;
pub mod internal_api;

0 comments on commit b92d9c1

Please sign in to comment.