generated from Patagia/template-nix
Compare commits
5 commits
435552a655
...
50cf677d68
Author | SHA1 | Date | |
---|---|---|---|
50cf677d68 |
|||
3cf1714185 |
|||
e42e924ce6 |
|||
64c971e68e | |||
cb9d8b4bf0 |
16 changed files with 1193 additions and 461 deletions
|
@ -1,10 +0,0 @@
|
|||
[alias]
|
||||
xtask = "run --package xtask --quiet --"
|
||||
|
||||
[profile.dev]
|
||||
debug = 0
|
||||
strip = "debuginfo"
|
||||
|
||||
[target.x86_64-unknown-linux-gnu]
|
||||
linker = "clang"
|
||||
rustflags = ["-C", "link-arg=-fuse-ld=mold", "-C", "target-cpu=native"]
|
1143
Cargo.lock
generated
1143
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
31
Cargo.toml
31
Cargo.toml
|
@ -23,28 +23,37 @@ edition = "2021"
|
|||
name = "patagia-run"
|
||||
|
||||
[workspace.dependencies]
|
||||
anyhow = "1.0.95"
|
||||
clap = { version = "4.5.26", features = [
|
||||
anyhow = "1.0.98"
|
||||
chrono = "0.4.39"
|
||||
clap = { version = "4.5.37", features = [
|
||||
"derive",
|
||||
"deprecated",
|
||||
"env",
|
||||
"wrap_help",
|
||||
"string",
|
||||
] }
|
||||
dropshot = "0.15.1"
|
||||
dropshot = "0.16.0"
|
||||
ed25519-dalek = { version = "2.1.1", features = ["pem", "rand_core"] }
|
||||
futures = "0.3"
|
||||
http = "1.2.0"
|
||||
once_cell = "1.20.2"
|
||||
hex = "0.4.3"
|
||||
hkdf = "0.12.4"
|
||||
http = "1.3.1"
|
||||
once_cell = "1.21.3"
|
||||
progenitor = "0.9"
|
||||
reqwest = { version = "0.12.12", features = ["json", "stream", "rustls-tls"] }
|
||||
schemars = "0.8.21"
|
||||
semver = "1.0.24"
|
||||
serde = { version = "1.0.217", features = ["derive"] }
|
||||
rand = "0.8.5"
|
||||
reqwest = { version = "0.12.15", features = ["json", "stream", "rustls-tls"] }
|
||||
schemars = { version = "0.8.22", features = ["bytes", "chrono", "derive"] }
|
||||
semver = "1.0.26"
|
||||
serde_json = "1.0.138"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_with = { version = "3.12.0", features = ["base64", "hex", "macros", "std"] }
|
||||
sha2 = "0.10.8"
|
||||
slog = "2.7.0"
|
||||
slog-async = "2.8.0"
|
||||
tokio = { version = "1.43.0", features = ["full"] }
|
||||
tokio = { version = "1.44.2", features = ["full"] }
|
||||
tracing = "0.1.41"
|
||||
tracing-core = "0.1.33"
|
||||
tracing-chrome = "0.7.2"
|
||||
tracing-core = "0.1.33"
|
||||
tracing-slog = { git = "https://github.com/oxidecomputer/tracing-slog", default-features = false }
|
||||
uuid = { version = "1", features = [ "serde", "v4" ] }
|
||||
x25519-dalek = { version = "2.0.1", features = ["serde", "static_secrets"] }
|
||||
|
|
|
@ -6,6 +6,7 @@ version.workspace = true
|
|||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
chrono.workspace = true
|
||||
clap.workspace = true
|
||||
futures.workspace = true
|
||||
instrumentation = { path = "../instrumentation" }
|
||||
|
|
65
api.json
65
api.json
|
@ -5,6 +5,43 @@
|
|||
"version": "1.0.0"
|
||||
},
|
||||
"paths": {
|
||||
"/nodes/register": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"node"
|
||||
],
|
||||
"summary": "Get registration info",
|
||||
"operationId": "get_registration_info",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "query",
|
||||
"name": "key",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "successful operation",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/RegistrationInfo"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"4XX": {
|
||||
"$ref": "#/components/responses/Error"
|
||||
},
|
||||
"5XX": {
|
||||
"$ref": "#/components/responses/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users": {
|
||||
"get": {
|
||||
"tags": [
|
||||
|
@ -141,6 +178,31 @@
|
|||
"request_id"
|
||||
]
|
||||
},
|
||||
"RegistrationInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"node_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"nonce": {
|
||||
"type": "string"
|
||||
},
|
||||
"server_dh_pub": {
|
||||
"type": "string"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"node_id",
|
||||
"nonce",
|
||||
"server_dh_pub",
|
||||
"timestamp"
|
||||
]
|
||||
},
|
||||
"User": {
|
||||
"description": "User",
|
||||
"type": "object",
|
||||
|
@ -210,6 +272,9 @@
|
|||
}
|
||||
},
|
||||
"tags": [
|
||||
{
|
||||
"name": "node"
|
||||
},
|
||||
{
|
||||
"name": "user"
|
||||
}
|
||||
|
|
|
@ -7,15 +7,24 @@ version.workspace = true
|
|||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
chrono.workspace = true
|
||||
clap.workspace = true
|
||||
dropshot.workspace = true
|
||||
ed25519-dalek.workspace = true
|
||||
futures.workspace = true
|
||||
hex.workspace = true
|
||||
hkdf.workspace = true
|
||||
http.workspace = true
|
||||
instrumentation = { path = "../instrumentation" }
|
||||
rand.workspace = true
|
||||
schemars.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde_with.workspace = true
|
||||
sha2.workspace = true
|
||||
slog-async.workspace = true
|
||||
slog.workspace = true
|
||||
sqlx = { version = "0.8.3", default-features = false, features = [
|
||||
sqlx = { version = "0.8.5", default-features = false, features = [
|
||||
"macros", "migrate", "postgres", "runtime-tokio", "tls-rustls", "time", "uuid"
|
||||
] }
|
||||
tokio.workspace = true
|
||||
|
@ -23,6 +32,7 @@ trace-request = { path = "../trace-request" }
|
|||
tracing-slog.workspace = true
|
||||
tracing.workspace = true
|
||||
uuid.workspace = true
|
||||
x25519-dalek.workspace = true
|
||||
|
||||
[package.metadata.cargo-machete]
|
||||
ignored = ["http"]
|
||||
|
|
|
@ -4,6 +4,7 @@ use dropshot::ApiDescription;
|
|||
use std::sync::Arc;
|
||||
|
||||
use crate::context::ControllerContext;
|
||||
use crate::node;
|
||||
use crate::user;
|
||||
use crate::version;
|
||||
|
||||
|
@ -11,6 +12,7 @@ type ControllerApiDescription = ApiDescription<Arc<ControllerContext>>;
|
|||
|
||||
pub fn api() -> Result<ControllerApiDescription> {
|
||||
let mut api = ControllerApiDescription::new();
|
||||
node::register_api(&mut api)?;
|
||||
user::register_api(&mut api)?;
|
||||
api.register(version::version)?;
|
||||
Ok(api)
|
||||
|
|
|
@ -1,11 +1,20 @@
|
|||
use sqlx::postgres::PgPool;
|
||||
|
||||
use crate::node::NodeController;
|
||||
|
||||
pub struct ControllerContext {
|
||||
pub pg_pool: PgPool,
|
||||
// pub node_controller: Mutex<NodeController>,
|
||||
pub node_controller: NodeController,
|
||||
}
|
||||
|
||||
impl ControllerContext {
|
||||
pub fn new(pg_pool: PgPool) -> ControllerContext {
|
||||
ControllerContext { pg_pool }
|
||||
// let node_controller = Mutex::new(NodeController::new(pg_pool.to_owned()));
|
||||
let node_controller = NodeController::new(pg_pool.to_owned());
|
||||
ControllerContext {
|
||||
pg_pool,
|
||||
node_controller,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
pub mod api;
|
||||
pub mod context;
|
||||
|
||||
mod node;
|
||||
mod user;
|
||||
mod version;
|
||||
|
|
43
controller/src/node/api.rs
Normal file
43
controller/src/node/api.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
use dropshot::{endpoint, HttpError, HttpResponseOk, Query, RequestContext};
|
||||
use dropshot::{ApiDescription, ApiDescriptionRegisterError};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::serde_as;
|
||||
use trace_request::trace_request;
|
||||
use x25519_dalek::PublicKey;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::context::ControllerContext;
|
||||
use crate::node::controller::RegistrationInfo;
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, Default, Deserialize, JsonSchema, Serialize)]
|
||||
pub struct RegistrationParams {
|
||||
#[serde_as(as = "serde_with::base64::Base64<serde_with::base64::UrlSafe>")]
|
||||
#[schemars(with = "String")]
|
||||
key: [u8; 32],
|
||||
}
|
||||
|
||||
pub fn register_api(
|
||||
api: &mut ApiDescription<Arc<ControllerContext>>,
|
||||
) -> Result<(), ApiDescriptionRegisterError> {
|
||||
api.register(get_registration_info)
|
||||
}
|
||||
|
||||
/// Get registration info
|
||||
#[endpoint {
|
||||
method = GET,
|
||||
path = "/nodes/register",
|
||||
tags = [ "node" ],
|
||||
}]
|
||||
#[trace_request]
|
||||
async fn get_registration_info(
|
||||
rqctx: RequestContext<Arc<ControllerContext>>,
|
||||
params: Query<RegistrationParams>,
|
||||
) -> Result<HttpResponseOk<RegistrationInfo>, HttpError> {
|
||||
let key = PublicKey::from(params.into_inner().key);
|
||||
tracing::debug!("Registration info for public key: {:?}", key);
|
||||
let info = rqctx.context().node_controller.new_registration(&key);
|
||||
Ok(HttpResponseOk(info))
|
||||
}
|
179
controller/src/node/controller.rs
Normal file
179
controller/src/node/controller.rs
Normal file
|
@ -0,0 +1,179 @@
|
|||
use chrono::DateTime;
|
||||
use ed25519_dalek::ed25519::signature::SignerMut;
|
||||
use hkdf::Hkdf;
|
||||
use rand::Rng;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::serde_as;
|
||||
use sha2::Sha256;
|
||||
use sqlx::postgres::PgPool;
|
||||
use uuid::Uuid;
|
||||
use x25519_dalek::{PublicKey, StaticSecret};
|
||||
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Deserialize, JsonSchema, Serialize)]
|
||||
pub struct RegistrationInfo {
|
||||
node_id: Uuid,
|
||||
challenge: Challenge,
|
||||
|
||||
#[serde_as(as = "serde_with::base64::Base64")]
|
||||
#[schemars(with = "String")]
|
||||
challenge_signature: [u8; 64],
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Deserialize, JsonSchema, Serialize)]
|
||||
pub struct Challenge {
|
||||
timestamp: DateTime<chrono::Utc>,
|
||||
|
||||
#[serde_as(as = "serde_with::base64::Base64")]
|
||||
#[schemars(with = "String")]
|
||||
nonce: [u8; 32],
|
||||
|
||||
#[serde_as(as = "serde_with::base64::Base64")]
|
||||
#[schemars(with = "String")]
|
||||
server_dh_pub: [u8; 32],
|
||||
|
||||
params: ArgonParams,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Deserialize, JsonSchema, Serialize)]
|
||||
struct ArgonParams {
|
||||
iterations: u32,
|
||||
memory_kb: u32,
|
||||
threads: u32,
|
||||
}
|
||||
|
||||
pub struct NodeController {
|
||||
_pg_pool: PgPool,
|
||||
signing_key: RwLock<Option<Arc<SecretKey>>>,
|
||||
}
|
||||
|
||||
type SecretKey = [u8; 32];
|
||||
type Nonce256 = [u8; 32];
|
||||
|
||||
trait SecretKeyExt {
|
||||
fn derive_dh_secret(&self, nonce: &Nonce256) -> StaticSecret;
|
||||
}
|
||||
|
||||
impl SecretKeyExt for SecretKey {
|
||||
fn derive_dh_secret(&self, nonce: &Nonce256) -> StaticSecret {
|
||||
let hk = Hkdf::<Sha256>::new(Some(nonce), self);
|
||||
let mut out = [0u8; 32];
|
||||
hk.expand(b"x25519-secret", &mut out).unwrap();
|
||||
StaticSecret::from(out)
|
||||
}
|
||||
}
|
||||
|
||||
impl RegistrationInfo {
|
||||
pub fn from(server_secret: &SecretKey, client_dh_public_key: &PublicKey) -> RegistrationInfo {
|
||||
let mut rng = rand::thread_rng();
|
||||
let nonce = rng.gen();
|
||||
|
||||
let server_dh_secret = server_secret.derive_dh_secret(&nonce);
|
||||
let _shared_secret = server_dh_secret.diffie_hellman(client_dh_public_key);
|
||||
let server_dh_public_key = PublicKey::from(&server_dh_secret);
|
||||
|
||||
let timestamp = chrono::Utc::now();
|
||||
|
||||
let params = ArgonParams {
|
||||
iterations: 10,
|
||||
memory_kb: 220 * 1024, // 220 MiB
|
||||
threads: 4,
|
||||
};
|
||||
|
||||
let challenge = Challenge {
|
||||
timestamp,
|
||||
nonce,
|
||||
server_dh_pub: server_dh_public_key.to_bytes(),
|
||||
params,
|
||||
};
|
||||
|
||||
let challenge_json = serde_json::to_vec(&challenge).unwrap();
|
||||
|
||||
let mut sk = ed25519_dalek::SigningKey::from_bytes(server_secret);
|
||||
let sig = sk.sign(challenge_json.as_slice());
|
||||
|
||||
let info = RegistrationInfo {
|
||||
node_id: Uuid::new_v4(),
|
||||
challenge,
|
||||
challenge_signature: sig.to_bytes(),
|
||||
};
|
||||
|
||||
tracing::debug!("Info: {:?}", info);
|
||||
info
|
||||
}
|
||||
}
|
||||
|
||||
impl NodeController {
|
||||
pub fn new(pg_pool: PgPool) -> NodeController {
|
||||
NodeController {
|
||||
_pg_pool: pg_pool,
|
||||
signing_key: RwLock::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_registration(&self, client_dh_public_key: &PublicKey) -> RegistrationInfo {
|
||||
let server_secret = self.master_key();
|
||||
RegistrationInfo::from(&server_secret, client_dh_public_key)
|
||||
}
|
||||
|
||||
fn master_key(&self) -> Arc<SecretKey> {
|
||||
self.signing_key
|
||||
.write()
|
||||
.unwrap()
|
||||
.get_or_insert_with(|| {
|
||||
tracing::debug!("Generating key");
|
||||
Arc::new(rand::rngs::OsRng.gen())
|
||||
})
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_registration_info() {
|
||||
let client_key: SecretKey = rand::rngs::OsRng.gen();
|
||||
let server_key = rand::rngs::OsRng.gen();
|
||||
let client_public_key = PublicKey::from(client_key);
|
||||
|
||||
let info = RegistrationInfo::from(&server_key, &client_public_key);
|
||||
let info2 = RegistrationInfo::from(&server_key, &client_public_key);
|
||||
|
||||
// Randomness
|
||||
assert_ne!(info.node_id, info2.node_id, "Node ID should be unique");
|
||||
assert_ne!(
|
||||
info.challenge.nonce, info2.challenge.nonce,
|
||||
"Nonce should be unique"
|
||||
);
|
||||
assert_ne!(
|
||||
info.challenge.server_dh_pub, info2.challenge.server_dh_pub,
|
||||
"Server public key derived from nonce should be unique"
|
||||
);
|
||||
|
||||
// Timestamp
|
||||
let now = chrono::Utc::now();
|
||||
assert!(
|
||||
info.challenge.timestamp <= now,
|
||||
"Timestamp is in the future"
|
||||
);
|
||||
assert!(
|
||||
info.challenge.timestamp >= now - chrono::Duration::milliseconds(5),
|
||||
"Timestamp is too old"
|
||||
);
|
||||
|
||||
// Public key
|
||||
let server_dh_secret = server_key.derive_dh_secret(&info.challenge.nonce);
|
||||
let server_dh_public_key = PublicKey::from(&server_dh_secret).to_bytes();
|
||||
assert_eq!(
|
||||
info.challenge.server_dh_pub, server_dh_public_key,
|
||||
"Server public key should be derived from nonce"
|
||||
);
|
||||
}
|
||||
}
|
5
controller/src/node/mod.rs
Normal file
5
controller/src/node/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
mod api;
|
||||
mod controller;
|
||||
|
||||
pub use self::api::register_api;
|
||||
pub(crate) use self::controller::NodeController;
|
42
flake.lock
generated
42
flake.lock
generated
|
@ -3,11 +3,11 @@
|
|||
"advisory-db": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1735928634,
|
||||
"narHash": "sha256-Qg1vJOuEohAbdRmTTOLrbbGsyK9KRB54r3+aBuOMctM=",
|
||||
"lastModified": 1745847494,
|
||||
"narHash": "sha256-tVK06dd+WVWurUq+VvzApYD6ZJHUKHAm3jbks5aVNqM=",
|
||||
"owner": "rustsec",
|
||||
"repo": "advisory-db",
|
||||
"rev": "63a2f39924f66ca89cf5761f299a8a244fe02543",
|
||||
"rev": "49a83cd6c827efeab34e74a4075ae184a32d2648",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -18,11 +18,11 @@
|
|||
},
|
||||
"crane": {
|
||||
"locked": {
|
||||
"lastModified": 1736101677,
|
||||
"narHash": "sha256-iKOPq86AOWCohuzxwFy/MtC8PcSVGnrxBOvxpjpzrAY=",
|
||||
"lastModified": 1745454774,
|
||||
"narHash": "sha256-oLvmxOnsEKGtwczxp/CwhrfmQUG2ym24OMWowcoRhH8=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "61ba163d85e5adeddc7b3a69bb174034965965b2",
|
||||
"rev": "efd36682371678e2b6da3f108fdb5c613b3ec598",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -66,11 +66,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1736061677,
|
||||
"narHash": "sha256-DjkQPnkAfd7eB522PwnkGhOMuT9QVCZspDpJJYyOj60=",
|
||||
"lastModified": 1745742390,
|
||||
"narHash": "sha256-1rqa/XPSJqJg21BKWjzJZC7yU0l/YTVtjRi0RJmipus=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "cbd8ec4de4469333c82ff40d057350c30e9f7d36",
|
||||
"rev": "26245db0cb552047418cfcef9a25da91b222d6c7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -82,11 +82,11 @@
|
|||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1728538411,
|
||||
"narHash": "sha256-f0SBJz1eZ2yOuKUr5CA9BHULGXVSn6miBuUWdTyhUhU=",
|
||||
"lastModified": 1744536153,
|
||||
"narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b69de56fac8c2b6f8fd27f2eca01dcda8e0a4221",
|
||||
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -98,11 +98,11 @@
|
|||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1735554305,
|
||||
"narHash": "sha256-zExSA1i/b+1NMRhGGLtNfFGXgLtgo+dcuzHzaWA6w3Q=",
|
||||
"lastModified": 1745377448,
|
||||
"narHash": "sha256-jhZDfXVKdD7TSEGgzFJQvEEZ2K65UMiqW5YJ2aIqxMA=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "0e82ab234249d8eee3e8c91437802b32c74bb3fd",
|
||||
"rev": "507b63021ada5fee621b6ca371c4fca9ca46f52c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -128,11 +128,11 @@
|
|||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1736044260,
|
||||
"narHash": "sha256-DTAr0mAd8AZwWgRtU9ZZFPz3DwNeoH/Oi/1QMSqc9YQ=",
|
||||
"lastModified": 1745807802,
|
||||
"narHash": "sha256-Aary9kzSx9QFgfK1CDu3ZqxhuoyHvf0F71j64gXZebA=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "c8ed24cc104ebbc218d992e208131e9f024b69f0",
|
||||
"rev": "9a6045615437787dfb9c1a3242fd75c6b6976b6b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -161,11 +161,11 @@
|
|||
"nixpkgs": "nixpkgs_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1736115332,
|
||||
"narHash": "sha256-FBG9d7e0BTFfxVdw4b5EmNll2Mv7hfRc54hbB4LrKko=",
|
||||
"lastModified": 1745848521,
|
||||
"narHash": "sha256-gNrTO3pEjmu3WiuYrUHJrTGCFw9v+qZXCFmX/Vjf5WI=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "1788ca5acd4b542b923d4757d4cfe4183cc6a92d",
|
||||
"rev": "763f1ce0dd12fe44ce6a5c6ea3f159d438571874",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
44
flake.nix
44
flake.nix
|
@ -26,7 +26,9 @@
|
|||
flake-utils.lib.eachDefaultSystem (
|
||||
system:
|
||||
let
|
||||
rustVersion = "1.83.0";
|
||||
rustVersion = "1.86.0";
|
||||
target = "x86_64-unknown-linux-musl";
|
||||
isStatic = true;
|
||||
|
||||
overlays = [
|
||||
(import rust-overlay)
|
||||
|
@ -43,7 +45,24 @@
|
|||
];
|
||||
|
||||
pkgs = import nixpkgs { inherit overlays system; };
|
||||
craneLib = (crane.mkLib pkgs).overrideToolchain pkgs.rust-toolchain;
|
||||
|
||||
basePkgs = import nixpkgs (
|
||||
{
|
||||
localSystem = system;
|
||||
overlays = [
|
||||
(import rust-overlay)
|
||||
];
|
||||
}
|
||||
// pkgs.lib.optionalAttrs isStatic { crossSystem.config = target; }
|
||||
);
|
||||
crossPkgs = (if isStatic then basePkgs.pkgsStatic else basePkgs);
|
||||
|
||||
craneLib = (crane.mkLib crossPkgs).overrideToolchain (
|
||||
p:
|
||||
p.rust-bin.stable.${rustVersion}.default.override {
|
||||
targets = [ target ];
|
||||
}
|
||||
);
|
||||
|
||||
src = pkgs.lib.fileset.toSource {
|
||||
root = ./.;
|
||||
|
@ -58,19 +77,21 @@
|
|||
commonArgs = {
|
||||
inherit src;
|
||||
|
||||
stdenv = pkgs.stdenvAdapters.useMoldLinker pkgs.stdenv;
|
||||
strictDeps = true;
|
||||
cargoArtifacts = craneLib.buildDepsOnly commonArgs;
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
clang
|
||||
mold-wrapped
|
||||
pkg-config
|
||||
];
|
||||
nativeBuildInputs = with crossPkgs.pkgsBuildHost; [ pkg-config ];
|
||||
buildInputs = with crossPkgs.pkgsHostHost; [ openssl ];
|
||||
|
||||
buildInputs = with pkgs; [
|
||||
openssl
|
||||
];
|
||||
CARGO_BUILD_TARGET = target;
|
||||
CARGO_BUILD_RUSTFLAGS = "-C target-feature=+crt-static";
|
||||
"CARGO_TARGET_${pkgs.lib.toUpper (builtins.replaceStrings [ "-" ] [ "_" ] target)}_LINKER" =
|
||||
"${crossPkgs.stdenv.cc.targetPrefix}cc";
|
||||
|
||||
OPENSSL_STATIC = true;
|
||||
OPENSSL_DIR = "${crossPkgs.openssl.dev}";
|
||||
OPENSSL_LIB_DIR = "${crossPkgs.openssl.out}/lib";
|
||||
OPENSSL_INCLUDE_DIR = "${crossPkgs.openssl.dev}/include/";
|
||||
};
|
||||
|
||||
buildCrate =
|
||||
|
@ -146,6 +167,7 @@
|
|||
rust-dev-toolchain
|
||||
sqls
|
||||
sqlx-cli
|
||||
tpm2-tools
|
||||
watchexec
|
||||
]
|
||||
++ commonArgs.buildInputs;
|
||||
|
|
|
@ -8,14 +8,14 @@ version.workspace = true
|
|||
anyhow.workspace = true
|
||||
http.workspace = true
|
||||
once_cell.workspace = true
|
||||
opentelemetry-otlp = { version = "0.27.0", features = ["grpc-tonic", "gzip-tonic", "zstd-tonic", "tls", "tls-roots", "trace"] }
|
||||
opentelemetry_sdk = { version = "0.27.1", features = ["metrics", "rt-tokio"] }
|
||||
opentelemetry-semantic-conventions = "0.27.0"
|
||||
opentelemetry-appender-tracing = { version = "0.27.0", features = ["log", "experimental_metadata_attributes"] }
|
||||
opentelemetry-resource-detectors = { version = "0.6.0" }
|
||||
opentelemetry = "0.27.1"
|
||||
tonic = "0.12.3"
|
||||
tracing-opentelemetry = "0.28.0"
|
||||
opentelemetry-otlp = { version = "0.29.0", features = ["grpc-tonic", "gzip-tonic", "zstd-tonic", "tls", "tls-roots", "trace"] }
|
||||
opentelemetry_sdk = { version = "0.29.0", features = ["metrics", "rt-tokio"] }
|
||||
opentelemetry-semantic-conventions = "0.29.0"
|
||||
opentelemetry-appender-tracing = { version = "0.29.1", features = ["log", "experimental_metadata_attributes"] }
|
||||
opentelemetry-resource-detectors = { version = "0.8.0" }
|
||||
opentelemetry = "0.29.1"
|
||||
tonic = { version = "0.13.0", features = [ "channel", "tls-native-roots" ] }
|
||||
tracing-opentelemetry = "0.30.0"
|
||||
tracing-subscriber = { version = "0.3.19", default-features = false, features = [
|
||||
"std",
|
||||
"ansi",
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use opentelemetry::{trace::TracerProvider as _, KeyValue};
|
||||
use opentelemetry_otlp::{WithExportConfig, WithTonicConfig};
|
||||
use opentelemetry::trace::TracerProvider;
|
||||
use opentelemetry::KeyValue;
|
||||
use opentelemetry_otlp::WithExportConfig;
|
||||
use opentelemetry_sdk::{
|
||||
metrics::{MeterProviderBuilder, PeriodicReader, SdkMeterProvider},
|
||||
propagation::TraceContextPropagator,
|
||||
runtime,
|
||||
trace::{RandomIdGenerator, Sampler, TracerProvider},
|
||||
trace::{RandomIdGenerator, Sampler, SdkTracerProvider},
|
||||
Resource,
|
||||
};
|
||||
use opentelemetry_semantic_conventions as semcov;
|
||||
|
@ -13,15 +13,11 @@ use tracing_opentelemetry::{MetricsLayer, OpenTelemetryLayer};
|
|||
use tracing_subscriber::layer::SubscriberExt;
|
||||
use tracing_subscriber::util::SubscriberInitExt;
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
// Construct MeterProvider for MetricsLayer
|
||||
fn init_meter_provider(otel_endpoint: &String, resource: Resource) -> Result<SdkMeterProvider> {
|
||||
let exporter = opentelemetry_otlp::MetricExporter::builder()
|
||||
.with_tonic()
|
||||
.with_endpoint(otel_endpoint)
|
||||
.with_tls_config(tonic::transport::ClientTlsConfig::new().with_native_roots())
|
||||
.with_compression(opentelemetry_otlp::Compression::Gzip)
|
||||
.with_temporality(opentelemetry_sdk::metrics::Temporality::default())
|
||||
.build()
|
||||
.map_err(|e| anyhow!("Error creating OTLP metric exporter: {:?}", e))?;
|
||||
|
@ -29,7 +25,7 @@ fn init_meter_provider(otel_endpoint: &String, resource: Resource) -> Result<Sdk
|
|||
let meter_provider = MeterProviderBuilder::default()
|
||||
.with_resource(resource)
|
||||
.with_reader(
|
||||
PeriodicReader::builder(exporter, runtime::Tokio)
|
||||
PeriodicReader::builder(exporter)
|
||||
.with_interval(std::time::Duration::from_secs(10))
|
||||
.build(),
|
||||
)
|
||||
|
@ -41,22 +37,20 @@ fn init_meter_provider(otel_endpoint: &String, resource: Resource) -> Result<Sdk
|
|||
}
|
||||
|
||||
// Construct TracerProvider for OpenTelemetryLayer
|
||||
fn init_tracer_provider(otel_endpoint: &String, resource: Resource) -> Result<TracerProvider> {
|
||||
fn init_tracer_provider(otel_endpoint: &String, resource: Resource) -> Result<SdkTracerProvider> {
|
||||
let exporter = opentelemetry_otlp::SpanExporter::builder()
|
||||
.with_tonic()
|
||||
.with_tls_config(tonic::transport::ClientTlsConfig::new().with_native_roots())
|
||||
.with_compression(opentelemetry_otlp::Compression::Gzip)
|
||||
.with_endpoint(otel_endpoint)
|
||||
.build()
|
||||
.map_err(|e| anyhow!("Error creating OTLP span exporter: {:?}", e))?;
|
||||
|
||||
let tracer_provider = opentelemetry_sdk::trace::TracerProvider::builder()
|
||||
let tracer_provider = SdkTracerProvider::builder()
|
||||
.with_sampler(Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased(
|
||||
1.0,
|
||||
))))
|
||||
.with_resource(resource)
|
||||
.with_id_generator(RandomIdGenerator::default())
|
||||
.with_batch_exporter(exporter, opentelemetry_sdk::runtime::Tokio)
|
||||
.with_batch_exporter(exporter)
|
||||
.build();
|
||||
|
||||
Ok(tracer_provider)
|
||||
|
@ -65,22 +59,19 @@ fn init_tracer_provider(otel_endpoint: &String, resource: Resource) -> Result<Tr
|
|||
// Initialize tracing-subscriber and return TracingGuard for opentelemetry-related termination processing
|
||||
pub fn init_tracing(otel_endpoint: Option<&String>, log_stderr: bool) -> Result<TracingGuard> {
|
||||
let resource = {
|
||||
let r = Resource::new([KeyValue::new(
|
||||
semcov::resource::SERVICE_VERSION,
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
)]);
|
||||
|
||||
let detected = Resource::from_detectors(
|
||||
Duration::from_secs(5),
|
||||
vec![
|
||||
let r = Resource::builder()
|
||||
.with_attribute(KeyValue::new(
|
||||
semcov::resource::SERVICE_VERSION,
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
))
|
||||
.with_detectors(&[
|
||||
Box::new(opentelemetry_sdk::resource::SdkProvidedResourceDetector),
|
||||
Box::new(opentelemetry_sdk::resource::EnvResourceDetector::new()),
|
||||
Box::new(opentelemetry_resource_detectors::OsResourceDetector),
|
||||
Box::new(opentelemetry_resource_detectors::ProcessResourceDetector),
|
||||
Box::new(opentelemetry_sdk::resource::TelemetryResourceDetector),
|
||||
],
|
||||
);
|
||||
r.merge(&detected)
|
||||
]);
|
||||
r.build()
|
||||
};
|
||||
|
||||
let env_filter = tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
|
@ -126,16 +117,14 @@ pub fn init_tracing(otel_endpoint: Option<&String>, log_stderr: bool) -> Result<
|
|||
|
||||
pub struct TracingGuard {
|
||||
meter_provider: Option<SdkMeterProvider>,
|
||||
tracer_provider: Option<TracerProvider>,
|
||||
tracer_provider: Option<SdkTracerProvider>,
|
||||
}
|
||||
|
||||
impl Drop for TracingGuard {
|
||||
fn drop(&mut self) {
|
||||
if let Some(tracer_provider) = &self.tracer_provider {
|
||||
for result in tracer_provider.force_flush() {
|
||||
if let Err(err) = result {
|
||||
eprintln!("{err:?}");
|
||||
}
|
||||
if let Err(err) = tracer_provider.force_flush() {
|
||||
eprintln!("{err:?}");
|
||||
}
|
||||
if let Err(err) = tracer_provider.shutdown() {
|
||||
eprintln!("{err:?}");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue