]> git.proxmox.com Git - proxmox-backup.git/blobdiff - src/api2/tape/drive.rs
typo fixes all over the place
[proxmox-backup.git] / src / api2 / tape / drive.rs
index 6ef6a78b0d0859ce93378ae7789922e982c5331f..9e86d8f84f3ac45514ad8ac2c1384660f311dd44 100644 (file)
@@ -16,6 +16,7 @@ use proxmox::{
         section_config::SectionConfigData,
         RpcEnvironment,
         RpcEnvironmentType,
+        Permission,
         Router,
         SubdirMap,
     },
@@ -23,7 +24,15 @@ use proxmox::{
 
 use crate::{
     task_log,
-    config,
+    config::{
+        self,
+        cached_user_info::CachedUserInfo,
+        acl::{
+            PRIV_TAPE_AUDIT,
+            PRIV_TAPE_READ,
+            PRIV_TAPE_WRITE,
+        },
+    },
     api2::{
         types::{
             UPID_SCHEMA,
@@ -64,6 +73,8 @@ use crate::{
             open_drive,
             lock_tape_device,
             set_tape_device_state,
+            get_tape_device_state,
+            tape_alert_flags_critical,
         },
         changer::update_changer_online_status,
     },
@@ -135,6 +146,9 @@ where
     returns: {
         schema: UPID_SCHEMA,
     },
+    access: {
+        permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
+    },
 )]
 /// Load media with specified label
 ///
@@ -174,6 +188,9 @@ pub fn load_media(
             },
         },
     },
+    access: {
+        permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
+    },
 )]
 /// Load media from the specified slot
 ///
@@ -203,10 +220,13 @@ pub async fn load_slot(drive: String, source_slot: u64) -> Result<(), Error> {
         },
     },
     returns: {
-        description: "The import-export slot number the media was transfered to.",
+        description: "The import-export slot number the media was transferred to.",
         type: u64,
         minimum: 1,
     },
+    access: {
+        permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
+    },
 )]
 /// Export media with specified label
 pub async fn export_media(drive: String, label_text: String) -> Result<u64, Error> {
@@ -244,6 +264,9 @@ pub async fn export_media(drive: String, label_text: String) -> Result<u64, Erro
     returns: {
         schema: UPID_SCHEMA,
     },
+    access: {
+        permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
+    },
 )]
 /// Unload media via changer
 pub fn unload(
@@ -289,6 +312,9 @@ pub fn unload(
     returns: {
         schema: UPID_SCHEMA,
     },
+    access: {
+        permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_WRITE, false),
+    },
 )]
 /// Erase media. Check for label-text if given (cancels if wrong media).
 pub fn erase_media(
@@ -373,6 +399,9 @@ pub fn erase_media(
     returns: {
         schema: UPID_SCHEMA,
     },
+    access: {
+        permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
+    },
 )]
 /// Rewind tape
 pub fn rewind(
@@ -405,6 +434,9 @@ pub fn rewind(
     returns: {
         schema: UPID_SCHEMA,
     },
+    access: {
+        permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
+    },
 )]
 /// Eject/Unload drive media
 pub fn eject_media(
@@ -448,6 +480,9 @@ pub fn eject_media(
     returns: {
         schema: UPID_SCHEMA,
     },
+    access: {
+        permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_WRITE, false),
+    },
 )]
 /// Label media
 ///
@@ -580,6 +615,9 @@ fn write_media_label(
             },
         },
     },
+    access: {
+        permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
+    },
 )]
 /// Try to restore a tape encryption key
 pub async fn restore_key(
@@ -623,6 +661,9 @@ pub async fn restore_key(
     returns: {
         type: MediaIdFlat,
     },
+    access: {
+        permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
+    },
 )]
 /// Read media label (optionally inventorize media)
 pub async fn read_label(
@@ -698,6 +739,9 @@ pub async fn read_label(
     returns: {
         schema: UPID_SCHEMA,
     },
+    access: {
+        permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
+    },
 )]
 /// Clean drive
 pub fn clean_drive(
@@ -716,7 +760,29 @@ pub fn clean_drive(
 
             changer.clean_drive()?;
 
-            worker.log("Drive cleaned sucessfully");
+             if let Ok(drive_config) = config.lookup::<LinuxTapeDrive>("linux", &drive) {
+                 // Note: clean_drive unloads the cleaning media, so we cannot use drive_config.open
+                 let mut handle = LinuxTapeHandle::new(open_linux_tape_device(&drive_config.path)?);
+
+                 // test for critical tape alert flags
+                 if let Ok(alert_flags) = handle.tape_alert_flags() {
+                     if !alert_flags.is_empty() {
+                         worker.log(format!("TapeAlertFlags: {:?}", alert_flags));
+                         if tape_alert_flags_critical(alert_flags) {
+                             bail!("found critical tape alert flags: {:?}", alert_flags);
+                         }
+                     }
+                 }
+
+                 // test wearout (max. 50 mounts)
+                 if let Ok(volume_stats) = handle.volume_statistics() {
+                     worker.log(format!("Volume mounts: {}", volume_stats.volume_mounts));
+                     let wearout = volume_stats.volume_mounts * 2; // (*100.0/50.0);
+                     worker.log(format!("Cleaning tape wearout: {}%", wearout));
+                 }
+             }
+
+            worker.log("Drive cleaned successfully");
 
             Ok(())
         },
@@ -740,6 +806,9 @@ pub fn clean_drive(
             type: LabelUuidMap,
         },
     },
