Compare commits

...

1 commit

19 changed files with 1679 additions and 56 deletions

719
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -4,8 +4,10 @@ members = [
"agent",
"controller",
"instrumentation",
"hostd",
"trace-request",
"xtask",
"systemd-ipc",
]
default-members = [
"agent",
@ -44,7 +46,5 @@ slog = "2.7.0"
slog-async = "2.8.0"
tokio = { version = "1.43.0", features = ["full"] }
tracing = "0.1.41"
tracing-core = "0.1.33"
tracing-chrome = "0.7.2"
tracing-slog = { git = "https://github.com/oxidecomputer/tracing-slog", default-features = false }
uuid = { version = "1", features = [ "serde", "v4" ] }

1
hostd/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

23
hostd/Cargo.toml Normal file
View 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
View 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)
}

View 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
View 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
View file

@ -0,0 +1,4 @@
pub mod api;
pub mod context;
pub mod machine;
pub mod sysupdate;

43
hostd/src/machine.rs Normal file
View 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
View 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))
}

1
systemd-ipc/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

17
systemd-ipc/Cargo.toml Normal file
View file

@ -0,0 +1,17 @@
[package]
name = "systemd-ipc"
version.workspace = true
edition.workspace = true
[dependencies]
serde.workspace = true
serde_derive = "1.0.217"
serde_json = "1.0.135"
varlink = "11.0.1"
[build-dependencies]
varlink_generator = "10.1.0"
walkdir = "2.5.0"
[package.metadata.cargo-machete]
ignored = ["serde"]

12
systemd-ipc/build.rs Normal file
View file

@ -0,0 +1,12 @@
extern crate varlink_generator;
use walkdir::WalkDir;
fn main() {
println!("cargo:rerun-if-changed=src/*.varlink");
for entry in WalkDir::new("src").into_iter().filter_map(|e| e.ok()) {
if entry.file_name().to_str().unwrap().ends_with(".varlink") {
varlink_generator::cargo_build_tosource(&entry.path().display().to_string(), true);
}
}
}

3
systemd-ipc/src/addrs.rs Normal file
View file

@ -0,0 +1,3 @@
#[allow(dead_code)]
pub const SYSTEMD_HOSTNAME: &str = "unix:/run/systemd/io.systemd.Hostname";
pub const SYSTEMD_BOOTCONTROL: &str = "unix:/run/systemd/io.systemd.BootControl";

View file

@ -0,0 +1,70 @@
# Boot Loader control APIs
interface io.systemd.BootControl
# The type of a boot entry
type BootEntryType(
# Boot Loader Specification Type #1 entries (.conf files)
type1,
# Boot Loader Specification Type #2 entries (UKIs)
type2,
# Additional entries reported by boot loader
loader,
# Automatically generated entries
auto
)
# A structure encapsulating a boot entry
type BootEntry(
type: BootEntryType,
# The string identifier of the entry
id: ?string,
path: ?string,
root: ?string,
title: ?string,
showTitle: ?string,
sortKey: ?string,
version: ?string,
machineId: ?string,
architecture: ?string,
options: ?string,
linux: ?string,
efi: ?string,
initrd: ?[]string,
devicetree: ?string,
devicetreeOverlay: ?[]string,
# Indicates whether the boot loader reported this entry on the current boot
isReported: bool,
# Indicates the number of tries left for this boot entry before it is assumed to be not working.
triesLeft: ?int,
# Indicates the number of unsuccessful tries already made for this boot entry.
triesDone: ?int,
# Indicates whether this entry is the default entry.
isDefault: ?bool,
# Indicates whether this entry has been booted.
isSelected: ?bool
)
# Enumerates boot entries. Method call must be called with 'more' flag set. Each response returns one entry. If no entries are defined returns the NoSuchBootEntry error.
# [Requires 'more' flag]
method ListBootEntries() -> (
# A boot menu entry structure
entry: ?BootEntry
)
# Sets the reboot-to-firmware-UI flag of the firmware, if this concept exists. Returns the RebootToFirmwareNotSupported error if not.
method SetRebootToFirmware(
# The new value of the reboot-to-firmware-UI flag
state: bool
) -> ()
# Gets the current state of the reboot-to-firmware-UI flag of the firmware, if this concept exists. Returns the RebootToFirmwareNotSupported error if not.
method GetRebootToFirmware() -> (
# The current state of the reboot-to-firmware-UI flag
state: bool
)
# SetRebootToFirmware() and GetRebootToFirmware() return this if the firmware does not actually support the reboot-to-firmware-UI concept.
error RebootToFirmwareNotSupported()
# No boot entry defined.
error NoSuchBootEntry()

