From bf5d6e9f01c925c18611ae578259b41c4ca8292c Mon Sep 17 00:00:00 2001 From: Brandon Pitman Date: Tue, 26 Nov 2024 16:56:57 -0800 Subject: [PATCH] Bump MSRV to 1.80. This is, at time of writing, the "stable minus two releases" that Janus supports. Also, clean up a few uses of OnceLock -- mostly to replace with the simpler LazyLock stabilized in 1.80, in one place replacing it with an async mutex as neither OnceLock nor LazyLock were appropriate as the initializing function would be async. --- Cargo.toml | 2 +- aggregator/src/binaries/janus_cli.rs | 39 ++++++++++--------- aggregator_api/src/routes.rs | 9 ++--- aggregator_core/src/taskprov.rs | 8 ++-- core/src/auth_tokens.rs | 10 ++--- .../tests/integration/in_cluster.rs | 9 ++--- .../tests/integration/simulation/proxy.rs | 7 ++-- 7 files changed, 41 insertions(+), 43 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e7d69b510..3a5657e71 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ edition = "2021" homepage = "https://divviup.org" license = "MPL-2.0" repository = "https://github.com/divviup/janus" -rust-version = "1.77.0" +rust-version = "1.80.0" version = "0.8.0-prerelease-1" [workspace.dependencies] diff --git a/aggregator/src/binaries/janus_cli.rs b/aggregator/src/binaries/janus_cli.rs index 02c1b3bc2..99fc21914 100644 --- a/aggregator/src/binaries/janus_cli.rs +++ b/aggregator/src/binaries/janus_cli.rs @@ -32,11 +32,12 @@ use serde::{Deserialize, Serialize}; use std::{ collections::BTreeMap, path::{Path, PathBuf}, - sync::{Arc, OnceLock}, + sync::Arc, }; use tokio::{ fs, runtime::{self, Runtime}, + sync::Mutex, }; use tracing::{debug, info}; use url::Url; @@ -510,8 +511,7 @@ async fn fetch_datastore_keys( secret_data_key, namespace, secret_name, ); - let secrets_api: kube::Api = - kube::Api::namespaced(kube_client.get().await?.clone(), namespace); + let secrets_api: kube::Api = kube::Api::namespaced(kube_client.get().await?, namespace); let secret = secrets_api .get(secret_name) @@ -542,7 +542,7 @@ async fn create_datastore_key( "Creating datastore key" ); let secrets_api: kube::Api = - kube::Api::namespaced(kube_client.get().await?.clone(), k8s_namespace); + kube::Api::namespaced(kube_client.get().await?, k8s_namespace); // Generate a random datastore key & encode it into unpadded base64 as will be expected by // consumers of the secret we are about to write. @@ -700,40 +700,43 @@ impl BinaryConfig for ConfigFile { /// A wrapper around [`kube::Client`] adding lazy initialization. struct LazyKubeClient { - lock: OnceLock, + lock: Mutex>, } impl LazyKubeClient { fn new() -> Self { Self { - lock: OnceLock::new(), + lock: Mutex::default(), } } /// Return a reference to a client, constructing a client from the default inferred /// configuration if it has not been done yet. This will use the local kubeconfig file if /// present, use in-cluster environment variables if present, or fail. - async fn get(&self) -> Result<&kube::Client> { - if let Some(client) = self.lock.get() { - return Ok(client); + async fn get(&self) -> Result { + let mut guard = self.lock.lock().await; + match guard.as_ref() { + Some(kube_client) => Ok(kube_client.clone()), + None => { + let kube_client = kube::Client::try_default() + .await + .context("couldn't load Kubernetes configuration")?; + *guard = Some(kube_client.clone()); + Ok(kube_client) + } } - let _ = self.lock.set( - kube::Client::try_default() - .await - .context("couldn't load Kubernetes configuration")?, - ); - Ok(self.lock.get().unwrap()) } } impl From for LazyKubeClient { - fn from(value: kube::Client) -> Self { + fn from(kube_client: kube::Client) -> Self { Self { - lock: OnceLock::from(value), + lock: Mutex::new(Some(kube_client)), } } } + #[cfg(test)] mod tests { use crate::{ @@ -823,7 +826,7 @@ mod tests { expected_datastore_keys ); // Shouldn't have set up a kube Client for this, since no namespace was given. - assert!(empty_kube_client.lock.get().is_none()); + assert!(empty_kube_client.lock.lock().await.is_none()); // Keys not provided at command line, present in k8s let common_options = CommonBinaryOptions::default(); diff --git a/aggregator_api/src/routes.rs b/aggregator_api/src/routes.rs index 75391dbb9..f82fd932d 100644 --- a/aggregator_api/src/routes.rs +++ b/aggregator_api/src/routes.rs @@ -26,7 +26,7 @@ use rand::random; use ring::digest::{digest, SHA256}; use std::{ str::FromStr, - sync::{Arc, OnceLock}, + sync::{Arc, LazyLock}, unreachable, }; use trillium::{Conn, Status}; @@ -36,9 +36,8 @@ pub(super) async fn get_config( _: &mut Conn, State(config): State>, ) -> Json { - static VERSION: OnceLock = OnceLock::new(); - let software_version = - VERSION.get_or_init(|| format!("{}-{}", env!("CARGO_PKG_VERSION"), git_revision())); + static VERSION: LazyLock = + LazyLock::new(|| format!("{}-{}", env!("CARGO_PKG_VERSION"), git_revision())); Json(AggregatorApiConfig { protocol: "DAP-09", @@ -61,7 +60,7 @@ pub(super) async fn get_config( "PureDpDiscreteLaplace", ], software_name: "Janus", - software_version, + software_version: &VERSION, }) } diff --git a/aggregator_core/src/taskprov.rs b/aggregator_core/src/taskprov.rs index a6337ef1a..14ac71c03 100644 --- a/aggregator_core/src/taskprov.rs +++ b/aggregator_core/src/taskprov.rs @@ -9,7 +9,7 @@ use serde::{ de::{self, Visitor}, Deserialize, Serialize, Serializer, }; -use std::{fmt, str::FromStr, sync::OnceLock}; +use std::{fmt, str::FromStr, sync::LazyLock}; use url::Url; #[derive(Educe, Clone, Copy, PartialEq, Eq)] @@ -131,8 +131,7 @@ pub struct PeerAggregator { /// /// [1]: https://www.ietf.org/archive/id/draft-wang-ppm-dap-taskprov-04.html#name-deriving-the-vdaf-verificat fn taskprov_salt() -> &'static Salt { - static SALT: OnceLock = OnceLock::new(); - SALT.get_or_init(|| { + static SALT: LazyLock = LazyLock::new(|| { Salt::new( HKDF_SHA256, &[ @@ -141,7 +140,8 @@ fn taskprov_salt() -> &'static Salt { 0x72, 0x3a, 0xf, 0xfe, ], ) - }) + }); + &SALT } impl PeerAggregator { diff --git a/core/src/auth_tokens.rs b/core/src/auth_tokens.rs index 0b3940a6b..57f497791 100644 --- a/core/src/auth_tokens.rs +++ b/core/src/auth_tokens.rs @@ -11,7 +11,7 @@ use ring::{ use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; use std::{ str::{self, FromStr}, - sync::OnceLock, + sync::LazyLock, }; /// HTTP header where auth tokens are provided in messages between participants. @@ -242,11 +242,9 @@ impl BearerToken { /// /// [1]: https://datatracker.ietf.org/doc/html/rfc6750#section-2.1 fn validate(value: &str) -> Result<(), anyhow::Error> { - static REGEX: OnceLock = OnceLock::new(); - - let regex = REGEX.get_or_init(|| Regex::new("^[-A-Za-z0-9._~+/]+=*$").unwrap()); - - if regex.is_match(value) { + static REGEX: LazyLock = + LazyLock::new(|| Regex::new("^[-A-Za-z0-9._~+/]+=*$").unwrap()); + if REGEX.is_match(value) { Ok(()) } else { Err(anyhow::anyhow!("bearer token has invalid format")) diff --git a/integration_tests/tests/integration/in_cluster.rs b/integration_tests/tests/integration/in_cluster.rs index 1fb020d87..e1bdbb3e5 100644 --- a/integration_tests/tests/integration/in_cluster.rs +++ b/integration_tests/tests/integration/in_cluster.rs @@ -666,7 +666,7 @@ mod rate_limits { use std::{ env, fs::File, - sync::{Arc, OnceLock}, + sync::{Arc, LazyLock}, time::Duration, }; use tokio::sync::Semaphore; @@ -687,14 +687,13 @@ mod rate_limits { impl TestConfig { fn load() -> &'static Self { - static CONFIG: OnceLock = OnceLock::new(); - - CONFIG.get_or_init(|| { + static CONFIG: LazyLock = LazyLock::new(|| { serde_json::from_reader( File::open(env::var("JANUS_E2E_RATE_LIMIT_TEST_CONFIG").unwrap()).unwrap(), ) .unwrap() - }) + }); + &CONFIG } } diff --git a/integration_tests/tests/integration/simulation/proxy.rs b/integration_tests/tests/integration/simulation/proxy.rs index e26221634..4bb6ec43e 100644 --- a/integration_tests/tests/integration/simulation/proxy.rs +++ b/integration_tests/tests/integration/simulation/proxy.rs @@ -1,6 +1,6 @@ use std::{ borrow::Cow, - sync::{Arc, Mutex, OnceLock}, + sync::{Arc, LazyLock, Mutex}, }; use regex::bytes::Regex; @@ -143,11 +143,10 @@ impl InspectHandler { } if conn.path().ends_with("/aggregate_shares") { inspect_response_body(&mut conn, |bytes| { - static ONCE: OnceLock = OnceLock::new(); - let batch_mismatch_regex = ONCE.get_or_init(|| { + static REGEX: LazyLock = LazyLock::new(|| { Regex::new("urn:ietf:params:ppm:dap:error:batchMismatch").unwrap() }); - if batch_mismatch_regex.is_match(bytes) { + if REGEX.is_match(bytes) { error!("batch mismatch response"); *self.failure.lock().unwrap() = true; }