generated from Patagia/template-nix
This commit is contained in:
parent
ac6a53fac9
commit
1cdb21b994
14 changed files with 266 additions and 78 deletions
2
.cargo/config.toml
Normal file
2
.cargo/config.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
[alias]
|
||||
xtask = "run --package xtask --quiet --"
|
|
@ -6,6 +6,7 @@ when:
|
|||
|
||||
steps:
|
||||
check:
|
||||
image: docker.io/nixpkgs/nix-flakes:nixos-24.11
|
||||
image: docker.io/nixpkgs/nix-flakes:nixos-24.05
|
||||
commands:
|
||||
- nix flake check
|
||||
- nix develop -c just check
|
||||
|
|
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -2457,6 +2457,16 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xtask"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"patagia-controller",
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
|
|
|
@ -3,7 +3,14 @@ resolver = "2"
|
|||
members = [
|
||||
"agent",
|
||||
"controller",
|
||||
"xtask",
|
||||
]
|
||||
default-members = [
|
||||
"agent",
|
||||
"controller",
|
||||
"xtask",
|
||||
]
|
||||
|
||||
|
||||
[workspace.package]
|
||||
version = "0.2.0"
|
||||
|
@ -30,6 +37,7 @@ opentelemetry_sdk = { version = "0.27.1", features = ["metrics", "rt-tokio"] }
|
|||
opentelemetry-semantic-conventions = "0.27.0"
|
||||
opentelemetry-stdout = "0.27.0"
|
||||
schemars = "0.8.21"
|
||||
semver = "1.0.23"
|
||||
serde = "1.0.215"
|
||||
slog = "2.7.0"
|
||||
slog-async = "2.8.0"
|
||||
|
|
84
api.json
Normal file
84
api.json
Normal file
|
@ -0,0 +1,84 @@
|
|||
{
|
||||
"openapi": "3.0.3",
|
||||
"info": {
|
||||
"title": "Patagia Controller",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"paths": {
|
||||
"/version": {
|
||||
"get": {
|
||||
"summary": "Fetch version info.",
|
||||
"operationId": "api_version",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "successful operation",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/VersionInfo"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"4XX": {
|
||||
"$ref": "#/components/responses/Error"
|
||||
},
|
||||
"5XX": {
|
||||
"$ref": "#/components/responses/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"Error": {
|
||||
"description": "Error information from a response.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"error_code": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"request_id": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"message",
|
||||
"request_id"
|
||||
]
|
||||
},
|
||||
"VersionInfo": {
|
||||
"description": "Version and build information",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"version"
|
||||
]
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"Error": {
|
||||
"description": "Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
15
controller/src/api.rs
Normal file
15
controller/src/api.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
use anyhow::Result;
|
||||
use dropshot::ApiDescription;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::context::ControllerContext;
|
||||
use crate::version;
|
||||
|
||||
type ControllerApiDescription = ApiDescription<Arc<ControllerContext>>;
|
||||
|
||||
pub fn api() -> Result<ControllerApiDescription> {
|
||||
let mut api = ControllerApiDescription::new();
|
||||
api.register(version::api_version)?;
|
||||
Ok(api)
|
||||
}
|
|
@ -1,67 +1,22 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use clap::Parser;
|
||||
use dropshot::{
|
||||
endpoint, ApiDescription, ConfigDropshot, HttpError, HttpResponseOk, RequestContext,
|
||||
ServerBuilder,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use dropshot::{ConfigDropshot, ServerBuilder};
|
||||
|
||||
use slog::Drain;
|
||||
use tracing::Instrument;
|
||||
use tracing_slog::TracingSlogDrain;
|
||||
|
||||
use std::net::SocketAddr;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use patagia_controller::api;
|
||||
use patagia_controller::context::ControllerContext;
|
||||
use patagia_controller::instrumentation;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Cli {}
|
||||
|
||||
/// Represents a project in our API.
|
||||
#[derive(Serialize, JsonSchema)]
|
||||
struct VersionInfo {
|
||||
name: String,
|
||||
version: String,
|
||||
}
|
||||
|
||||
/// Fetch version info.
|
||||
#[endpoint {
|
||||
method = GET,
|
||||
path = "/version",
|
||||
}]
|
||||
#[tracing::instrument(
|
||||
skip(rqctx),
|
||||
fields(
|
||||
http.method=rqctx.request.method().as_str(),
|
||||
http.path=rqctx.request.uri().path(),
|
||||
http.remote_ip=rqctx.request.remote_addr().ip().to_string(),
|
||||
request_id = rqctx.request_id,
|
||||
),
|
||||
err(Debug),
|
||||
)]
|
||||
async fn api_version(
|
||||
rqctx: RequestContext<Arc<()>>,
|
||||
) -> Result<HttpResponseOk<VersionInfo>, HttpError> {
|
||||
let ver = VersionInfo {
|
||||
name: env!("CARGO_PKG_NAME").to_string(),
|
||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
};
|
||||
|
||||
tracing::info_span!("Hello, span!");
|
||||
|
||||
async move {
|
||||
tracing::info!("Someone made a request to /version");
|
||||
|
||||
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
|
||||
}
|
||||
.instrument(tracing::info_span!("Let's do the thing...."))
|
||||
.await;
|
||||
Ok(HttpResponseOk(ver))
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let _args = Cli::parse();
|
||||
|
@ -69,15 +24,6 @@ async fn main() -> Result<()> {
|
|||
|
||||
tracing::info!("Patagia Controller");
|
||||
|
||||
tracing::debug!("Starting server");
|
||||
|
||||
tracing::error!(name: "my-event-name", target: "my-system", event_id = 20, user_name = "otel", user_email = "otel@opentelemetry.io", message = "This is an example message");
|
||||
|
||||
foo().await;
|
||||
|
||||
let mut api = ApiDescription::new();
|
||||
api.register(api_version).unwrap();
|
||||
|
||||
let config = ConfigDropshot {
|
||||
bind_address: SocketAddr::from_str("0.0.0.0:9474").unwrap(),
|
||||
..Default::default()
|
||||
|
@ -90,22 +36,12 @@ async fn main() -> Result<()> {
|
|||
slog::Logger::root(async_drain, slog::o!())
|
||||
};
|
||||
|
||||
ServerBuilder::new(api, Arc::new(()), logger)
|
||||
let ctx = ControllerContext::new();
|
||||
let api = api::api()?;
|
||||
ServerBuilder::new(api, Arc::new(ctx), logger)
|
||||
.config(config)
|
||||
.start()
|
||||
.map_err(|e| anyhow!("Error starting server: {:?}", e))?
|
||||
.await
|
||||
.map_err(|e| anyhow!(e))
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
async fn foo() {
|
||||
tracing::info!(
|
||||
monotonic_counter.foo = 1_u64,
|
||||
key_1 = "bar",
|
||||
key_2 = 10,
|
||||
"handle foo",
|
||||
);
|
||||
|
||||
tracing::info!(histogram.baz = 10, "histogram example",);
|
||||
}
|
||||
|
|
13
controller/src/context.rs
Normal file
13
controller/src/context.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
pub struct ControllerContext {}
|
||||
|
||||
impl ControllerContext {
|
||||
pub fn new() -> ControllerContext {
|
||||
ControllerContext {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ControllerContext {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
|
@ -1 +1,5 @@
|
|||
pub mod api;
|
||||
pub mod context;
|
||||
pub mod instrumentation;
|
||||
|
||||
mod version;
|
||||
|
|
49
controller/src/version.rs
Normal file
49
controller/src/version.rs
Normal file
|
@ -0,0 +1,49 @@
|
|||
use dropshot::{endpoint, HttpError, HttpResponseOk, RequestContext};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use tracing::Instrument;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::context::ControllerContext;
|
||||
|
||||
/// Version and build information
|
||||
#[derive(Serialize, JsonSchema)]
|
||||
struct VersionInfo {
|
||||
name: String,
|
||||
version: String,
|
||||
}
|
||||
|
||||
/// Fetch version info.
|
||||
#[endpoint {
|
||||
method = GET,
|
||||
path = "/version",
|
||||
}]
|
||||
#[tracing::instrument(
|
||||
skip(rqctx),
|
||||
fields(
|
||||
http.method=rqctx.request.method().as_str(),
|
||||
http.path=rqctx.request.uri().path(),
|
||||
http.remote_ip=rqctx.request.remote_addr().ip().to_string(),
|
||||
request_id = rqctx.request_id,
|
||||
),
|
||||
err(Debug),
|
||||
)]
|
||||
pub async fn api_version(
|
||||
rqctx: RequestContext<Arc<ControllerContext>>,
|
||||
) -> Result<HttpResponseOk<VersionInfo>, HttpError> {
|
||||
let ver = VersionInfo {
|
||||
name: env!("CARGO_PKG_NAME").to_string(),
|
||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
};
|
||||
|
||||
tracing::info_span!("Hello, span!");
|
||||
|
||||
async move {
|
||||
tracing::info!("Someone made a request to /version");
|
||||
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
|
||||
}
|
||||
.instrument(tracing::info_span!("Let's do the thing...."))
|
||||
.await;
|
||||
Ok(HttpResponseOk(ver))
|
||||
}
|
14
flake.nix
14
flake.nix
|
@ -91,6 +91,7 @@
|
|||
./Cargo.lock
|
||||
(craneLib.fileset.commonCargoSources ./agent)
|
||||
(craneLib.fileset.commonCargoSources ./controller)
|
||||
(craneLib.fileset.commonCargoSources ./xtask)
|
||||
(craneLib.fileset.commonCargoSources crate)
|
||||
];
|
||||
};
|
||||
|
@ -113,16 +114,24 @@
|
|||
}
|
||||
);
|
||||
|
||||
xtask = craneLib.buildPackage (
|
||||
individualCrateArgs
|
||||
// {
|
||||
pname = "xtask";
|
||||
cargoExtraArgs = "-p xtask";
|
||||
src = fileSetForCrate ./xtask;
|
||||
}
|
||||
);
|
||||
in
|
||||
{
|
||||
# `nix build`
|
||||
packages = {
|
||||
inherit patagia-agent patagia-controller;
|
||||
inherit patagia-agent patagia-controller xtask;
|
||||
};
|
||||
|
||||
# Tests
|
||||
checks = {
|
||||
inherit patagia-agent patagia-controller;
|
||||
inherit patagia-agent patagia-controller xtask;
|
||||
|
||||
clippy = craneLib.cargoClippy (
|
||||
commonArgs
|
||||
|
@ -162,6 +171,7 @@
|
|||
cargo-watch
|
||||
hyperfine
|
||||
just
|
||||
libsodium
|
||||
rust-dev-toolchain
|
||||
watchexec
|
||||
];
|
||||
|
|
19
justfile
19
justfile
|
@ -12,10 +12,6 @@ run-controller $RUST_LOG="debug,h2=info,hyper_util=info,tower=info":
|
|||
dev-controller:
|
||||
watchexec --clear --restart --stop-signal INT --debounce 300ms -- just run-controller
|
||||
|
||||
# Run all tests
|
||||
check:
|
||||
nix flake check
|
||||
|
||||
# Lint all source code
|
||||
lint:
|
||||
cargo clippy
|
||||
|
@ -39,3 +35,18 @@ update-nix:
|
|||
# Find unused dependencies with cargo machete
|
||||
machete:
|
||||
cargo machete
|
||||
|
||||
# Generate OpenAPI spec
|
||||
open-api:
|
||||
cargo xtask open-api
|
||||
|
||||
# Run all tests
|
||||
check: check-nix check-openapi
|
||||
|
||||
# check-nix
|
||||
check-nix:
|
||||
nix flake check
|
||||
|
||||
# Check if OpenAPI spec is valid
|
||||
check-openapi:
|
||||
just open-api | diff -u api.json -
|
||||
|
|
15
xtask/Cargo.toml
Normal file
15
xtask/Cargo.toml
Normal file
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "xtask"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "xtask"
|
||||
test = false
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
clap = { workspace = true, features = ["derive"] }
|
||||
patagia-controller = { path = "../controller" }
|
||||
semver.workspace = true
|
30
xtask/src/main.rs
Normal file
30
xtask/src/main.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
|
||||
use patagia_controller::api;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(name = "cargo xtask", about = "Extra tasks for Patagia Controller")]
|
||||
enum Xtask {
|
||||
/// Generate OpenAPI spec
|
||||
OpenApi,
|
||||
}
|
||||
|
||||
fn gen_openapi() -> Result<()> {
|
||||
let api = api::api()?;
|
||||
let openapi = api.openapi("Patagia Controller", semver::Version::new(1, 0, 0));
|
||||
openapi.write(&mut std::io::stdout().lock())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let xtask = Xtask::parse();
|
||||
|
||||
match xtask {
|
||||
Xtask::OpenApi => {
|
||||
gen_openapi()?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in a new issue