Skip to content

Commit

Permalink
Merge pull request #143 from navicore/refactor-user-agent
Browse files Browse the repository at this point in the history
user agent
  • Loading branch information
navicore committed Apr 21, 2024
2 parents 93b19f7 + 5f9b9fe commit e48dd70
Show file tree
Hide file tree
Showing 13 changed files with 214 additions and 40 deletions.
125 changes: 118 additions & 7 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ path = "src/main.rs"

[dependencies]
anyhow = "1.0.82"
bytes = "1.6.0"
chrono = "0.4"
clap = { version = "4", features = ["derive"] }
clap_complete = "4"
Expand Down Expand Up @@ -42,12 +43,14 @@ tokio-stream = "0.1"
tokio-util = "0.7"
tower = "0.4"
tower-http = "0.5"
tower-test = "0.4.0"
tracing = "0.1"
tracing-subscriber = "0.3"
unicode-width = "0.1"
uuid = { version = "1", features = [ "v4" ] }
webpki = "0.22"
webpki-roots = "0.25"
wiremock = "0.6.0"
x509-parser = "0.16.0"

[dev-dependencies]
Expand Down
9 changes: 2 additions & 7 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::k8s::client::UserAgentError;
use derive_more::From;
use k8s_openapi::serde_json;

Expand All @@ -6,7 +7,7 @@ pub type Result<T> = core::result::Result<T, Error>;
#[derive(Debug, From)]
pub enum Error {
#[from]
Custom(String),
UserAgentError(UserAgentError),

#[from]
Json(serde_json::Error),
Expand All @@ -21,12 +22,6 @@ pub enum Error {
HttpHeader(hyper::http::Error),
}

impl From<&str> for Error {
fn from(val: &str) -> Self {
Self::Custom(val.to_string())
}
}

impl core::fmt::Display for Error {
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> {
write!(fmt, "{self:?}")
Expand Down
54 changes: 39 additions & 15 deletions src/k8s/client.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,48 @@
/// almost a hundred lines of code just to add a proper User-Agent header
// A hundred lines of code just to add a correct User-Agent header - what am I missing?
use crate::error::Result as NvResult;
use hyper::Request;
use hyper_util::rt::TokioExecutor;
use kube::{client::ConfigExt, Client, Config};
use pin_project::pin_project;
use std::fmt;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use tower::{Layer, Service};

const VERSION: &str = env!("CARGO_PKG_VERSION");
const MODULE: &str = env!("CARGO_PKG_NAME");

#[derive(Debug)]
pub struct UserAgentError {
message: String,
}

impl fmt::Display for UserAgentError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.message)
}
}

impl std::error::Error for UserAgentError {}

pub struct UserAgentLayer {
user_agent: String,
user_agent: hyper::header::HeaderValue,
}

impl UserAgentLayer {
#[must_use]
pub fn new(user_agent: &str) -> Self {
Self {
user_agent: user_agent.to_string(),
}
/// # Errors
///
/// Will return `Err` if Layer cannot be created due to invalid `user_agent` header value
pub fn new(user_agent: &str) -> Result<Self, UserAgentError> {
let header_value =
hyper::header::HeaderValue::from_str(user_agent).map_err(|e| UserAgentError {
message: format!("can not parse user_agent: {e}"),
})?;

Ok(Self {
user_agent: header_value,
})
}
}

Expand All @@ -37,7 +61,7 @@ impl<S> Layer<S> for UserAgentLayer {
pub struct UserAgentService<S> {
#[pin]
inner: S,
user_agent: String,
user_agent: hyper::header::HeaderValue,
}

impl<S, ReqBody> Service<Request<ReqBody>> for UserAgentService<S>
Expand All @@ -57,29 +81,29 @@ where
}

fn call(&mut self, mut req: Request<ReqBody>) -> Self::Future {
let header_value = hyper::header::HeaderValue::from_str(&self.user_agent)
.unwrap_or_else(|_| hyper::header::HeaderValue::from_static("navipod"));

req.headers_mut()
.insert(hyper::header::USER_AGENT, header_value);
.insert(hyper::header::USER_AGENT, self.user_agent.clone());

let fut = self.inner.call(req);
Box::pin(fut)
}
}

/// Create a new k8s client to interact with k8s cluster api
/// Create a new k8s client to interact with k8s cluster api that includes User-Agent header
///
/// # Errors
///
/// Will return `Err` if data can not be retrieved from k8s cluster api
pub async fn new() -> NvResult<Client> {
pub async fn new(custom_user_agent: Option<&str>) -> NvResult<Client> {
let config = Config::infer().await?;

let https = config.rustls_https_connector()?;

let default_user_agent = format!("{MODULE}/{VERSION}");
let user_agent_str = custom_user_agent.unwrap_or(&default_user_agent);

let service = tower::ServiceBuilder::new()
.layer(UserAgentLayer::new("navipod/1.0")) // todo: manage via CICD
.layer(UserAgentLayer::new(user_agent_str)?)
.layer(config.base_uri_layer())
.option_layer(config.auth_layer()?)
.service(hyper_util::client::legacy::Client::builder(TokioExecutor::new()).build(https));
Expand Down
2 changes: 1 addition & 1 deletion src/k8s/containers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ pub async fn logs(
pod_name: String,
container_name: String,
) -> Result<Vec<LogRec>> {
let client = new().await?;
let client = new(None).await?;
let pods: Api<Pod> = Api::default_namespaced(client);

let label_selector = format_label_selector(&selector);
Expand Down
2 changes: 1 addition & 1 deletion src/k8s/pod_ingress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use super::client::new;
///
/// Will return `Err` if function cannot connect to Kubernetes
pub async fn explain(namespace: &str, pod_name: &str) -> Result<()> {
let client = new().await?;
let client = new(None).await?;
let pod = get_pod(&client, namespace, pod_name).await?;

check_replica_set(&client, &pod, namespace).await?;
Expand Down
2 changes: 1 addition & 1 deletion src/k8s/pods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ fn get_pod_state(pod: &Pod) -> String {
/// Will return `Err` if data can not be retrieved from k8s cluster api
#[allow(clippy::significant_drop_tightening)]
pub async fn list_rspods(selector: BTreeMap<String, String>) -> Result<Vec<RsPod>> {
let client = new().await?;
let client = new(None).await?;

// Format the label selector from the BTreeMap
let label_selector = format_label_selector(&selector);
Expand Down

0 comments on commit e48dd70

Please sign in to comment.