#[cfg(feature = "tracer")]
use opentelemetry::trace::Tracer;
use crate::cluster::EtcdNode;
use crate::etcdpb::etcdserverpb::kv_server::Kv;
use crate::etcdpb::etcdserverpb::{CompactionRequest, CompactionResponse, DeleteRangeRequest, DeleteRangeResponse, PutRequest, PutResponse, RangeRequest, RangeResponse, TxnRequest, TxnResponse};
use tonic::{async_trait, Request, Response, Status};
impl EtcdNode {
#[cfg(feature = "tracer")]
pub(crate) async fn metric_kv(&self, op: &'static str, ok: bool, took: std::time::Duration) {
if let Some(i) = self.meter.read().await.as_ref() {
i.kv(op, ok, took);
}
}
async fn deny_remote(&self, key: &[u8], remote: Option<std::net::SocketAddr>)
-> Result<(), Status>
{
if self.policy.read().await.may_serve(key, remote) {
return Ok(());
}
Err(Status::permission_denied(
"this key prefix is served only on a local connection"))
}
async fn deny_readonly(&self, key: &[u8], range_end: &[u8]) -> Result<(), Status> {
let p = self.policy.read().await;
let ok = if range_end.is_empty() { p.writable(key) } else { p.range_writable(key, range_end) };
if ok {
return Ok(());
}
Err(Status::permission_denied("this key prefix is written only by the node itself"))
}
}
#[async_trait]
impl Kv for EtcdNode {
async fn range(&self, request: Request<RangeRequest>) -> Result<Response<RangeResponse>, Status> {
let remote = request.remote_addr();
self.deny_remote(&request.get_ref().key, remote).await?;
let (key, end, count_only) = {
let r = request.get_ref();
(r.key.clone(), r.range_end.clone(), r.count_only)
};
let span_ok = self.policy.read().await.range_may_serve(&key, &end, remote);
if !span_ok && count_only {
return Err(Status::permission_denied("this key prefix is served only on a local connection"));
}
#[cfg(feature = "tracer")]
let _s = self.tracer.read().await.as_ref().map(|t| t.start("get"));
let _started = std::time::Instant::now();
let got = self.get_impl(request).await;
#[cfg(feature = "tracer")]
self.metric_kv("get", got.is_ok(), _started.elapsed()).await;
let mut result = got?;
if !span_ok {
let p = self.policy.read().await;
let r = result.get_mut();
let before = r.kvs.len();
r.kvs.retain(|kv| p.may_serve(&kv.key, remote));
r.count -= (before - r.kvs.len()) as i64;
}
Ok(result)
}
async fn put(&self, request: Request<PutRequest>) -> Result<Response<PutResponse>, Status> {
self.deny_remote(&request.get_ref().key, request.remote_addr()).await?;
self.deny_readonly(&request.get_ref().key, &[]).await?;
#[cfg(feature = "tracer")]
let _s = self.tracer.read().await.as_ref().map(|t| t.start("put"));
let _started = std::time::Instant::now();
let result = self.put_impl(request).await;
#[cfg(feature = "tracer")]
self.metric_kv("put", result.is_ok(), _started.elapsed()).await;
result
}
async fn delete_range(&self, request: Request<DeleteRangeRequest>) -> Result<Response<DeleteRangeResponse>, Status> {
self.deny_remote(&request.get_ref().key, request.remote_addr()).await?;
self.deny_readonly(&request.get_ref().key, &request.get_ref().range_end).await?;
#[cfg(feature = "tracer")]
let _s = self.tracer.read().await.as_ref().map(|t| t.start("delete"));
let _started = std::time::Instant::now();
let result = self.delete_impl(request).await;
#[cfg(feature = "tracer")]
self.metric_kv("delete", result.is_ok(), _started.elapsed()).await;
result
}
async fn txn(&self, request: Request<TxnRequest>) -> Result<Response<TxnResponse>, Status> {
let remote = request.remote_addr();
for k in crate::kv::txn_keys(request.get_ref()) {
self.deny_remote(&k, remote).await?;
self.deny_readonly(&k, &[]).await?;
}
#[cfg(feature = "tracer")]
let _s = self.tracer.read().await.as_ref().map(|t| t.start("txn"));
let _started = std::time::Instant::now();
let result = self.txn_impl(request).await;
#[cfg(feature = "tracer")]
self.metric_kv("txn", result.is_ok(), _started.elapsed()).await;
result
}
async fn compact(&self, _request: Request<CompactionRequest>) -> Result<Response<CompactionResponse>, Status> {
Ok(Response::new(CompactionResponse { header: None }))
}
}