generated from Patagia/template-nix
This commit is contained in:
parent
8e99ab4555
commit
bb277591e2
19 changed files with 1679 additions and 56 deletions
1
hostd/.gitignore
vendored
Normal file
1
hostd/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/target
|
23
hostd/Cargo.toml
Normal file
23
hostd/Cargo.toml
Normal file
|
@ -0,0 +1,23 @@
|
|||
[package]
|
||||
name = "hostd"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
tokio.workspace = true
|
||||
sqlx = { version = "0.8.3", default-features = false, features = [
|
||||
"macros", "migrate", "postgres", "runtime-tokio", "tls-rustls", "time", "uuid"
|
||||
] }
|
||||
dropshot.workspace = true
|
||||
clap.workspace = true
|
||||
slog.workspace = true
|
||||
slog-async.workspace = true
|
||||
tracing-slog.workspace = true
|
||||
tracing.workspace = true
|
||||
trace-request = { path = "../trace-request" }
|
||||
schemars.workspace = true
|
||||
serde.workspace = true
|
||||
http.workspace = true
|
||||
zbus_systemd = { version = "0.25701.0", features = ["hostname1", "sysupdate1", "network1", "portable1", "resolve1", "systemd1"] }
|
||||
zbus = "5.4.0"
|
17
hostd/src/api.rs
Normal file
17
hostd/src/api.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
use anyhow::Result;
|
||||
use dropshot::ApiDescription;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::context::ControllerContext;
|
||||
use crate::machine;
|
||||
use crate::sysupdate;
|
||||
|
||||
type ControllerApiDescription = ApiDescription<Arc<ControllerContext>>;
|
||||
|
||||
pub fn api() -> Result<ControllerApiDescription> {
|
||||
let mut api = ControllerApiDescription::new();
|
||||
api.register(machine::describe)?;
|
||||
api.register(sysupdate::list_versions)?;
|
||||
Ok(api)
|
||||
}
|
75
hostd/src/bin/hostd-controller.rs
Normal file
75
hostd/src/bin/hostd-controller.rs
Normal file
|
@ -0,0 +1,75 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
|
||||
use clap::Parser;
|
||||
use dropshot::{ConfigDropshot, ServerBuilder};
|
||||
use slog::Drain;
|
||||
use std::net::SocketAddr;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use tracing_slog::TracingSlogDrain;
|
||||
|
||||
use hostd::api;
|
||||
use hostd::context::ControllerContext;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Cli {
|
||||
#[arg(
|
||||
long = "telemetry-otlp-endpoint",
|
||||
default_value = "http://localhost:4317",
|
||||
env = "OTEL_EXPORTER_OTLP_ENDPOINT"
|
||||
)]
|
||||
otlp_endpoint: Option<String>,
|
||||
|
||||
#[arg(
|
||||
long = "log-stderr",
|
||||
short = 'v',
|
||||
default_value = "false",
|
||||
env = "LOG_TO_STDERR"
|
||||
)]
|
||||
log_stderr: bool,
|
||||
|
||||
#[arg(
|
||||
long = "listen-address",
|
||||
default_value = "127.0.0.1:9478",
|
||||
env = "LISTEN_ADDRESS"
|
||||
)]
|
||||
listen_address: String,
|
||||
|
||||
#[arg(
|
||||
long = "database-url",
|
||||
default_value = "postgresql://localhost/patagia",
|
||||
env = "DATABASE_URL"
|
||||
)]
|
||||
database_url: Option<String>,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let args = Cli::parse();
|
||||
|
||||
let config = ConfigDropshot {
|
||||
bind_address: SocketAddr::from_str(&args.listen_address).unwrap(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let logger = {
|
||||
let level_drain = slog::LevelFilter(TracingSlogDrain, slog::Level::Debug).fuse();
|
||||
let async_drain = slog_async::Async::new(level_drain).build().fuse();
|
||||
slog::Logger::root(async_drain, slog::o!())
|
||||
};
|
||||
|
||||
let dbus = zbus::Connection::system().await.unwrap();
|
||||
let ctx = ControllerContext::new(dbus);
|
||||
|
||||
let api = api::api()?;
|
||||
|
||||
println!("Listening on http://{}", config.bind_address);
|
||||
|
||||
ServerBuilder::new(api, Arc::new(ctx), logger)
|
||||
.config(config)
|
||||
.start()
|
||||
.map_err(|e| anyhow!("Error starting server: {:?}", e))?
|
||||
.await
|
||||
.map_err(|e| anyhow!(e))
|
||||
}
|
9
hostd/src/context.rs
Normal file
9
hostd/src/context.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
pub struct ControllerContext {
|
||||
pub dbus: zbus::Connection,
|
||||
}
|
||||
|
||||
impl ControllerContext {
|
||||
pub fn new(dbus: zbus::Connection) -> ControllerContext {
|
||||
ControllerContext { dbus }
|
||||
}
|
||||
}
|
4
hostd/src/lib.rs
Normal file
4
hostd/src/lib.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
pub mod api;
|
||||
pub mod context;
|
||||
pub mod machine;
|
||||
pub mod sysupdate;
|
43
hostd/src/machine.rs
Normal file
43
hostd/src/machine.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
use dropshot::{endpoint, HttpError, HttpResponseOk, RequestContext};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use std::sync::Arc;
|
||||
use trace_request::trace_request;
|
||||
|
||||
use crate::context::ControllerContext;
|
||||
|
||||
/// Machine information
|
||||
#[derive(Serialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct MachineInfo {
|
||||
machine_id: String,
|
||||
}
|
||||
|
||||
/// Fetch machine info
|
||||
#[endpoint {
|
||||
method = GET,
|
||||
path = "/machine_info",
|
||||
}]
|
||||
#[trace_request]
|
||||
pub async fn describe(
|
||||
rqctx: RequestContext<Arc<ControllerContext>>,
|
||||
) -> Result<HttpResponseOk<MachineInfo>, HttpError> {
|
||||
let hostnamed = zbus_systemd::hostname1::HostnamedProxy::new(&rqctx.context().dbus)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let machine_id = hostnamed
|
||||
.machine_id()
|
||||
.await
|
||||
.map_err(|e| match e {
|
||||
err => HttpError::for_internal_error(format!("Error: {}", err)),
|
||||
})?
|
||||
// convert bytes to hex string
|
||||
.iter()
|
||||
.map(|&b| format!("{:02x}", b))
|
||||
.collect();
|
||||
|
||||
let machine_info = MachineInfo { machine_id };
|
||||
|
||||
Ok(HttpResponseOk(machine_info))
|
||||
}
|
52
hostd/src/sysupdate.rs
Normal file
52
hostd/src/sysupdate.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
use dropshot::{endpoint, HttpError, HttpResponseOk, RequestContext};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use std::sync::Arc;
|
||||
use trace_request::trace_request;
|
||||
|
||||
use crate::context::ControllerContext;
|
||||
|
||||
const SYSUPDATE_HOST_PATH: &str = "/org/freedesktop/sysupdate1/target/host";
|
||||
|
||||
#[derive(Serialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct SysUpdate {
|
||||
current_version: String,
|
||||
versions: Vec<String>,
|
||||
}
|
||||
|
||||
#[endpoint {
|
||||
method = GET,
|
||||
path = "/list_versions",
|
||||
}]
|
||||
#[trace_request]
|
||||
pub async fn list_versions(
|
||||
rqctx: RequestContext<Arc<ControllerContext>>,
|
||||
) -> Result<HttpResponseOk<SysUpdate>, HttpError> {
|
||||
let sysupdate_target = zbus_systemd::sysupdate1::TargetProxy::builder(&rqctx.context().dbus)
|
||||
.path(SYSUPDATE_HOST_PATH)
|
||||
.unwrap()
|
||||
.build()
|
||||
.await
|
||||
.map_err(|e| match e {
|
||||
err => HttpError::for_internal_error(format!("Error: {}", err)),
|
||||
})?;
|
||||
|
||||
let versions = sysupdate_target.list(0).await.map_err(|e| match e {
|
||||
err => {
|
||||
println!("Error: {}", err);
|
||||
HttpError::for_internal_error(format!("Error: {}", err))
|
||||
}
|
||||
})?;
|
||||
|
||||
let current_version = sysupdate_target.get_version().await.map_err(|e| match e {
|
||||
err => HttpError::for_internal_error(format!("Error: {}", err)),
|
||||
})?;
|
||||
|
||||
let sysupdate = SysUpdate {
|
||||
versions,
|
||||
current_version,
|
||||
};
|
||||
|
||||
Ok(HttpResponseOk(sysupdate))
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue