diff --git a/pbs-api-types/src/lib.rs b/pbs-api-types/src/lib.rs index 460c7da7..6bae4a52 100644 --- a/pbs-api-types/src/lib.rs +++ b/pbs-api-types/src/lib.rs @@ -155,6 +155,9 @@ pub use zfs::*; mod metrics; pub use metrics::*; +mod version; +pub use version::*; + const_regex! { // just a rough check - dummy acceptor is used before persisting pub OPENSSL_CIPHERS_REGEX = r"^[0-9A-Za-z_:, +!\-@=.]+$"; diff --git a/pbs-api-types/src/version.rs b/pbs-api-types/src/version.rs new file mode 100644 index 00000000..7a4c6cb7 --- /dev/null +++ b/pbs-api-types/src/version.rs @@ -0,0 +1,88 @@ +//! Defines the types for the api version info endpoint +use std::convert::TryFrom; + +use anyhow::{format_err, Context}; + +use proxmox_schema::api; + +#[api( + description: "Api version information", + properties: { + "version": { + description: "Version 'major.minor'", + type: String, + }, + "release": { + description: "Version release", + type: String, + }, + "repoid": { + description: "Version repository id", + type: String, + }, + "features": { + description: "List of supported features", + type: Array, + items: { + type: String, + description: "Feature id", + }, + }, + } +)] +#[derive(serde::Deserialize, serde::Serialize)] +pub struct ApiVersionInfo { + pub version: String, + pub release: String, + pub repoid: String, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub features: Vec, +} + +pub type ApiVersionMajor = u64; +pub type ApiVersionMinor = u64; +pub type ApiVersionRelease = u64; + +pub struct ApiVersion { + pub major: ApiVersionMajor, + pub minor: ApiVersionMinor, + pub release: ApiVersionRelease, + pub repoid: String, + pub features: Vec, +} + +impl TryFrom for ApiVersion { + type Error = anyhow::Error; + + fn try_from(value: ApiVersionInfo) -> Result { + let (major, minor) = value + .version + .split_once('.') + .ok_or_else(|| format_err!("malformed API version {}", value.version))?; + + let major: ApiVersionMajor = major + .parse() + .with_context(|| "failed to parse major version")?; + let minor: ApiVersionMinor = minor + .parse() + .with_context(|| "failed to parse minor version")?; + let release: ApiVersionRelease = value + .release + .parse() + .with_context(|| "failed to parse release version")?; + + Ok(Self { + major, + minor, + release, + repoid: value.repoid.clone(), + features: value.features.clone(), + }) + } +} + +impl ApiVersion { + pub fn supports_feature(&self, feature: &str) -> bool { + self.features.iter().any(|f| f == feature) + } +} diff --git a/src/api2/version.rs b/src/api2/version.rs index 0e91688b..a6cec521 100644 --- a/src/api2/version.rs +++ b/src/api2/version.rs @@ -1,27 +1,35 @@ //! Version information use anyhow::Error; -use serde_json::{json, Value}; +use serde_json::Value; -use proxmox_router::{ApiHandler, ApiMethod, Permission, Router, RpcEnvironment}; -use proxmox_schema::ObjectSchema; +use proxmox_router::{ApiMethod, Permission, Router, RpcEnvironment}; +use proxmox_schema::api; -fn get_version( +use pbs_api_types::ApiVersionInfo; + +const FEATURES: &'static [&'static str] = &[]; + +#[api( + returns: { + type: ApiVersionInfo, + }, + access: { + permission: &Permission::Anybody, + } +)] +///Proxmox Backup Server API version. +fn version( _param: Value, _info: &ApiMethod, _rpcenv: &mut dyn RpcEnvironment, -) -> Result { - Ok(json!({ - "version": pbs_buildcfg::PROXMOX_PKG_VERSION, - "release": pbs_buildcfg::PROXMOX_PKG_RELEASE, - "repoid": pbs_buildcfg::PROXMOX_PKG_REPOID - })) +) -> Result { + Ok(ApiVersionInfo { + version: pbs_buildcfg::PROXMOX_PKG_VERSION.to_string(), + release: pbs_buildcfg::PROXMOX_PKG_RELEASE.to_string(), + repoid: pbs_buildcfg::PROXMOX_PKG_REPOID.to_string(), + features: FEATURES.iter().map(|feature| feature.to_string()).collect(), + }) } -pub const ROUTER: Router = Router::new().get( - &ApiMethod::new( - &ApiHandler::Sync(&get_version), - &ObjectSchema::new("Proxmox Backup Server API version.", &[]), - ) - .access(None, &Permission::Anybody), -); +pub const ROUTER: Router = Router::new().get(&API_METHOD_VERSION);