Skip to content

Commit

Permalink
Merge pull request #261 from juicebox-systems/nt/version-check
Browse files Browse the repository at this point in the history
Return 426 error for SDKs with old version
  • Loading branch information
Imperiopolis committed Aug 10, 2023
2 parents 6d441f3 + 3c9a7d1 commit c3d273f
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 13 deletions.
19 changes: 10 additions & 9 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ rustls = "0.20.8"
rustls-pemfile = "1.0"
secrecy = { version = "0.8.0", features = ["serde"] }
secret_manager = { path = "secret_manager" }
semver = "1.0.18"
serde = { version = "1.0.152", default-features = false, features = [
"alloc",
"derive",
Expand Down
1 change: 1 addition & 0 deletions load_balancer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ opentelemetry-http = { workspace = true }
rustls = { workspace = true }
rustls-pemfile = { workspace = true }
secret_manager = { workspace = true }
semver = { workspace = true }
serde = { workspace = true }
service_core = { workspace = true }
signal-hook = { workspace = true }
Expand Down
36 changes: 34 additions & 2 deletions load_balancer/src/load_balancer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ use futures::Future;
use http_body_util::{BodyExt, Full, LengthLimitError, Limited};
use hyper::server::conn::http1;
use hyper::service::Service;
use hyper::StatusCode;
use hyper::{body::Incoming as IncomingBody, Request, Response};
use opentelemetry_http::HeaderExtractor;
use rustls::server::ResolvesServerCert;
use semver::Version;
use serde::Serialize;
use std::collections::HashMap;
use std::error::Error;
Expand All @@ -32,7 +34,7 @@ use juicebox_marshalling as marshalling;
use juicebox_networking::reqwest::{Client, ClientOptions};
use juicebox_networking::rpc;
use juicebox_realm_api::requests::{ClientRequest, ClientResponse, BODY_SIZE_LIMIT};
use juicebox_realm_api::types::RealmId;
use juicebox_realm_api::types::{RealmId, JUICEBOX_VERSION_HEADER};
use juicebox_realm_auth::validation::Validator as AuthTokenValidator;
use observability::logging::{Spew, TracingSource};
use observability::metrics::{self, Tag};
Expand All @@ -50,6 +52,7 @@ struct State {
agent_client: Client<AgentService>,
realms: Mutex<Arc<HashMap<RealmId, Vec<Partition>>>>,
metrics: metrics::Client,
semver: Version,
}

static TCP_ACCEPT_SPEW: Spew = Spew::new();
Expand All @@ -70,6 +73,7 @@ impl LoadBalancer {
agent_client: Client::new(ClientOptions::default()),
realms: Mutex::new(Arc::new(HashMap::new())),
metrics,
semver: Version::parse(env!("CARGO_PKG_VERSION")).unwrap(),
}))
}

Expand Down Expand Up @@ -234,7 +238,35 @@ impl Service<Request<IncomingBody>> for LoadBalancer {
if request.uri().path() == "/livez" {
return Ok(Response::builder()
.status(200)
.body(Full::from(Bytes::from("Juicebox load balancer: OK\n")))
.body(Full::from(Bytes::from(format!(
"Juicebox load balancer: {}\n",
state.semver
))))
.unwrap());
}

let has_valid_version = request
.headers()
.get(JUICEBOX_VERSION_HEADER)
.and_then(|version| version.to_str().ok())
.and_then(|str| Version::parse(str).ok())
.is_some_and(|semver| {
// verify that major.minor is >= to our major.minor
// patch and bugfix versions can be out-of-sync
// to allow the SDK and realm software to make
// changes that don't break protocol compatability
semver.major > state.semver.major
|| (semver.major == state.semver.major
&& semver.minor >= state.semver.minor)
});

if !has_valid_version {
return Ok(Response::builder()
.status(StatusCode::UPGRADE_REQUIRED)
.body(Full::from(Bytes::from(format!(
"SDK upgrade required to version >={}.{}",
state.semver.major, state.semver.minor
))))
.unwrap());
}

Expand Down
11 changes: 10 additions & 1 deletion testing/tests/loadbalancer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use http::StatusCode;
use http::{HeaderMap, HeaderValue, StatusCode};
use juicebox_sdk::{JUICEBOX_VERSION_HEADER, VERSION};
use once_cell::sync::Lazy;

use std::path::PathBuf;
use std::time::Duration;

Expand Down Expand Up @@ -42,6 +44,13 @@ async fn request_bodysize_check() {
.use_rustls_tls();
b = b.add_root_certificate(cluster.lb_cert());

let mut headers = HeaderMap::new();
headers.append(
JUICEBOX_VERSION_HEADER,
HeaderValue::from_str(VERSION).unwrap(),
);
b = b.default_headers(headers);

let http = b.build().unwrap();
let req = vec![1; BODY_SIZE_LIMIT + 1];
let res = http
Expand Down

0 comments on commit c3d273f

Please sign in to comment.