Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
9.6 kB · 328 lines
Rust
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329use std::{marker::PhantomData, ops::Deref};
use serde::{Deserialize, Serialize, de};use serde_with::{DisplayFromStr, json::JsonString, serde_as};use tracing::info;use zbus::{proxy, zvariant};
use super::metadata::{PoolMetadata, Sectors};
// Wrapper over an Option<T> that (de-)serializes as (present: bool, T), to// be able to work with Stratis APIs that use a struct of bool + T `(bT)`.#[derive(Debug)]pub struct OptionalByPair<T>(Option<T>);
impl<T> OptionalByPair<T> { pub fn into_option(self) -> Option<T> { self.0 }}
impl<T> Deref for OptionalByPair<T> { type Target = Option<T>;
fn deref(&self) -> &Self::Target { &self.0 }}
impl<T> From<Option<T>> for OptionalByPair<T> { fn from(value: Option<T>) -> Self { OptionalByPair(value) }}
impl<T: Default + Serialize + zvariant::Type> Serialize for OptionalByPair<T> { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer, { match &self.0 { Some(x) => (true, x).serialize(serializer), None => (false, T::default()).serialize(serializer), } }}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for OptionalByPair<T> { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de>, { struct Visitor<T>(PhantomData<T>);
impl<'de, T: Deserialize<'de>> de::Visitor<'de> for Visitor<T> { type Value = OptionalByPair<T>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { write!(formatter, "a (bool, T) struct") }
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> where A: de::SeqAccess<'de>, { let value = if seq .next_element() .and_then(|x| x.ok_or(de::Error::invalid_length(0, &"2")))? { seq.next_element() .and_then(|x| x.ok_or(de::Error::invalid_length(1, &"2"))) .map(Some)? } else { seq.next_element::<de::IgnoredAny>() .and_then(|x| x.ok_or(de::Error::invalid_length(1, &"2")))?; None };
let None = seq.next_element::<de::IgnoredAny>()? else { return Err(de::Error::invalid_length(3, &"2")); };
Ok(OptionalByPair(value)) } }
deserializer.deserialize_tuple(2, Visitor(PhantomData::<T>)) }}
impl<T: zvariant::Type> zvariant::Type for OptionalByPair<T> { const SIGNATURE: &'static zvariant::Signature = &zvariant::Signature::static_structure(&[bool::SIGNATURE, T::SIGNATURE]);}
impl<'v, T: TryFrom<zvariant::Value<'v>, Error = zbus::Error>> TryFrom<zvariant::Value<'v>> for OptionalByPair<T>{ type Error = zbus::Error;
fn try_from(value: zvariant::Value<'v>) -> zbus::Result<Self> { let (exists, inner) = value.downcast::<(zvariant::Value<'v>, zvariant::Value<'v>)>()?; let exists = exists.downcast::<bool>()?; if exists { inner.try_into().map(Some).map(Into::into) } else { Ok(None.into()) } }}
impl<'v, T: TryFrom<zvariant::Value<'v>, Error = zbus::Error>> TryFrom<zvariant::OwnedValue> for OptionalByPair<T>{ type Error = zbus::Error;
fn try_from(value: zvariant::OwnedValue) -> zbus::Result<Self> { zvariant::Value::from(value).try_into() }}
impl<'v, T: Default + zvariant::Type + Into<zvariant::Value<'v>>> From<OptionalByPair<T>> for zvariant::Value<'v>{ fn from(value: OptionalByPair<T>) -> Self { match value.0 { Some(x) => (true, x).into(), None => (false, T::default()).into(), } }}
#[serde_as]#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize, zvariant::Type)]#[serde(transparent)]#[zvariant(signature = "s")]pub struct Bytes(#[serde_as(as = "DisplayFromStr")] pub u128);
impl From<Sectors> for Bytes { fn from(value: Sectors) -> Self { Bytes(value.0 as u128 * 512) }}
impl<'a> TryFrom<zvariant::Value<'a>> for Bytes { type Error = zbus::Error;
fn try_from(value: zvariant::Value<'a>) -> Result<Self, Self::Error> { let s = zvariant::Str::try_from(value)?; s.as_str() .parse() .map(Bytes) .map_err(|_| zbus::Error::Failure(format!("byte count '{s}' is not a u128"))) }}
impl TryFrom<zvariant::OwnedValue> for Bytes { type Error = zbus::Error;
fn try_from(value: zvariant::OwnedValue) -> Result<Self, Self::Error> { zvariant::Value::from(value).try_into() }}
impl From<Bytes> for zvariant::Value<'_> { fn from(value: Bytes) -> Self { zvariant::Value::Str(value.0.to_string().into()) }}
#[derive(Deserialize, zvariant::Type)]pub struct OperationResult<T: zvariant::Type> { pub result: T, pub return_code: u16, pub return_message: String,}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]struct Version { major: u8, minor: u8, patch: u8,}
impl std::fmt::Display for Version { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}.{}.{}", self.major, self.minor, self.patch) }}
impl TryFrom<zvariant::Value<'_>> for Version { type Error = zvariant::Error;
fn try_from(value: zvariant::Value) -> Result<Self, Self::Error> { let s = String::try_from(value)?; let components = s .split(".") .map(str::parse::<u8>) .collect::<Result<Vec<_>, _>>() .map_err(|e| zvariant::Error::Message(format!("version component invalid: {e}")))?; if components.len() != 3 { return Err(zvariant::Error::Message(format!( "version expected 3 components, got {}", components.len() ))); } Ok(Version { major: components[0], minor: components[1], patch: components[2], }) }}
impl TryFrom<zvariant::OwnedValue> for Version { type Error = zvariant::Error;
fn try_from(value: zvariant::OwnedValue) -> Result<Self, Self::Error> { zvariant::Value::from(value).try_into() }}
#[proxy( default_service = "org.storage.stratis3", default_path = "/org/storage/stratis3", interface = "org.storage.stratis3.Manager.r0")]trait ManagerV0 { #[zbus(property)] fn version(&self) -> zbus::Result<Version>;}
const MIN_VERSION: Version = Version { major: 3, minor: 8, patch: 0,};
pub async fn check_stratisd_version(conn: &zbus::Connection) -> zbus::Result<()> { let version = ManagerV0Proxy::new(conn).await?.version().await?; info!(?version, "remote stratisd version"); if version < MIN_VERSION { return Err(zbus::Error::Failure(format!( "expected minimum stratisd of {MIN_VERSION}, got {version}" ))); }
Ok(())}
#[derive(Debug, Serialize, Deserialize, zvariant::Type)]pub struct FilesystemSpec { pub name: String, pub size: OptionalByPair<Bytes>, pub size_limit: OptionalByPair<Bytes>,}
#[derive(Debug, Deserialize, zvariant::Type)]#[allow(dead_code)]pub struct CreatedFilesystem { pub path: zvariant::OwnedObjectPath, pub name: String,}
#[derive(Debug, Deserialize, zvariant::Type)]#[zvariant(signature = "s")]#[serde(transparent)]#[allow(dead_code)]pub struct DestroyedFilesystem { pub uuid: String,}
#[serde_as]#[derive(Debug, Deserialize, zvariant::Type, Clone)]#[serde(transparent)]#[zvariant(signature = "s")]pub struct PoolMetadataJson(#[serde_as(as = "JsonString")] PoolMetadata);
impl PoolMetadataJson { pub fn into_inner(self) -> PoolMetadata { self.0 }}
#[proxy( default_service = "org.storage.stratis3", interface = "org.storage.stratis3.pool.r8")]pub trait Pool { fn create_filesystems( &self, specs: &[FilesystemSpec], ) -> zbus::Result<OperationResult<OptionalByPair<Vec<CreatedFilesystem>>>>; fn destroy_filesystems( &self, specs: &[zvariant::ObjectPath<'_>], ) -> zbus::Result<OperationResult<OptionalByPair<Vec<DestroyedFilesystem>>>>; fn snapshot_filesystem( &self, origin: zvariant::ObjectPath<'_>, snapshot_name: &str, ) -> zbus::Result<OperationResult<OptionalByPair<zvariant::OwnedObjectPath>>>; fn metadata(&self, current: bool) -> zbus::Result<OperationResult<PoolMetadataJson>>; #[zbus(property)] fn name(&self) -> zbus::Result<String>; #[zbus(property)] fn total_physical_size(&self) -> zbus::Result<Bytes>; #[zbus(property)] fn total_physical_used(&self) -> zbus::Result<OptionalByPair<Bytes>>;}
#[proxy( default_service = "org.storage.stratis3", interface = "org.storage.stratis3.filesystem.r8")]pub trait Filesystem { #[zbus(property)] fn name(&self) -> zbus::Result<String>; #[zbus(property)] fn size(&self) -> zbus::Result<Bytes>; #[zbus(property)] fn size_limit(&self) -> zbus::Result<OptionalByPair<Bytes>>; #[zbus(property)] fn set_size_limit(&self, value: OptionalByPair<Bytes>) -> zbus::Result<()>; #[zbus(property)] fn used(&self) -> zbus::Result<OptionalByPair<Bytes>>; #[zbus(property)] fn devnode(&self) -> zbus::Result<String>;}