+    access: {
+        permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
+    },
 )]
 /// List known media labels (Changer Inventory)
 ///
@@ -809,6 +878,9 @@ pub async fn inventory(
     returns: {
         schema: UPID_SCHEMA,
     },
+    access: {
+        permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
+    },
 )]
 /// Update inventory
 ///
@@ -871,7 +943,7 @@ pub fn update_inventory(
                     }
                     Ok((Some(media_id), _key_config)) => {
                         if label_text != media_id.label.label_text {
-                            worker.warn(format!("label text missmatch ({} != {})", label_text, media_id.label.label_text));
+                            worker.warn(format!("label text mismatch ({} != {})", label_text, media_id.label.label_text));
                             continue;
                         }
                         worker.log(format!("inventorize media '{}' with uuid '{}'", label_text, media_id.label.uuid));
@@ -903,6 +975,9 @@ pub fn update_inventory(
     returns: {
         schema: UPID_SCHEMA,
     },
+    access: {
+        permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_WRITE, false),
+    },
 )]
 /// Label media with barcodes from changer device
 pub fn barcode_label_media(
@@ -937,7 +1012,10 @@ fn barcode_label_media_worker(
 ) -> Result<(), Error> {
     let (mut changer, changer_name) = required_media_changer(drive_config, &drive)?;
 
-    let label_text_list = changer.online_media_label_texts()?;
+    let mut label_text_list = changer.online_media_label_texts()?;
+
+    // make sure we label them in the right order
+    label_text_list.sort();
 
     let state_path = Path::new(TAPE_STATUS_DIR);
 
@@ -1012,6 +1090,9 @@ fn barcode_label_media_worker(
             type: MamAttribute,
         },
     },
+    access: {
+        permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_AUDIT, false),
+    },
 )]
 /// Read Cartridge Memory (Medium auxiliary memory attributes)
 pub async fn cartridge_memory(drive: String) -> Result<Vec<MamAttribute>, Error> {
@@ -1039,6 +1120,9 @@ pub async fn cartridge_memory(drive: String) -> Result<Vec<MamAttribute>, Error>
     returns: {
         type: Lp17VolumeStatistics,
     },
+    access: {
+        permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_AUDIT, false),
+    },
 )]
 /// Read Volume Statistics (SCSI log page 17h)
 pub async fn volume_statistics(drive: String) -> Result<Lp17VolumeStatistics, Error> {
@@ -1066,6 +1150,9 @@ pub async fn volume_statistics(drive: String) -> Result<Lp17VolumeStatistics, Er
     returns: {
         type: LinuxDriveAndMediaStatus,
     },
+    access: {
+        permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_AUDIT, false),
+    },
 )]
 /// Get drive/media status
 pub async fn status(drive: String) -> Result<LinuxDriveAndMediaStatus, Error> {
@@ -1107,6 +1194,9 @@ pub async fn status(drive: String) -> Result<LinuxDriveAndMediaStatus, Error> {
     returns: {
         schema: UPID_SCHEMA,
     },
+    access: {
+        permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
+    },
 )]
 /// Scan media and record content
 pub fn catalog_media(
@@ -1202,12 +1292,19 @@ pub fn catalog_media(
             type: DriveListEntry,
         },
     },
+    access: {
+        description: "List configured tape drives filtered by Tape.Audit privileges",
+        permission: &Permission::Anybody,
+    },
 )]
 /// List drives
 pub fn list_drives(
     changer: Option<String>,
     _param: Value,
+    rpcenv: &mut dyn RpcEnvironment,
 ) -> Result<Vec<DriveListEntry>, Error> {
+    let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
+    let user_info = CachedUserInfo::new()?;
 
     let (config, _) = config::drive::config()?;
 
@@ -1222,8 +1319,14 @@ pub fn list_drives(
             continue;
         }
 
+        let privs = user_info.lookup_privs(&auth_id, &["tape", "drive", &drive.name]);
+        if (privs & PRIV_TAPE_AUDIT) == 0 {
+            continue;
+        }
+
         let info = lookup_device_identification(&linux_drives, &drive.path);
-        let entry = DriveListEntry { config: drive, info };
+        let state = get_tape_device_state(&config, &drive.name)?;
+        let entry = DriveListEntry { config: drive, info, state };
         list.push(entry);
     }