Skip to content

Commit

Permalink
simplify dependencies, tracing, no axum-extras, inline health check
Browse files Browse the repository at this point in the history
also remove crate level reimports since this is meant to be super clean

Signed-off-by: clux <[email protected]>
  • Loading branch information
clux committed Dec 26, 2023
1 parent 42dfb82 commit 9439d48
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 184 deletions.
168 changes: 15 additions & 153 deletions Cargo.lock

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

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ path = "version.rs"

[dependencies]
axum = "0.6.20"
axum-extra = { version = "0.9.0", features = ["typed-routing"] }
tower-http = { version = "0.4.4", default-features = false, features = ["trace"] }
futures = "0.3.30"
tokio = { version = "1.35.1", features = ["macros", "rt-multi-thread", "signal"] }
Expand Down
2 changes: 1 addition & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ default:
@just --list --unsorted

run:
RUST_LOG=info,kube=debug,version=debug cargo run
RUST_LOG=debug,hyper=info,rustls=info cargo run

fmt:
cargo +nightly fmt
Expand Down
1 change: 0 additions & 1 deletion rustfmt.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
overflow_delimited_expr = true
newline_style = "Unix"
imports_granularity = "Crate"
reorder_impl_items = true
blank_lines_upper_bound = 2
comment_width = 110
Expand Down
49 changes: 21 additions & 28 deletions version.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use axum::{extract::State, http::StatusCode, response::IntoResponse, routing, Json, Router};
use axum_extra::routing::TypedPath;
use axum::extract::{Path, State};
use axum::{http::StatusCode, response::IntoResponse, routing, Json, Router};
use futures::{future, StreamExt};
use k8s_openapi::api::apps::v1::Deployment;
use kube::{
runtime::{reflector, watcher, WatchStreamExt},
Api, Client, ResourceExt,
};
use tracing::{debug, info, instrument, warn, Level};
use kube::runtime::{reflector, watcher, WatchStreamExt};
use kube::{Api, Client, ResourceExt};
use tracing::{debug, info, warn};

#[derive(serde::Serialize, Clone)]
struct Entry {
Expand All @@ -31,55 +29,50 @@ fn deployment_to_entry(d: &Deployment) -> Option<Entry> {
Some(Entry { name, namespace, container, version })
}

#[instrument(skip(store))]
async fn get_versions(State(store): State<Cache>) -> Json<Vec<Entry>> {
let data = store.state().iter().filter_map(|d| deployment_to_entry(d)).collect();
Json(data)
}

#[derive(TypedPath, serde::Deserialize, Debug)]
#[typed_path("/versions/:namespace/:name")]
// - GET /versions/:namespace/:name
#[derive(serde::Deserialize, Debug)]
struct EntryPath {
name: String,
namespace: String,
}

#[instrument(skip(store))]
async fn get_version(State(store): State<Cache>, path: EntryPath) -> impl IntoResponse {
let key = reflector::ObjectRef::new(&path.name).within(&path.namespace);
async fn get_version(State(store): State<Cache>, Path(p): Path<EntryPath>) -> impl IntoResponse {
let key = reflector::ObjectRef::new(&p.name).within(&p.namespace);
if let Some(Some(e)) = store.get(&key).map(|d| deployment_to_entry(&d)) {
return Ok(Json(e));
}
Err((StatusCode::NOT_FOUND, "not found"))
}

async fn health() -> impl IntoResponse {
Json("healthy")
// - GET /versions
async fn get_versions(State(store): State<Cache>) -> Json<Vec<Entry>> {
let data = store.state().iter().filter_map(|d| deployment_to_entry(d)).collect();
Json(data)
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt().with_max_level(Level::DEBUG).init();
tracing_subscriber::fmt::init();
let client = Client::try_default().await?;
let api: Api<Deployment> = Api::all(client);

let (reader, writer) = reflector::store();
let watch = reflector(writer, watcher(api, Default::default()))
.default_backoff()
.touched_objects()
.filter_map(|x| async move { Result::ok(x) })
.for_each(|o| {
debug!("Saw {} in {}", o.name_any(), o.namespace().unwrap());
future::ready(())
.for_each(|r| {
future::ready(match r {
Ok(o) => debug!("Saw {} in {}", o.name_any(), o.namespace().unwrap()),
Err(e) => warn!("watcher error: {e}"),
})
});

let app = Router::new()
.route("/versions", routing::get(get_versions))
.route("/versions/:namespace/:name", routing::get(get_version))
.with_state(reader)
.with_state(reader) // routes can read from the reflector store
.layer(tower_http::trace::TraceLayer::new_for_http())
// NB: routes added after TraceLayer are not traced
.route("/health", routing::get(health));
.route("/health", routing::get(|| async { "up" }));

let server = axum::Server::bind(&std::net::SocketAddr::from(([0, 0, 0, 0], 8000)))
.serve(app.into_make_service())
Expand Down

0 comments on commit 9439d48

Please sign in to comment.