]> git.proxmox.com Git - proxmox-backup.git/blobdiff - src/tape/inventory.rs
typo fixes all over the place
[proxmox-backup.git] / src / tape / inventory.rs
index 21b72e0a190a462ef506740f63d4d2b3df915c8e..7ae9d56504d8d6df32e02f9e6225379a904cbc51 100644 (file)
@@ -6,6 +6,7 @@
 
 use std::collections::{HashMap, BTreeMap};
 use std::path::{Path, PathBuf};
+use std::os::unix::io::AsRawFd;
 
 use anyhow::{bail, Error};
 use serde::{Serialize, Deserialize};
@@ -16,6 +17,7 @@ use proxmox::tools::{
     fs::{
         open_file_locked,
         replace_file,
+        fchown,
         file_get_json,
         CreateOptions,
     },
@@ -31,12 +33,12 @@ use crate::{
     },
     tape::{
         TAPE_STATUS_DIR,
-        OnlineStatusMap,
         MediaSet,
         file_formats::{
             MediaLabel,
             MediaSetLabel,
         },
+        changer::OnlineStatusMap,
     },
 };
 
@@ -126,7 +128,16 @@ impl Inventory {
 
     /// Lock the database
     pub fn lock(&self) -> Result<std::fs::File, Error> {
-        open_file_locked(&self.lockfile_path, std::time::Duration::new(10, 0), true)
+        let file = open_file_locked(&self.lockfile_path, std::time::Duration::new(10, 0), true)?;
+        if cfg!(test) {
+            // We cannot use chown inside test environment (no permissions)
+            return Ok(file);
+        }
+
+        let backup_user = crate::backup::backup_user()?;
+        fchown(file.as_raw_fd(), Some(backup_user.uid), Some(backup_user.gid))?;
+
+        Ok(file)
     }
 
     fn load_media_db(path: &Path) -> Result<BTreeMap<Uuid, MediaStateEntry>, Error> {
@@ -146,12 +157,18 @@ impl Inventory {
         let list: Vec<&MediaStateEntry> = self.map.values().collect();
         let raw = serde_json::to_string_pretty(&serde_json::to_value(list)?)?;
 
-        let backup_user = crate::backup::backup_user()?;
         let mode = nix::sys::stat::Mode::from_bits_truncate(0o0640);
-        let options = CreateOptions::new()
-            .perm(mode)
-            .owner(backup_user.uid)
-            .group(backup_user.gid);
+
+        let options = if cfg!(test) {
+            // We cannot use chown inside test environment (no permissions)
+            CreateOptions::new().perm(mode)
+        } else {
+            let backup_user = crate::backup::backup_user()?;
+            CreateOptions::new()
+                .perm(mode)
+                .owner(backup_user.uid)
+                .group(backup_user.gid)
+        };
 
         replace_file(&self.inventory_path, raw.as_bytes(), options)?;
 
@@ -213,14 +230,20 @@ impl Inventory {
         self.map.get(uuid).map(|entry| &entry.id)
     }
 
+    /// List all media Uuids
+    pub fn media_list(&self) -> Vec<&Uuid> {
+        self.map.keys().collect()
+    }
+
     /// find media by label_text
     pub fn find_media_by_label_text(&self, label_text: &str) -> Option<&MediaId> {
-        for (_uuid, entry) in &self.map {
+        self.map.values().find_map(|entry| {
             if entry.id.label.label_text == label_text {
-                return Some(&entry.id);
+                Some(&entry.id)
+            } else {
+                None
             }
-        }
-        None
+        })
     }
 
     /// Lookup media pool
@@ -245,7 +268,7 @@ impl Inventory {
     pub fn list_pool_media(&self, pool: &str) -> Vec<MediaId> {
         let mut list = Vec::new();
 
-        for (_uuid, entry) in &self.map {
+        for entry in self.map.values() {
             match entry.id.media_set_label {
                 None => continue, // not assigned to any pool
                 Some(ref set) => {
@@ -253,7 +276,7 @@ impl Inventory {
                         continue; // belong to another pool
                     }
 
-                    if set.uuid.as_ref() == [0u8;16] { // should we do this??
+                    if set.uuid.as_ref() == [0u8;16] {
                         list.push(MediaId {
                             label: entry.id.label.clone(),
                             media_set_label: None,
@@ -272,7 +295,7 @@ impl Inventory {
     pub fn list_used_media(&self) -> Vec<MediaId> {
         let mut list = Vec::new();
 
-        for (_uuid, entry) in &self.map {
+        for entry in self.map.values() {
             match entry.id.media_set_label {
                 None => continue, // not assigned to any pool
                 Some(ref set) => {
@@ -288,19 +311,17 @@ impl Inventory {
 
     /// List media not assigned to any pool
     pub fn list_unassigned_media(&self) -> Vec<MediaId> {
-        let mut list = Vec::new();
-
-        for (_uuid, entry) in &self.map {
+        self.map.values().filter_map(|entry|
             if entry.id.media_set_label.is_none() {
-                list.push(entry.id.clone());
+                Some(entry.id.clone())
+            } else {
+                None
             }
-        }
-
-        list
+        ).collect()
     }
 
     pub fn media_set_start_time(&self, media_set_uuid: &Uuid) -> Option<i64> {
-        self.media_set_start_times.get(media_set_uuid).map(|t| *t)
+        self.media_set_start_times.get(media_set_uuid).copied()
     }
 
     /// Lookup media set pool
@@ -330,7 +351,7 @@ impl Inventory {
 
         match last_pool {
             Some(pool) => Ok(pool.to_string()),
-            None => bail!("media set {} is incomplete - unable to lookup pool"),
+            None => bail!("media set {} is incomplete - unable to lookup pool", media_set_uuid),
         }
     }
 
@@ -383,7 +404,7 @@ impl Inventory {
 
         let set_list = self.map.values()
             .filter_map(|entry| entry.id.media_set_label.as_ref())
-            .filter(|set| &set.pool == &pool && set.uuid.as_ref() != [0u8;16]);
+            .filter(|set| set.pool == pool && set.uuid.as_ref() != [0u8;16]);
 
         for set in set_list {
             match last_set {
@@ -406,7 +427,7 @@ impl Inventory {
         // consistency check - must be the only set with that ctime
         let set_list = self.map.values()
             .filter_map(|entry| entry.id.media_set_label.as_ref())
-            .filter(|set| &set.pool == &pool && set.uuid.as_ref() != [0u8;16]);
+            .filter(|set| set.pool == pool && set.uuid.as_ref() != [0u8;16]);
 
         for set in set_list {
             if set.uuid != uuid && set.ctime >= ctime { // should not happen
@@ -437,7 +458,7 @@ impl Inventory {
 
         let set_list = self.map.values()
             .filter_map(|entry| entry.id.media_set_label.as_ref())
-            .filter(|set| (&set.uuid != media_set_uuid) && (&set.pool == &pool));
+            .filter(|set| (&set.uuid != media_set_uuid) && (set.pool == pool));
 
         let mut next_ctime = None;
 
@@ -484,20 +505,27 @@ impl Inventory {
             Some(time) => time,
         };
 
-        let max_use_time = match media_set_policy {
-            MediaSetPolicy::ContinueCurrent => {
-                match self.media_set_next_start_time(&set.uuid) {
-                    Some(next_start_time) => next_start_time,
-                    None => return i64::MAX,
-                }
+        let max_use_time = match self.media_set_next_start_time(&set.uuid) {
+            Some(next_start_time) => {
+               match media_set_policy {
+                   MediaSetPolicy::AlwaysCreate => set_start_time,
+                   _ => next_start_time,
+               }
             }
-            MediaSetPolicy::AlwaysCreate => {
-                set_start_time + 1
-            }
-            MediaSetPolicy::CreateAt(ref event) => {
-                match compute_next_event(event, set_start_time, false) {
-                    Ok(Some(next)) => next,
-                    Ok(None) | Err(_) => return i64::MAX,
+            None => {
+                match media_set_policy {
+                    MediaSetPolicy::ContinueCurrent => {
+                        return i64::MAX;
+                    }
+                    MediaSetPolicy::AlwaysCreate => {
+                        set_start_time
+                    }
+                    MediaSetPolicy::CreateAt(ref event) => {
+                        match compute_next_event(event, set_start_time, false) {
+                            Ok(Some(next)) => next,
+                            Ok(None) | Err(_) => return i64::MAX,
+                        }
+                    }
                 }
             }
         };
@@ -522,7 +550,7 @@ impl Inventory {
     ) -> Result<String, Error> {
 
         if let Some(ctime) = self.media_set_start_time(media_set_uuid) {
-            let mut template = template.unwrap_or(String::from("%c"));
+            let mut template = template.unwrap_or_else(|| String::from("%c"));
             template = template.replace("%id%", &media_set_uuid.to_string());
             proxmox::tools::time::strftime_local(&template, ctime)
         } else {
@@ -533,7 +561,7 @@ impl Inventory {
 
     // Helpers to simplify testing
 
-    /// Genreate and insert a new free tape (test helper)
+    /// Generate and insert a new free tape (test helper)
     pub fn generate_free_tape(&mut self, label_text: &str, ctime: i64) -> Uuid {
 
         let label = MediaLabel {
@@ -548,7 +576,7 @@ impl Inventory {
         uuid
     }
 
-    /// Genreate and insert a new tape assigned to a specific pool
+    /// Generate and insert a new tape assigned to a specific pool
     /// (test helper)
     pub fn generate_assigned_tape(
         &mut self,
@@ -572,7 +600,7 @@ impl Inventory {
         uuid
     }
 
-    /// Genreate and insert a used tape (test helper)
+    /// Generate and insert a used tape (test helper)
     pub fn generate_used_tape(
         &mut self,
         label_text: &str,
@@ -638,6 +666,11 @@ impl Inventory {
         self.set_media_status(uuid, Some(MediaStatus::Damaged))
     }
 
+    /// Lock database, reload database, set status to Retired, store database
+    pub fn set_media_status_retired(&mut self, uuid: &Uuid) -> Result<(), Error> {
+        self.set_media_status(uuid, Some(MediaStatus::Retired))
+    }
+
     /// Lock database, reload database, set status to None, store database
     pub fn clear_media_status(&mut self, uuid: &Uuid) -> Result<(), Error> {
         self.set_media_status(uuid, None)
@@ -675,20 +708,18 @@ impl Inventory {
         for (uuid, entry) in self.map.iter_mut() {
             if let Some(changer_name) = online_map.lookup_changer(uuid) {
                 entry.location = Some(MediaLocation::Online(changer_name.to_string()));
-            } else {
-                if let Some(MediaLocation::Online(ref changer_name)) = entry.location {
-                    match online_map.online_map(changer_name) {
-                        None => {
-                            // no such changer device
-                            entry.location = Some(MediaLocation::Offline);
-                        }
-                        Some(None) => {
-                            // got no info - do nothing
-                        }
-                        Some(Some(_)) => {
-                            // media changer changed
-                            entry.location = Some(MediaLocation::Offline);
-                        }
+            } else if let Some(MediaLocation::Online(ref changer_name)) = entry.location {
+                match online_map.online_map(changer_name) {
+                    None => {
+                        // no such changer device
+                        entry.location = Some(MediaLocation::Offline);
+                    }
+                    Some(None) => {
+                        // got no info - do nothing
+                    }
+                    Some(Some(_)) => {
+                        // media changer changed
+                        entry.location = Some(MediaLocation::Offline);
                     }
                 }
             }