pbs-api-types: add mount_status field to DataStoreListItem

Signed-off-by: Hannes Laimer <h.laimer@proxmox.com>
This commit is contained in:
Hannes Laimer 2024-11-25 17:21:55 +01:00 committed by Thomas Lamprecht
parent 40a2b110bf
commit 76609915d6
3 changed files with 66 additions and 21 deletions

View File

@ -178,6 +178,20 @@ pub enum ChunkOrder {
Inode, Inode,
} }
#[api]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
/// Current mounting status of a datastore, useful for removable datastores.
pub enum DataStoreMountStatus {
/// Removable datastore is currently mounted correctly.
Mounted,
/// Removable datastore is currebtly not mounted.
NotMounted,
/// Datastore is not removable, so there is no mount status.
#[default]
NonRemovable,
}
#[api] #[api]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]
@ -451,6 +465,7 @@ impl DataStoreConfig {
pub struct DataStoreListItem { pub struct DataStoreListItem {
pub store: String, pub store: String,
pub comment: Option<String>, pub comment: Option<String>,
pub mount_status: DataStoreMountStatus,
/// If the datastore is in maintenance mode, information about it /// If the datastore is in maintenance mode, information about it
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub maintenance: Option<String>, pub maintenance: Option<String>,
@ -1456,6 +1471,7 @@ pub struct DataStoreStatusListItem {
/// The available bytes of the underlying storage. (-1 on error) /// The available bytes of the underlying storage. (-1 on error)
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub avail: Option<u64>, pub avail: Option<u64>,
pub mount_status: DataStoreMountStatus,
/// A list of usages of the past (last Month). /// A list of usages of the past (last Month).
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub history: Option<Vec<Option<f64>>>, pub history: Option<Vec<Option<f64>>>,
@ -1480,12 +1496,13 @@ pub struct DataStoreStatusListItem {
} }
impl DataStoreStatusListItem { impl DataStoreStatusListItem {
pub fn empty(store: &str, err: Option<String>) -> Self { pub fn empty(store: &str, err: Option<String>, mount_status: DataStoreMountStatus) -> Self {
DataStoreStatusListItem { DataStoreStatusListItem {
store: store.to_owned(), store: store.to_owned(),
total: None, total: None,
used: None, used: None,
avail: None, avail: None,
mount_status,
history: None, history: None,
history_start: None, history_start: None,
history_delta: None, history_delta: None,

View File

@ -38,14 +38,15 @@ use pxar::EntryKind;
use pbs_api_types::{ use pbs_api_types::{
print_ns_and_snapshot, print_store_and_ns, ArchiveType, Authid, BackupArchiveName, print_ns_and_snapshot, print_store_and_ns, ArchiveType, Authid, BackupArchiveName,
BackupContent, BackupGroupDeleteStats, BackupNamespace, BackupType, Counts, CryptMode, BackupContent, BackupGroupDeleteStats, BackupNamespace, BackupType, Counts, CryptMode,
DataStoreConfig, DataStoreListItem, DataStoreStatus, GarbageCollectionJobStatus, GroupListItem, DataStoreConfig, DataStoreListItem, DataStoreMountStatus, DataStoreStatus,
JobScheduleStatus, KeepOptions, MaintenanceMode, MaintenanceType, Operation, PruneJobOptions, GarbageCollectionJobStatus, GroupListItem, JobScheduleStatus, KeepOptions, MaintenanceMode,
SnapshotListItem, SnapshotVerifyState, BACKUP_ARCHIVE_NAME_SCHEMA, BACKUP_ID_SCHEMA, MaintenanceType, Operation, PruneJobOptions, SnapshotListItem, SnapshotVerifyState,
BACKUP_NAMESPACE_SCHEMA, BACKUP_TIME_SCHEMA, BACKUP_TYPE_SCHEMA, CATALOG_NAME, BACKUP_ARCHIVE_NAME_SCHEMA, BACKUP_ID_SCHEMA, BACKUP_NAMESPACE_SCHEMA, BACKUP_TIME_SCHEMA,
CLIENT_LOG_BLOB_NAME, DATASTORE_SCHEMA, IGNORE_VERIFIED_BACKUPS_SCHEMA, MANIFEST_BLOB_NAME, BACKUP_TYPE_SCHEMA, CATALOG_NAME, CLIENT_LOG_BLOB_NAME, DATASTORE_SCHEMA,
MAX_NAMESPACE_DEPTH, NS_MAX_DEPTH_SCHEMA, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP, IGNORE_VERIFIED_BACKUPS_SCHEMA, MANIFEST_BLOB_NAME, MAX_NAMESPACE_DEPTH, NS_MAX_DEPTH_SCHEMA,
PRIV_DATASTORE_MODIFY, PRIV_DATASTORE_PRUNE, PRIV_DATASTORE_READ, PRIV_DATASTORE_VERIFY, UPID, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP, PRIV_DATASTORE_MODIFY, PRIV_DATASTORE_PRUNE,
UPID_SCHEMA, VERIFICATION_OUTDATED_AFTER_SCHEMA, PRIV_DATASTORE_READ, PRIV_DATASTORE_VERIFY, UPID, UPID_SCHEMA,
VERIFICATION_OUTDATED_AFTER_SCHEMA,
}; };
use pbs_client::pxar::{create_tar, create_zip}; use pbs_client::pxar::{create_tar, create_zip};
use pbs_config::CachedUserInfo; use pbs_config::CachedUserInfo;
@ -1323,8 +1324,8 @@ pub fn get_datastore_list(
let mut list = Vec::new(); let mut list = Vec::new();
for (store, (_, data)) in &config.sections { for (store, (_, data)) in config.sections {
let acl_path = &["datastore", store]; let acl_path = &["datastore", &store];
let user_privs = user_info.lookup_privs(&auth_id, acl_path); let user_privs = user_info.lookup_privs(&auth_id, acl_path);
let allowed = (user_privs & (PRIV_DATASTORE_AUDIT | PRIV_DATASTORE_BACKUP)) != 0; let allowed = (user_privs & (PRIV_DATASTORE_AUDIT | PRIV_DATASTORE_BACKUP)) != 0;
@ -1335,15 +1336,20 @@ pub fn get_datastore_list(
} }
} }
let store_config: DataStoreConfig = serde_json::from_value(data)?;
let mount_status = match pbs_datastore::get_datastore_mount_status(&store_config) {
Some(true) => DataStoreMountStatus::Mounted,
Some(false) => DataStoreMountStatus::NotMounted,
None => DataStoreMountStatus::NonRemovable,
};
if allowed || allow_id { if allowed || allow_id {
list.push(DataStoreListItem { list.push(DataStoreListItem {
store: store.clone(), store: store.clone(),
comment: if !allowed { comment: store_config.comment.filter(|_| allowed),
None mount_status,
} else { maintenance: store_config.maintenance_mode,
data["comment"].as_str().map(String::from)
},
maintenance: data["maintenance-mode"].as_str().map(String::from),
}); });
} }
} }

View File

@ -10,11 +10,12 @@ use proxmox_schema::api;
use proxmox_sortable_macro::sortable; use proxmox_sortable_macro::sortable;
use pbs_api_types::{ use pbs_api_types::{
Authid, DataStoreStatusListItem, Operation, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP, Authid, DataStoreConfig, DataStoreMountStatus, DataStoreStatusListItem, Operation,
PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP,
}; };
use pbs_config::CachedUserInfo; use pbs_config::CachedUserInfo;
use pbs_datastore::DataStore; use pbs_datastore::{get_datastore_mount_status, DataStore};
use crate::server::metric_collection::rrd::extract_rrd_data; use crate::server::metric_collection::rrd::extract_rrd_data;
use crate::tools::statistics::linear_regression; use crate::tools::statistics::linear_regression;
@ -51,10 +52,26 @@ pub async fn datastore_status(
for (store, (_, _)) in &config.sections { for (store, (_, _)) in &config.sections {
let user_privs = user_info.lookup_privs(&auth_id, &["datastore", store]); let user_privs = user_info.lookup_privs(&auth_id, &["datastore", store]);
let allowed = (user_privs & (PRIV_DATASTORE_AUDIT | PRIV_DATASTORE_BACKUP)) != 0; let allowed = (user_privs & (PRIV_DATASTORE_AUDIT | PRIV_DATASTORE_BACKUP)) != 0;
let store_config = config.lookup::<DataStoreConfig>("datastore", store)?;
let mount_status = match get_datastore_mount_status(&store_config) {
Some(true) => DataStoreMountStatus::Mounted,
Some(false) => {
list.push(DataStoreStatusListItem::empty(
store,
None,
DataStoreMountStatus::NotMounted,
));
continue;
}
None => DataStoreMountStatus::NonRemovable,
};
if !allowed { if !allowed {
if let Ok(datastore) = DataStore::lookup_datastore(store, Some(Operation::Lookup)) { if let Ok(datastore) = DataStore::lookup_datastore(store, Some(Operation::Lookup)) {
if can_access_any_namespace(datastore, &auth_id, &user_info) { if can_access_any_namespace(datastore, &auth_id, &user_info) {
list.push(DataStoreStatusListItem::empty(store, None)); list.push(DataStoreStatusListItem::empty(store, None, mount_status));
} }
} }
continue; continue;
@ -63,7 +80,11 @@ pub async fn datastore_status(
let datastore = match DataStore::lookup_datastore(store, Some(Operation::Read)) { let datastore = match DataStore::lookup_datastore(store, Some(Operation::Read)) {
Ok(datastore) => datastore, Ok(datastore) => datastore,
Err(err) => { Err(err) => {
list.push(DataStoreStatusListItem::empty(store, Some(err.to_string()))); list.push(DataStoreStatusListItem::empty(
store,
Some(err.to_string()),
mount_status,
));
continue; continue;
} }
}; };
@ -74,6 +95,7 @@ pub async fn datastore_status(
total: Some(status.total), total: Some(status.total),
used: Some(status.used), used: Some(status.used),
avail: Some(status.available), avail: Some(status.available),
mount_status,
history: None, history: None,
history_start: None, history_start: None,
history_delta: None, history_delta: None,