View file

@ -0,0 +1,32 @@
interface io.systemd.Hostname
method Describe() -> (
Hostname: string,
StaticHostname: ?string,
PrettyHostname: ?string,
DefaultHostname: ?string,
HostnameSource: string,
IconName: ?string,
Chassis: ?string,
Deployment: ?string,
Location: ?string,
KernelName: string,
KernelRelease: string,
KernelVersion: string,
OperatingSystemPrettyName: ?string,
OperatingSystemCPEName: ?string,
OperatingSystemHomeURL: ?string,
OperatingSystemSupportEnd: ?int,
OperatingSystemReleaseData: ?[]string,
MachineInformationData: ?[]string,
HardwareVendor: ?string,
HardwareModel: ?string,
HardwareSerial: ?string,
FirmwareVersion: ?string,
FirmwareVendor: ?string,
FirmwareDate: ?int,
MachineID: string,
BootID: string,
ProductUUID: ?string,
VSockCID: ?int
)

View file

@ -0,0 +1,356 @@
#![doc = "This file was automatically generated by the varlink rust generator"]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
use serde_derive::{Deserialize, Serialize};
use std::io::BufRead;
use std::sync::{Arc, RwLock};
use varlink::{self, CallTrait};
#[allow(dead_code)]
#[derive(Clone, PartialEq, Debug)]
#[allow(clippy::enum_variant_names)]
pub enum ErrorKind {
Varlink_Error,
VarlinkReply_Error,
NoSuchBootEntry(Option<NoSuchBootEntry_Args>),
RebootToFirmwareNotSupported(Option<RebootToFirmwareNotSupported_Args>),
}
impl ::std::fmt::Display for ErrorKind {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
match self {
ErrorKind::Varlink_Error => write!(f, "Varlink Error"),
ErrorKind::VarlinkReply_Error => write!(f, "Varlink error reply"),
ErrorKind::NoSuchBootEntry(v) => {
write!(f, "io.systemd.BootControl.NoSuchBootEntry: {:#?}", v)
}
ErrorKind::RebootToFirmwareNotSupported(v) => write!(
f,
"io.systemd.BootControl.RebootToFirmwareNotSupported: {:#?}",
v
),
}
}
}
pub struct Error(
pub ErrorKind,
pub Option<Box<dyn std::error::Error + 'static + Send + Sync>>,
pub Option<&'static str>,
);
impl Error {
#[allow(dead_code)]
pub fn kind(&self) -> &ErrorKind {
&self.0
}
}
impl From<ErrorKind> for Error {
fn from(e: ErrorKind) -> Self {
Error(e, None, None)
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.1
.as_ref()
.map(|e| e.as_ref() as &(dyn std::error::Error + 'static))
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, f)
}
}
impl std::fmt::Debug for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use std::error::Error as StdError;
if let Some(ref o) = self.2 {
std::fmt::Display::fmt(o, f)?;
}
std::fmt::Debug::fmt(&self.0, f)?;
if let Some(e) = self.source() {
std::fmt::Display::fmt("\nCaused by:\n", f)?;
std::fmt::Debug::fmt(&e, f)?;
}
Ok(())
}
}
#[allow(dead_code)]
pub type Result<T> = std::result::Result<T, Error>;
impl From<varlink::Error> for Error {
fn from(e: varlink::Error) -> Self {
match e.kind() {
varlink::ErrorKind::VarlinkErrorReply(r) => Error(
ErrorKind::from(r),
Some(Box::from(e)),
Some(concat!(file!(), ":", line!(), ": ")),
),
_ => Error(
ErrorKind::Varlink_Error,
Some(Box::from(e)),
Some(concat!(file!(), ":", line!(), ": ")),
),
}
}
}
#[allow(dead_code)]
impl Error {
pub fn source_varlink_kind(&self) -> Option<&varlink::ErrorKind> {
use std::error::Error as StdError;
let mut s: &dyn StdError = self;
while let Some(c) = s.source() {
let k = self
.source()
.and_then(|e| e.downcast_ref::<varlink::Error>())
.map(|e| e.kind());
if k.is_some() {
return k;
}
s = c;
}
None
}
}
impl From<&varlink::Reply> for ErrorKind {
#[allow(unused_variables)]
fn from(e: &varlink::Reply) -> Self {
match e {
varlink::Reply {
error: Some(ref t), ..
} if t == "io.systemd.BootControl.NoSuchBootEntry" => match e {
varlink::Reply {
parameters: Some(p),
..
} => match serde_json::from_value(p.clone()) {
Ok(v) => ErrorKind::NoSuchBootEntry(v),
Err(_) => ErrorKind::NoSuchBootEntry(None),
},
_ => ErrorKind::NoSuchBootEntry(None),
},
varlink::Reply {
error: Some(ref t), ..
} if t == "io.systemd.BootControl.RebootToFirmwareNotSupported" => match e {
varlink::Reply {
parameters: Some(p),
..
} => match serde_json::from_value(p.clone()) {
Ok(v) => ErrorKind::RebootToFirmwareNotSupported(v),
Err(_) => ErrorKind::RebootToFirmwareNotSupported(None),
},
_ => ErrorKind::RebootToFirmwareNotSupported(None),
},
_ => ErrorKind::VarlinkReply_Error,
}
}
}
pub trait VarlinkCallError: varlink::CallTrait {
fn reply_no_such_boot_entry(&mut self) -> varlink::Result<()> {
self.reply_struct(varlink::Reply::error(
"io.systemd.BootControl.NoSuchBootEntry",
None,
))
}
fn reply_reboot_to_firmware_not_supported(&mut self) -> varlink::Result<()> {
self.reply_struct(varlink::Reply::error(
"io.systemd.BootControl.RebootToFirmwareNotSupported",
None,
))
}
}
impl<'a> VarlinkCallError for varlink::Call<'a> {}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct r#BootEntry {
pub r#type: BootEntryType,
pub r#id: Option<String>,
pub r#path: Option<String>,
pub r#root: Option<String>,
pub r#title: Option<String>,
pub r#showTitle: Option<String>,
pub r#sortKey: Option<String>,
pub r#version: Option<String>,
pub r#machineId: Option<String>,
pub r#architecture: Option<String>,
pub r#options: Option<String>,
pub r#linux: Option<String>,
pub r#efi: Option<String>,
pub r#initrd: Option<Vec<String>>,
pub r#devicetree: Option<String>,
pub r#devicetreeOverlay: Option<Vec<String>>,
pub r#isReported: bool,
pub r#triesLeft: Option<i64>,
pub r#triesDone: Option<i64>,
pub r#isDefault: Option<bool>,
pub r#isSelected: Option<bool>,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub enum r#BootEntryType {
r#type1,
r#type2,
r#loader,
r#auto,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct NoSuchBootEntry_Args {}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct RebootToFirmwareNotSupported_Args {}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct GetRebootToFirmware_Reply {
pub r#state: bool,
}
impl varlink::VarlinkReply for GetRebootToFirmware_Reply {}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct GetRebootToFirmware_Args {}
pub trait Call_GetRebootToFirmware: VarlinkCallError {
fn reply(&mut self, r#state: bool) -> varlink::Result<()> {
self.reply_struct(GetRebootToFirmware_Reply { r#state }.into())
}
}
impl<'a> Call_GetRebootToFirmware for varlink::Call<'a> {}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct ListBootEntries_Reply {
#[serde(skip_serializing_if = "Option::is_none")]
pub r#entry: Option<BootEntry>,
}
impl varlink::VarlinkReply for ListBootEntries_Reply {}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct ListBootEntries_Args {}
pub trait Call_ListBootEntries: VarlinkCallError {
fn reply(&mut self, r#entry: Option<BootEntry>) -> varlink::Result<()> {
self.reply_struct(ListBootEntries_Reply { r#entry }.into())
}
}
impl<'a> Call_ListBootEntries for varlink::Call<'a> {}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct SetRebootToFirmware_Reply {}
impl varlink::VarlinkReply for SetRebootToFirmware_Reply {}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct SetRebootToFirmware_Args {
pub r#state: bool,
}
pub trait Call_SetRebootToFirmware: VarlinkCallError {
fn reply(&mut self) -> varlink::Result<()> {
self.reply_struct(varlink::Reply::parameters(None))
}
}
impl<'a> Call_SetRebootToFirmware for varlink::Call<'a> {}
pub trait VarlinkInterface {
fn get_reboot_to_firmware(
&self,
call: &mut dyn Call_GetRebootToFirmware,
) -> varlink::Result<()>;
fn list_boot_entries(&self, call: &mut dyn Call_ListBootEntries) -> varlink::Result<()>;
fn set_reboot_to_firmware(
&self,
call: &mut dyn Call_SetRebootToFirmware,
r#state: bool,
) -> varlink::Result<()>;
fn call_upgraded(
&self,
_call: &mut varlink::Call,
_bufreader: &mut dyn BufRead,
) -> varlink::Result<Vec<u8>> {
Ok(Vec::new())
}
}
pub trait VarlinkClientInterface {
fn get_reboot_to_firmware(
&mut self,
) -> varlink::MethodCall<GetRebootToFirmware_Args, GetRebootToFirmware_Reply, Error>;
fn list_boot_entries(
&mut self,
) -> varlink::MethodCall<ListBootEntries_Args, ListBootEntries_Reply, Error>;
fn set_reboot_to_firmware(
&mut self,
r#state: bool,
) -> varlink::MethodCall<SetRebootToFirmware_Args, SetRebootToFirmware_Reply, Error>;
}
#[allow(dead_code)]
pub struct VarlinkClient {
connection: Arc<RwLock<varlink::Connection>>,
}
impl VarlinkClient {
#[allow(dead_code)]
pub fn new(connection: Arc<RwLock<varlink::Connection>>) -> Self {
VarlinkClient { connection }
}
}
impl VarlinkClientInterface for VarlinkClient {
fn get_reboot_to_firmware(
&mut self,
) -> varlink::MethodCall<GetRebootToFirmware_Args, GetRebootToFirmware_Reply, Error> {
varlink::MethodCall::<GetRebootToFirmware_Args, GetRebootToFirmware_Reply, Error>::new(
self.connection.clone(),
"io.systemd.BootControl.GetRebootToFirmware",
GetRebootToFirmware_Args {},
)
}
fn list_boot_entries(
&mut self,
) -> varlink::MethodCall<ListBootEntries_Args, ListBootEntries_Reply, Error> {
varlink::MethodCall::<ListBootEntries_Args, ListBootEntries_Reply, Error>::new(
self.connection.clone(),
"io.systemd.BootControl.ListBootEntries",
ListBootEntries_Args {},
)
}
fn set_reboot_to_firmware(
&mut self,
r#state: bool,
) -> varlink::MethodCall<SetRebootToFirmware_Args, SetRebootToFirmware_Reply, Error> {
varlink::MethodCall::<SetRebootToFirmware_Args, SetRebootToFirmware_Reply, Error>::new(
self.connection.clone(),
"io.systemd.BootControl.SetRebootToFirmware",
SetRebootToFirmware_Args { r#state },
)
}
}
#[allow(dead_code)]
pub struct VarlinkInterfaceProxy {
inner: Box<dyn VarlinkInterface + Send + Sync>,
}
#[allow(dead_code)]
pub fn new(inner: Box<dyn VarlinkInterface + Send + Sync>) -> VarlinkInterfaceProxy {
VarlinkInterfaceProxy { inner }
}
impl varlink::Interface for VarlinkInterfaceProxy {
fn get_description(&self) -> &'static str {
"# Boot Loader control APIs\ninterface io.systemd.BootControl\n\n# The type of a boot entry\ntype BootEntryType(\n\t# Boot Loader Specification Type #1 entries (.conf files)\n\ttype1,\n\t# Boot Loader Specification Type #2 entries (UKIs)\n\ttype2,\n\t# Additional entries reported by boot loader\n\tloader,\n\t# Automatically generated entries\n\tauto\n)\n\n# A structure encapsulating a boot entry\ntype BootEntry(\n\ttype: BootEntryType,\n\t# The string identifier of the entry\n\tid: ?string,\n\tpath: ?string,\n\troot: ?string,\n\ttitle: ?string,\n\tshowTitle: ?string,\n\tsortKey: ?string,\n\tversion: ?string,\n\tmachineId: ?string,\n\tarchitecture: ?string,\n\toptions: ?string,\n\tlinux: ?string,\n\tefi: ?string,\n\tinitrd: ?[]string,\n\tdevicetree: ?string,\n\tdevicetreeOverlay: ?[]string,\n\t# Indicates whether the boot loader reported this entry on the current boot\n\tisReported: bool,\n\t# Indicates the number of tries left for this boot entry before it is assumed to be not working.\n\ttriesLeft: ?int,\n\t# Indicates the number of unsuccessful tries already made for this boot entry.\n\ttriesDone: ?int,\n\t# Indicates whether this entry is the default entry.\n\tisDefault: ?bool,\n\t# Indicates whether this entry has been booted.\n\tisSelected: ?bool\n)\n\n# Enumerates boot entries. Method call must be called with 'more' flag set. Each response returns one entry. If no entries are defined returns the NoSuchBootEntry error.\n# [Requires 'more' flag]\nmethod ListBootEntries() -> (\n\t# A boot menu entry structure\n\tentry: ?BootEntry\n)\n\n# Sets the reboot-to-firmware-UI flag of the firmware, if this concept exists. Returns the RebootToFirmwareNotSupported error if not.\nmethod SetRebootToFirmware(\n\t# The new value of the reboot-to-firmware-UI flag\n\tstate: bool\n) -> ()\n\n# Gets the current state of the reboot-to-firmware-UI flag of the firmware, if this concept exists. Returns the RebootToFirmwareNotSupported error if not.\nmethod GetRebootToFirmware() -> (\n\t# The current state of the reboot-to-firmware-UI flag\n\tstate: bool\n)\n\n# SetRebootToFirmware() and GetRebootToFirmware() return this if the firmware does not actually support the reboot-to-firmware-UI concept.\nerror RebootToFirmwareNotSupported()\n\n# No boot entry defined.\nerror NoSuchBootEntry()\n"
}
fn get_name(&self) -> &'static str {
"io.systemd.BootControl"
}
fn call_upgraded(
&self,
call: &mut varlink::Call,
bufreader: &mut dyn BufRead,
) -> varlink::Result<Vec<u8>> {
self.inner.call_upgraded(call, bufreader)
}
fn call(&self, call: &mut varlink::Call) -> varlink::Result<()> {
let req = call.request.unwrap();
match req.method.as_ref() {
"io.systemd.BootControl.GetRebootToFirmware" => self
.inner
.get_reboot_to_firmware(call as &mut dyn Call_GetRebootToFirmware),
"io.systemd.BootControl.ListBootEntries" => self
.inner
.list_boot_entries(call as &mut dyn Call_ListBootEntries),
"io.systemd.BootControl.SetRebootToFirmware" => {
if let Some(args) = req.parameters.clone() {
let args: SetRebootToFirmware_Args = match serde_json::from_value(args) {
Ok(v) => v,
Err(e) => {
let es = format!("{}", e);
let _ = call.reply_invalid_parameter(es.clone());
return Err(varlink::context!(varlink::ErrorKind::SerdeJsonDe(es)));
}
};
self.inner.set_reboot_to_firmware(
call as &mut dyn Call_SetRebootToFirmware,
args.r#state,
)
} else {
call.reply_invalid_parameter("parameters".into())
}
}
m => call.reply_method_not_found(String::from(m)),
}
}
}

View file

@ -0,0 +1,295 @@
#![doc = "This file was automatically generated by the varlink rust generator"]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
use serde_derive::{Deserialize, Serialize};
use std::io::BufRead;
use std::sync::{Arc, RwLock};
use varlink::{self, CallTrait};
#[allow(dead_code)]
#[derive(Clone, PartialEq, Debug)]
#[allow(clippy::enum_variant_names)]
pub enum ErrorKind {
Varlink_Error,
VarlinkReply_Error,
}
impl ::std::fmt::Display for ErrorKind {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
match self {
ErrorKind::Varlink_Error => write!(f, "Varlink Error"),
ErrorKind::VarlinkReply_Error => write!(f, "Varlink error reply"),
}
}
}
pub struct Error(
pub ErrorKind,
pub Option<Box<dyn std::error::Error + 'static + Send + Sync>>,
pub Option<&'static str>,
);
impl Error {
#[allow(dead_code)]
pub fn kind(&self) -> &ErrorKind {
&self.0
}
}
impl From<ErrorKind> for Error {
fn from(e: ErrorKind) -> Self {
Error(e, None, None)
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.1
.as_ref()
.map(|e| e.as_ref() as &(dyn std::error::Error + 'static))
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, f)
}
}
impl std::fmt::Debug for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use std::error::Error as StdError;
if let Some(ref o) = self.2 {
std::fmt::Display::fmt(o, f)?;
}
std::fmt::Debug::fmt(&self.0, f)?;
if let Some(e) = self.source() {
std::fmt::Display::fmt("\nCaused by:\n", f)?;
std::fmt::Debug::fmt(&e, f)?;
}
Ok(())
}
}
#[allow(dead_code)]
pub type Result<T> = std::result::Result<T, Error>;
impl From<varlink::Error> for Error {
fn from(e: varlink::Error) -> Self {
match e.kind() {
varlink::ErrorKind::VarlinkErrorReply(r) => Error(
ErrorKind::from(r),
Some(Box::from(e)),
Some(concat!(file!(), ":", line!(), ": ")),
),
_ => Error(
ErrorKind::Varlink_Error,
Some(Box::from(e)),
Some(concat!(file!(), ":", line!(), ": ")),
),
}
}
}
#[allow(dead_code)]
impl Error {
pub fn source_varlink_kind(&self) -> Option<&varlink::ErrorKind> {
use std::error::Error as StdError;
let mut s: &dyn StdError = self;
while let Some(c) = s.source() {
let k = self
.source()
.and_then(|e| e.downcast_ref::<varlink::Error>())
.map(|e| e.kind());
if k.is_some() {
return k;
}
s = c;
}
None
}
}
impl From<&varlink::Reply> for ErrorKind {
#[allow(unused_variables)]
fn from(e: &varlink::Reply) -> Self {
match e {
_ => ErrorKind::VarlinkReply_Error,
}
}
}
pub trait VarlinkCallError: varlink::CallTrait {}
impl<'a> VarlinkCallError for varlink::Call<'a> {}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct Describe_Reply {
pub r#Hostname: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#StaticHostname: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#PrettyHostname: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#DefaultHostname: Option<String>,
pub r#HostnameSource: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#IconName: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#Chassis: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#Deployment: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#Location: Option<String>,
pub r#KernelName: String,
pub r#KernelRelease: String,
pub r#KernelVersion: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#OperatingSystemPrettyName: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#OperatingSystemCPEName: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#OperatingSystemHomeURL: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#OperatingSystemSupportEnd: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#OperatingSystemReleaseData: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#MachineInformationData: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#HardwareVendor: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#HardwareModel: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#HardwareSerial: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#FirmwareVersion: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#FirmwareVendor: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#FirmwareDate: Option<i64>,
pub r#MachineID: String,
pub r#BootID: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#ProductUUID: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#VSockCID: Option<i64>,
}
impl varlink::VarlinkReply for Describe_Reply {}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct Describe_Args {}
pub trait Call_Describe: VarlinkCallError {
fn reply(
&mut self,
r#Hostname: String,
r#StaticHostname: Option<String>,
r#PrettyHostname: Option<String>,
r#DefaultHostname: Option<String>,
r#HostnameSource: String,
r#IconName: Option<String>,
r#Chassis: Option<String>,
r#Deployment: Option<String>,
r#Location: Option<String>,
r#KernelName: String,
r#KernelRelease: String,
r#KernelVersion: String,
r#OperatingSystemPrettyName: Option<String>,
r#OperatingSystemCPEName: Option<String>,
r#OperatingSystemHomeURL: Option<String>,
r#OperatingSystemSupportEnd: Option<i64>,
r#OperatingSystemReleaseData: Option<Vec<String>>,
r#MachineInformationData: Option<Vec<String>>,
r#HardwareVendor: Option<String>,
r#HardwareModel: Option<String>,
r#HardwareSerial: Option<String>,
r#FirmwareVersion: Option<String>,
r#FirmwareVendor: Option<String>,
r#FirmwareDate: Option<i64>,
r#MachineID: String,
r#BootID: String,
r#ProductUUID: Option<String>,
r#VSockCID: Option<i64>,
) -> varlink::Result<()> {
self.reply_struct(
Describe_Reply {
r#Hostname,
r#StaticHostname,
r#PrettyHostname,
r#DefaultHostname,
r#HostnameSource,
r#IconName,
r#Chassis,
r#Deployment,
r#Location,
r#KernelName,
r#KernelRelease,
r#KernelVersion,
r#OperatingSystemPrettyName,
r#OperatingSystemCPEName,
r#OperatingSystemHomeURL,
r#OperatingSystemSupportEnd,
r#OperatingSystemReleaseData,
r#MachineInformationData,
r#HardwareVendor,
r#HardwareModel,
r#HardwareSerial,
r#FirmwareVersion,
r#FirmwareVendor,
r#FirmwareDate,
r#MachineID,
r#BootID,
r#ProductUUID,
r#VSockCID,
}
.into(),
)
}
}
impl<'a> Call_Describe for varlink::Call<'a> {}
pub trait VarlinkInterface {
fn describe(&self, call: &mut dyn Call_Describe) -> varlink::Result<()>;
fn call_upgraded(
&self,
_call: &mut varlink::Call,
_bufreader: &mut dyn BufRead,
) -> varlink::Result<Vec<u8>> {
Ok(Vec::new())
}
}
pub trait VarlinkClientInterface {
fn describe(&mut self) -> varlink::MethodCall<Describe_Args, Describe_Reply, Error>;
}
#[allow(dead_code)]
pub struct VarlinkClient {
connection: Arc<RwLock<varlink::Connection>>,
}
impl VarlinkClient {
#[allow(dead_code)]
pub fn new(connection: Arc<RwLock<varlink::Connection>>) -> Self {
VarlinkClient { connection }
}
}
impl VarlinkClientInterface for VarlinkClient {
fn describe(&mut self) -> varlink::MethodCall<Describe_Args, Describe_Reply, Error> {
varlink::MethodCall::<Describe_Args, Describe_Reply, Error>::new(
self.connection.clone(),
"io.systemd.Hostname.Describe",
Describe_Args {},
)
}
}
#[allow(dead_code)]
pub struct VarlinkInterfaceProxy {
inner: Box<dyn VarlinkInterface + Send + Sync>,
}
#[allow(dead_code)]
pub fn new(inner: Box<dyn VarlinkInterface + Send + Sync>) -> VarlinkInterfaceProxy {
VarlinkInterfaceProxy { inner }
}
impl varlink::Interface for VarlinkInterfaceProxy {
fn get_description(&self) -> &'static str {
"interface io.systemd.Hostname\n\nmethod Describe() -> (\n\tHostname: string,\n\tStaticHostname: ?string,\n\tPrettyHostname: ?string,\n\tDefaultHostname: ?string,\n\tHostnameSource: string,\n\tIconName: ?string,\n\tChassis: ?string,\n\tDeployment: ?string,\n\tLocation: ?string,\n\tKernelName: string,\n\tKernelRelease: string,\n\tKernelVersion: string,\n\tOperatingSystemPrettyName: ?string,\n\tOperatingSystemCPEName: ?string,\n\tOperatingSystemHomeURL: ?string,\n\tOperatingSystemSupportEnd: ?int,\n\tOperatingSystemReleaseData: ?[]string,\n\tMachineInformationData: ?[]string,\n\tHardwareVendor: ?string,\n\tHardwareModel: ?string,\n\tHardwareSerial: ?string,\n\tFirmwareVersion: ?string,\n\tFirmwareVendor: ?string,\n\tFirmwareDate: ?int,\n\tMachineID: string,\n\tBootID: string,\n\tProductUUID: ?string,\n\tVSockCID: ?int\n)\n"
}
fn get_name(&self) -> &'static str {
"io.systemd.Hostname"
}
fn call_upgraded(
&self,
call: &mut varlink::Call,
bufreader: &mut dyn BufRead,
) -> varlink::Result<Vec<u8>> {
self.inner.call_upgraded(call, bufreader)
}
fn call(&self, call: &mut varlink::Call) -> varlink::Result<()> {
let req = call.request.unwrap();
match req.method.as_ref() {
"io.systemd.Hostname.Describe" => self.inner.describe(call as &mut dyn Call_Describe),
m => call.reply_method_not_found(String::from(m)),
}
}
}

2
systemd-ipc/src/lib.rs Normal file
View file

@ -0,0 +1,2 @@
pub mod addrs;
pub mod io_systemd_hostname;