diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs index 3f3de7ba..a160c844 100644 --- a/src/api2/admin/datastore.rs +++ b/src/api2/admin/datastore.rs @@ -423,12 +423,18 @@ pub fn list_snapshots ( Ok(snapshots) } -// returns a map from type to (group_count, snapshot_count) -fn get_snaphots_count(store: &DataStore) -> Result, Error> { +fn get_snapshots_count(store: &DataStore) -> Result { let base_path = store.base_path(); let backup_list = BackupInfo::list_backups(&base_path)?; let mut groups = HashSet::new(); - let mut result: HashMap = HashMap::new(); + + let mut result = Counts { + ct: None, + host: None, + vm: None, + other: None, + }; + for info in backup_list { let group = info.backup_dir.group(); @@ -441,13 +447,23 @@ fn get_snaphots_count(store: &DataStore) -> Result result.ct.take().unwrap_or(Default::default()), + "host" => result.host.take().unwrap_or(Default::default()), + "vm" => result.vm.take().unwrap_or(Default::default()), + _ => result.other.take().unwrap_or(Default::default()), + }; + + counts.snapshots += 1; + if new_id { + counts.groups +=1; + } + + match backup_type { + "ct" => result.ct = Some(counts), + "host" => result.host = Some(counts), + "vm" => result.vm = Some(counts), + _ => result.other = Some(counts), } } @@ -463,21 +479,7 @@ fn get_snaphots_count(store: &DataStore) -> Result Result { +) -> Result { let datastore = DataStore::lookup_datastore(&store)?; - let storage_status = crate::tools::disks::disk_usage(&datastore.base_path())?; - let counts = get_snaphots_count(&datastore)?; + let storage = crate::tools::disks::disk_usage(&datastore.base_path())?; + let counts = get_snapshots_count(&datastore)?; let gc_status = datastore.last_gc_status(); - let res = json!({ - "storage": storage_status, - "counts": counts, - "gc-status": gc_status, - }); - - Ok(res) + Ok(DataStoreStatus { + total: storage.total, + used: storage.used, + avail: storage.avail, + gc_status, + counts, + }) } #[api( diff --git a/src/api2/types/mod.rs b/src/api2/types/mod.rs index 1b9a305f..1f98215c 100644 --- a/src/api2/types/mod.rs +++ b/src/api2/types/mod.rs @@ -622,6 +622,71 @@ pub struct StorageStatus { pub avail: u64, } +#[api()] +#[derive(Serialize, Deserialize, Default)] +/// Backup Type group/snapshot counts. +pub struct TypeCounts { + /// The number of groups of the type. + pub groups: u64, + /// The number of snapshots of the type. + pub snapshots: u64, +} + +#[api( + properties: { + ct: { + type: TypeCounts, + optional: true, + }, + host: { + type: TypeCounts, + optional: true, + }, + vm: { + type: TypeCounts, + optional: true, + }, + other: { + type: TypeCounts, + optional: true, + }, + }, +)] +#[derive(Serialize, Deserialize)] +/// Counts of groups/snapshots per BackupType. +pub struct Counts { + /// The counts for CT backups + pub ct: Option, + /// The counts for Host backups + pub host: Option, + /// The counts for VM backups + pub vm: Option, + /// The counts for other backup types + pub other: Option, +} + +#[api( + properties: { + "gc-status": { type: GarbageCollectionStatus, }, + counts: { type: Counts, } + }, +)] +#[derive(Serialize, Deserialize)] +#[serde(rename_all="kebab-case")] +/// Overall Datastore status and useful information. +pub struct DataStoreStatus { + /// Total space (bytes). + pub total: u64, + /// Used space (bytes). + pub used: u64, + /// Available space (bytes). + pub avail: u64, + /// Status of last GC + pub gc_status: GarbageCollectionStatus, + /// Group/Snapshot counts + pub counts: Counts, +} + #[api( properties: { upid: { schema: UPID_SCHEMA }, diff --git a/src/bin/proxmox-backup-client.rs b/src/bin/proxmox-backup-client.rs index beaa935e..139e607b 100644 --- a/src/bin/proxmox-backup-client.rs +++ b/src/bin/proxmox-backup-client.rs @@ -1674,7 +1674,7 @@ async fn status(param: Value) -> Result { let path = format!("api2/json/admin/datastore/{}/status", repo.store()); let mut result = client.get(&path, None).await?; - let mut data = result["data"]["storage"].take(); + let mut data = result["data"].take(); record_repository(&repo); diff --git a/www/DataStoreSummary.js b/www/DataStoreSummary.js index 525486a5..93bd99a3 100644 --- a/www/DataStoreSummary.js +++ b/www/DataStoreSummary.js @@ -48,21 +48,23 @@ Ext.define('PBS.DataStoreInfo', { let vm = me.getViewModel(); let counts = store.getById('counts').data.value; - let storage = store.getById('storage').data.value; + let total = store.getById('total').data.value; + let used = store.getById('used').data.value; - let used = Proxmox.Utils.format_size(storage.used); - let total = Proxmox.Utils.format_size(storage.total); - let percent = 100*storage.used/storage.total; - if (storage.total === 0) { + let percent = 100*used/total; + if (total === 0) { percent = 0; } let used_percent = `${percent.toFixed(2)}%`; let usage = used_percent + ' (' + - Ext.String.format(gettext('{0} of {1}'), - used, total) + ')'; + Ext.String.format( + gettext('{0} of {1}'), + Proxmox.Utils.format_size(used), + Proxmox.Utils.format_size(total), + ) + ')'; vm.set('usagetext', usage); - vm.set('usage', storage.used/storage.total); + vm.set('usage', used/total); let gcstatus = store.getById('gc-status').data.value; @@ -70,12 +72,12 @@ Ext.define('PBS.DataStoreInfo', { (gcstatus['disk-bytes'] || Infinity); let countstext = function(count) { - return `${count[0]} ${gettext('Groups')}, ${count[1]} ${gettext('Snapshots')}`; + return `${count.groups || 0} ${gettext('Groups')}, ${count.snapshots || 0} ${gettext('Snapshots')}`; }; - vm.set('ctcount', countstext(counts.ct || [0, 0])); - vm.set('vmcount', countstext(counts.vm || [0, 0])); - vm.set('hostcount', countstext(counts.host || [0, 0])); + vm.set('ctcount', countstext(counts.ct)); + vm.set('vmcount', countstext(counts.vm)); + vm.set('hostcount', countstext(counts.host)); vm.set('deduplication', dedup.toFixed(2)); vm.set('stillbad', gcstatus['still-bad']); vm.set('removedbytes', Proxmox.Utils.format_size(gcstatus['removed-bytes']));