From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 259A5B435 for ; Wed, 6 Apr 2022 15:09:33 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 1C8C32B5D7 for ; Wed, 6 Apr 2022 15:09:03 +0200 (CEST) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS id B4FF12B5CC for ; Wed, 6 Apr 2022 15:09:00 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 89ECC41978 for ; Wed, 6 Apr 2022 15:09:00 +0200 (CEST) Message-ID: <45f18be5-0739-f1da-6b88-3a383bf7e838@proxmox.com> Date: Wed, 6 Apr 2022 15:08:27 +0200 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.7.0 Content-Language: en-US To: Proxmox Backup Server development discussion , Hannes Laimer References: <20220217171457.72206-1-h.laimer@proxmox.com> <20220217171457.72206-3-h.laimer@proxmox.com> From: Dylan Whyte In-Reply-To: <20220217171457.72206-3-h.laimer@proxmox.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.487 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment NICE_REPLY_A -0.631 Looks like a legit reply (A) POISEN_SPAM_PILL 0.1 Meta: its spam POISEN_SPAM_PILL_1 0.1 random spam to be learned in bayes POISEN_SPAM_PILL_3 0.1 random spam to be learned in bayes SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record T_SCC_BODY_TEXT_LINE -0.01 - Subject: Re: [pbs-devel] [PATCH proxmox-backup v9 2/6] datastore: add check for maintenance in lookup X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 06 Apr 2022 13:09:33 -0000 Minor comment inline: On 2/17/22 18:14, Hannes Laimer wrote: > Signed-off-by: Hannes Laimer > --- > pbs-api-types/src/maintenance.rs | 23 +++++++++++-- > pbs-datastore/src/datastore.rs | 17 +++++++--- > pbs-datastore/src/snapshot_reader.rs | 6 +++- > src/api2/admin/datastore.rs | 50 ++++++++++++++-------------- > src/api2/backup/mod.rs | 4 +-- > src/api2/reader/mod.rs | 6 ++-- > src/api2/status.rs | 4 +-- > src/api2/tape/backup.rs | 6 ++-- > src/api2/tape/restore.rs | 6 ++-- > src/bin/proxmox-backup-proxy.rs | 4 +-- > src/server/prune_job.rs | 4 +-- > src/server/pull.rs | 4 +-- > src/server/verify_job.rs | 4 +-- > 13 files changed, 85 insertions(+), 53 deletions(-) > > diff --git a/pbs-api-types/src/maintenance.rs b/pbs-api-types/src/maintenance.rs > index 19883e46..55d66964 100644 > --- a/pbs-api-types/src/maintenance.rs > +++ b/pbs-api-types/src/maintenance.rs > @@ -1,3 +1,5 @@ > +use std::borrow::Cow; > +use anyhow::{bail, Error}; > use serde::{Deserialize, Serialize}; > > use proxmox_schema::{api, ApiStringFormat, const_regex, Schema, StringSchema}; > @@ -24,7 +26,7 @@ pub enum Operation { > } > > #[api] > -#[derive(Deserialize, Serialize)] > +#[derive(Deserialize, Serialize, PartialEq)] > #[serde(rename_all="kebab-case")] > /// Maintenance type. > pub enum MaintenanceType { > @@ -49,7 +51,7 @@ pub enum MaintenanceType { > #[derive(Deserialize, Serialize)] > /// Maintenance mode > pub struct MaintenanceMode { > - /// Type of the maintenance > + /// Type of the maintenance. > #[serde(rename = "type")] > ty: MaintenanceType, > > @@ -57,3 +59,20 @@ pub struct MaintenanceMode { > #[serde(skip_serializing_if = "Option::is_none")] > message: Option, > } > + > +impl MaintenanceMode { > + pub fn check(&self, operation: Option) -> Result<(), Error> { > + let message = percent_encoding::percent_decode_str(self.message.as_deref().unwrap_or("")) > + .decode_utf8() > + .unwrap_or(Cow::Borrowed("")); You could possibly add a more generic default/fallback message here, such as "contact the administrator for more info". This adds less confusion, given the trailing semi-colon below, but is really not a big deal in any case. > + > + if self.ty == MaintenanceType::Offline { > + bail!("offline maintenance mode: {}", message); > + } else if self.ty == MaintenanceType::ReadOnly { > + if let Some(Operation::Write) = operation { > + bail!("read-only maintenance mode: {}", message); > + } > + } > + Ok(()) > + } > +} > diff --git a/pbs-datastore/src/datastore.rs b/pbs-datastore/src/datastore.rs > index 7044e074..902848d6 100644 > --- a/pbs-datastore/src/datastore.rs > +++ b/pbs-datastore/src/datastore.rs > @@ -15,7 +15,9 @@ use proxmox_sys::WorkerTaskContext; > use proxmox_sys::{task_log, task_warn}; > use proxmox_sys::fs::{lock_dir_noblock, DirLockGuard}; > > -use pbs_api_types::{UPID, DataStoreConfig, Authid, GarbageCollectionStatus, HumanByte}; > +use pbs_api_types::{ > + UPID, DataStoreConfig, Authid, Operation, GarbageCollectionStatus, HumanByte > +}; > use pbs_config::{open_backup_lockfile, BackupLockGuard}; > > use crate::DataBlob; > @@ -60,13 +62,20 @@ pub struct DataStore { > } > > impl DataStore { > - > - pub fn lookup_datastore(name: &str) -> Result, Error> { > - > + pub fn lookup_datastore( > + name: &str, > + operation: Option, > + ) -> Result, Error> { > let (config, _digest) = pbs_config::datastore::config()?; > let config: DataStoreConfig = config.lookup("datastore", name)?; > let path = PathBuf::from(&config.path); > > + if let Some(maintenance_mode) = config.get_maintenance_mode() { > + if let Err(error) = maintenance_mode.check(operation) { > + bail!("datastore '{}' is in {}", name, error); > + } > + } > + > let mut map = DATASTORE_MAP.lock().unwrap(); > > if let Some(datastore) = map.get(name) { > diff --git a/pbs-datastore/src/snapshot_reader.rs b/pbs-datastore/src/snapshot_reader.rs > index 18bc0d83..65abac7d 100644 > --- a/pbs-datastore/src/snapshot_reader.rs > +++ b/pbs-datastore/src/snapshot_reader.rs > @@ -14,6 +14,7 @@ use crate::fixed_index::FixedIndexReader; > use crate::dynamic_index::DynamicIndexReader; > use crate::manifest::{archive_type, ArchiveType, CLIENT_LOG_BLOB_NAME, MANIFEST_BLOB_NAME}; > use crate::DataStore; > +use pbs_api_types::Operation; > > /// Helper to access the contents of a datastore backup snapshot > /// > @@ -120,7 +121,10 @@ impl <'a> Iterator for SnapshotChunkIterator<'a> { > }; > > let datastore = > - DataStore::lookup_datastore(self.snapshot_reader.datastore_name())?; > + DataStore::lookup_datastore( > + self.snapshot_reader.datastore_name(), > + Some(Operation::Read) > + )?; > let order = datastore.get_chunks_in_order(&index, |_| false, |_| Ok(()))?; > > self.current_index = Some((Arc::new(index), 0, order)); > diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs > index 263ea96f..ce710938 100644 > --- a/src/api2/admin/datastore.rs > +++ b/src/api2/admin/datastore.rs > @@ -30,7 +30,7 @@ use pxar::EntryKind; > > use pbs_api_types::{ Authid, BackupContent, Counts, CryptMode, > DataStoreListItem, GarbageCollectionStatus, GroupListItem, > - SnapshotListItem, SnapshotVerifyState, PruneOptions, > + Operation, SnapshotListItem, SnapshotVerifyState, PruneOptions, > DataStoreStatus, RRDMode, RRDTimeFrame, > BACKUP_ARCHIVE_NAME_SCHEMA, BACKUP_ID_SCHEMA, BACKUP_TIME_SCHEMA, > BACKUP_TYPE_SCHEMA, DATASTORE_SCHEMA, > @@ -170,7 +170,7 @@ pub fn list_groups( > let user_info = CachedUserInfo::new()?; > let user_privs = user_info.lookup_privs(&auth_id, &["datastore", &store]); > > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Read))?; > let list_all = (user_privs & PRIV_DATASTORE_AUDIT) != 0; > > let backup_groups = BackupInfo::list_backup_groups(&datastore.base_path())?; > @@ -268,7 +268,7 @@ pub fn delete_group( > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > > let group = BackupGroup::new(backup_type, backup_id); > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Write))?; > > check_priv_or_backup_owner(&datastore, &group, &auth_id, PRIV_DATASTORE_MODIFY)?; > > @@ -315,7 +315,7 @@ pub fn list_snapshot_files( > ) -> Result, Error> { > > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Read))?; > > let snapshot = BackupDir::new(backup_type, backup_id, backup_time)?; > > @@ -365,7 +365,7 @@ pub fn delete_snapshot( > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > > let snapshot = BackupDir::new(backup_type, backup_id, backup_time)?; > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Write))?; > > check_priv_or_backup_owner(&datastore, snapshot.group(), &auth_id, PRIV_DATASTORE_MODIFY)?; > > @@ -414,7 +414,7 @@ pub fn list_snapshots ( > > let list_all = (user_privs & PRIV_DATASTORE_AUDIT) != 0; > > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Read))?; > > let base_path = datastore.base_path(); > > @@ -615,7 +615,7 @@ pub fn status( > _info: &ApiMethod, > rpcenv: &mut dyn RpcEnvironment, > ) -> Result { > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Read))?; > let storage = crate::tools::disks::disk_usage(&datastore.base_path())?; > let (counts, gc_status) = if verbose { > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > @@ -693,7 +693,7 @@ pub fn verify( > outdated_after: Option, > rpcenv: &mut dyn RpcEnvironment, > ) -> Result { > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Read))?; > let ignore_verified = ignore_verified.unwrap_or(true); > > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > @@ -838,7 +838,7 @@ pub fn prune( > > let group = BackupGroup::new(&backup_type, &backup_id); > > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Write))?; > > check_priv_or_backup_owner(&datastore, &group, &auth_id, PRIV_DATASTORE_MODIFY)?; > > @@ -963,7 +963,7 @@ pub fn prune_datastore( > > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Write))?; > > let to_stdout = rpcenv.env_type() == RpcEnvironmentType::CLI; > > @@ -1007,7 +1007,7 @@ pub fn start_garbage_collection( > rpcenv: &mut dyn RpcEnvironment, > ) -> Result { > > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Write))?; > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > > let job = Job::new("garbage_collection", &store) > @@ -1043,7 +1043,7 @@ pub fn garbage_collection_status( > _rpcenv: &mut dyn RpcEnvironment, > ) -> Result { > > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Read))?; > > let status = datastore.last_gc_status(); > > @@ -1119,7 +1119,7 @@ pub fn download_file( > > async move { > let store = required_string_param(¶m, "store")?; > - let datastore = DataStore::lookup_datastore(store)?; > + let datastore = DataStore::lookup_datastore(store, Some(Operation::Read))?; > > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > > @@ -1189,7 +1189,7 @@ pub fn download_file_decoded( > > async move { > let store = required_string_param(¶m, "store")?; > - let datastore = DataStore::lookup_datastore(store)?; > + let datastore = DataStore::lookup_datastore(store, Some(Operation::Read))?; > > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > > @@ -1303,7 +1303,7 @@ pub fn upload_backup_log( > > async move { > let store = required_string_param(¶m, "store")?; > - let datastore = DataStore::lookup_datastore(store)?; > + let datastore = DataStore::lookup_datastore(store, Some(Operation::Write))?; > > let file_name = CLIENT_LOG_BLOB_NAME; > > @@ -1380,7 +1380,7 @@ pub fn catalog( > filepath: String, > rpcenv: &mut dyn RpcEnvironment, > ) -> Result, Error> { > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Read))?; > > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > > @@ -1450,7 +1450,7 @@ pub fn pxar_file_download( > > async move { > let store = required_string_param(¶m, "store")?; > - let datastore = DataStore::lookup_datastore(store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Read))?; > > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > > @@ -1567,7 +1567,7 @@ pub fn get_rrd_stats( > _param: Value, > ) -> Result { > > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Read))?; > let disk_manager = crate::tools::disks::DiskManage::new(); > > let mut rrd_fields = vec![ > @@ -1615,7 +1615,7 @@ pub fn get_group_notes( > backup_id: String, > rpcenv: &mut dyn RpcEnvironment, > ) -> Result { > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Read))?; > > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > let backup_group = BackupGroup::new(backup_type, backup_id); > @@ -1657,7 +1657,7 @@ pub fn set_group_notes( > notes: String, > rpcenv: &mut dyn RpcEnvironment, > ) -> Result<(), Error> { > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Write))?; > > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > let backup_group = BackupGroup::new(backup_type, backup_id); > @@ -1699,7 +1699,7 @@ pub fn get_notes( > backup_time: i64, > rpcenv: &mut dyn RpcEnvironment, > ) -> Result { > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Read))?; > > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > let backup_dir = BackupDir::new(backup_type, backup_id, backup_time)?; > @@ -1750,7 +1750,7 @@ pub fn set_notes( > notes: String, > rpcenv: &mut dyn RpcEnvironment, > ) -> Result<(), Error> { > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Write))?; > > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > let backup_dir = BackupDir::new(backup_type, backup_id, backup_time)?; > @@ -1793,7 +1793,7 @@ pub fn get_protection( > backup_time: i64, > rpcenv: &mut dyn RpcEnvironment, > ) -> Result { > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Read))?; > > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > let backup_dir = BackupDir::new(backup_type, backup_id, backup_time)?; > @@ -1838,7 +1838,7 @@ pub fn set_protection( > protected: bool, > rpcenv: &mut dyn RpcEnvironment, > ) -> Result<(), Error> { > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Write))?; > > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > let backup_dir = BackupDir::new(backup_type, backup_id, backup_time)?; > @@ -1879,7 +1879,7 @@ pub fn set_backup_owner( > rpcenv: &mut dyn RpcEnvironment, > ) -> Result<(), Error> { > > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Write))?; > > let backup_group = BackupGroup::new(backup_type, backup_id); > > diff --git a/src/api2/backup/mod.rs b/src/api2/backup/mod.rs > index 395edd3d..9d62dc52 100644 > --- a/src/api2/backup/mod.rs > +++ b/src/api2/backup/mod.rs > @@ -16,7 +16,7 @@ use proxmox_router::{ > use proxmox_schema::*; > > use pbs_api_types::{ > - Authid, VerifyState, SnapshotVerifyState, > + Authid, Operation, VerifyState, SnapshotVerifyState, > BACKUP_ID_SCHEMA, BACKUP_TIME_SCHEMA, BACKUP_TYPE_SCHEMA, DATASTORE_SCHEMA, > CHUNK_DIGEST_SCHEMA, PRIV_DATASTORE_BACKUP, BACKUP_ARCHIVE_NAME_SCHEMA, > }; > @@ -77,7 +77,7 @@ async move { > let user_info = CachedUserInfo::new()?; > user_info.check_privs(&auth_id, &["datastore", &store], PRIV_DATASTORE_BACKUP, false)?; > > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Write))?; > > let backup_type = required_string_param(¶m, "backup-type")?; > let backup_id = required_string_param(¶m, "backup-id")?; > diff --git a/src/api2/reader/mod.rs b/src/api2/reader/mod.rs > index 2b11d1b1..45cefe5d 100644 > --- a/src/api2/reader/mod.rs > +++ b/src/api2/reader/mod.rs > @@ -16,8 +16,8 @@ use proxmox_router::{ > use proxmox_schema::{BooleanSchema, ObjectSchema}; > > use pbs_api_types::{ > - Authid, DATASTORE_SCHEMA, BACKUP_TYPE_SCHEMA, BACKUP_TIME_SCHEMA, BACKUP_ID_SCHEMA, > - CHUNK_DIGEST_SCHEMA, PRIV_DATASTORE_READ, PRIV_DATASTORE_BACKUP, > + Authid, Operation, DATASTORE_SCHEMA, BACKUP_TYPE_SCHEMA, BACKUP_TIME_SCHEMA, > + BACKUP_ID_SCHEMA, CHUNK_DIGEST_SCHEMA, PRIV_DATASTORE_READ, PRIV_DATASTORE_BACKUP, > BACKUP_ARCHIVE_NAME_SCHEMA, > }; > use proxmox_sys::fs::lock_dir_noblock_shared; > @@ -81,7 +81,7 @@ fn upgrade_to_backup_reader_protocol( > bail!("no permissions on /datastore/{}", store); > } > > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Read))?; > > let backup_type = required_string_param(¶m, "backup-type")?; > let backup_id = required_string_param(¶m, "backup-id")?; > diff --git a/src/api2/status.rs b/src/api2/status.rs > index 029529ac..b589951d 100644 > --- a/src/api2/status.rs > +++ b/src/api2/status.rs > @@ -14,7 +14,7 @@ use proxmox_router::{ > use proxmox_router::list_subdirs_api_method; > > use pbs_api_types::{ > - Authid, DATASTORE_SCHEMA, RRDMode, RRDTimeFrame, > + Authid, Operation, DATASTORE_SCHEMA, RRDMode, RRDTimeFrame, > PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP, > }; > > @@ -97,7 +97,7 @@ pub fn datastore_status( > continue; > } > > - let datastore = match DataStore::lookup_datastore(store) { > + let datastore = match DataStore::lookup_datastore(&store, Some(Operation::Read)) { > Ok(datastore) => datastore, > Err(err) => { > list.push(json!({ > diff --git a/src/api2/tape/backup.rs b/src/api2/tape/backup.rs > index 1462f200..28b24168 100644 > --- a/src/api2/tape/backup.rs > +++ b/src/api2/tape/backup.rs > @@ -10,7 +10,7 @@ use proxmox_schema::api; > use proxmox_sys::{task_log, task_warn, WorkerTaskContext}; > > use pbs_api_types::{ > - Authid, Userid, TapeBackupJobConfig, TapeBackupJobSetup, TapeBackupJobStatus, MediaPoolConfig, > + Authid, Userid, Operation, TapeBackupJobConfig, TapeBackupJobSetup, TapeBackupJobStatus, MediaPoolConfig, > UPID_SCHEMA, JOB_ID_SCHEMA, PRIV_DATASTORE_READ, PRIV_TAPE_AUDIT, PRIV_TAPE_WRITE, > GroupFilter, > }; > @@ -168,7 +168,7 @@ pub fn do_tape_backup_job( > > let worker_type = job.jobtype().to_string(); > > - let datastore = DataStore::lookup_datastore(&setup.store)?; > + let datastore = DataStore::lookup_datastore(&setup.store, Some(Operation::Read))?; > > let (config, _digest) = pbs_config::media_pool::config()?; > let pool_config: MediaPoolConfig = config.lookup("pool", &setup.pool)?; > @@ -349,7 +349,7 @@ pub fn backup( > &setup.drive, > )?; > > - let datastore = DataStore::lookup_datastore(&setup.store)?; > + let datastore = DataStore::lookup_datastore(&setup.store, Some(Operation::Read))?; > > let (config, _digest) = pbs_config::media_pool::config()?; > let pool_config: MediaPoolConfig = config.lookup("pool", &setup.pool)?; > diff --git a/src/api2/tape/restore.rs b/src/api2/tape/restore.rs > index 2ce16c9d..59f098d9 100644 > --- a/src/api2/tape/restore.rs > +++ b/src/api2/tape/restore.rs > @@ -17,7 +17,7 @@ use proxmox_uuid::Uuid; > use proxmox_sys::{task_log, task_warn, WorkerTaskContext}; > > use pbs_api_types::{ > - Authid, Userid, CryptMode, > + Authid, Operation, Userid, CryptMode, > DATASTORE_MAP_ARRAY_SCHEMA, DATASTORE_MAP_LIST_SCHEMA, DRIVE_NAME_SCHEMA, > UPID_SCHEMA, TAPE_RESTORE_SNAPSHOT_SCHEMA, > PRIV_DATASTORE_BACKUP, PRIV_DATASTORE_MODIFY, PRIV_TAPE_READ, > @@ -93,10 +93,10 @@ impl TryFrom for DataStoreMap { > if let Some(index) = store.find('=') { > let mut target = store.split_off(index); > target.remove(0); // remove '=' > - let datastore = DataStore::lookup_datastore(&target)?; > + let datastore = DataStore::lookup_datastore(&target, Some(Operation::Write))?; > map.insert(store, datastore); > } else if default.is_none() { > - default = Some(DataStore::lookup_datastore(&store)?); > + default = Some(DataStore::lookup_datastore(&store, Some(Operation::Write))?); > } else { > bail!("multiple default stores given"); > } > diff --git a/src/bin/proxmox-backup-proxy.rs b/src/bin/proxmox-backup-proxy.rs > index a4f20af1..e8315e5f 100644 > --- a/src/bin/proxmox-backup-proxy.rs > +++ b/src/bin/proxmox-backup-proxy.rs > @@ -48,7 +48,7 @@ use proxmox_time::CalendarEvent; > > use pbs_api_types::{ > Authid, DataStoreConfig, PruneOptions, SyncJobConfig, TapeBackupJobConfig, > - VerificationJobConfig, > + VerificationJobConfig, Operation > }; > > use proxmox_rest_server::daemon; > @@ -560,7 +560,7 @@ async fn schedule_datastore_garbage_collection() { > }; > > for (store, (_, store_config)) in config.sections { > - let datastore = match DataStore::lookup_datastore(&store) { > + let datastore = match DataStore::lookup_datastore(&store, Some(Operation::Write)) { > Ok(datastore) => datastore, > Err(err) => { > eprintln!("lookup_datastore failed - {}", err); > diff --git a/src/server/prune_job.rs b/src/server/prune_job.rs > index 825fd60d..d9a6651e 100644 > --- a/src/server/prune_job.rs > +++ b/src/server/prune_job.rs > @@ -7,7 +7,7 @@ use proxmox_sys::{task_log, task_warn}; > use pbs_datastore::backup_info::BackupInfo; > use pbs_datastore::prune::compute_prune_info; > use pbs_datastore::DataStore; > -use pbs_api_types::{Authid, PRIV_DATASTORE_MODIFY, PruneOptions}; > +use pbs_api_types::{Authid, Operation, PRIV_DATASTORE_MODIFY, PruneOptions}; > use pbs_config::CachedUserInfo; > use proxmox_rest_server::WorkerTask; > > @@ -97,7 +97,7 @@ pub fn do_prune_job( > auth_id: &Authid, > schedule: Option, > ) -> Result { > - let datastore = DataStore::lookup_datastore(&store)?; > + let datastore = DataStore::lookup_datastore(&store, Some(Operation::Write))?; > > let worker_type = job.jobtype().to_string(); > let auth_id = auth_id.clone(); > diff --git a/src/server/pull.rs b/src/server/pull.rs > index a2a5f1f1..559533a6 100644 > --- a/src/server/pull.rs > +++ b/src/server/pull.rs > @@ -16,7 +16,7 @@ use proxmox_sys::task_log; > > use pbs_api_types::{ > Authid, GroupFilter, GroupListItem, RateLimitConfig, Remote, > - SnapshotListItem, > + Operation, SnapshotListItem, > }; > > use pbs_datastore::{BackupDir, BackupInfo, BackupGroup, DataStore, StoreProgress}; > @@ -57,7 +57,7 @@ impl PullParameters { > group_filter: Option>, > limit: RateLimitConfig, > ) -> Result { > - let store = DataStore::lookup_datastore(store)?; > + let store = DataStore::lookup_datastore(store, Some(Operation::Write))?; > > let (remote_config, _digest) = pbs_config::remote::config()?; > let remote: Remote = remote_config.lookup("remote", remote)?; > diff --git a/src/server/verify_job.rs b/src/server/verify_job.rs > index a23eb04e..e472ed91 100644 > --- a/src/server/verify_job.rs > +++ b/src/server/verify_job.rs > @@ -1,7 +1,7 @@ > use anyhow::{format_err, Error}; > > use proxmox_sys::task_log; > -use pbs_api_types::{Authid, VerificationJobConfig}; > +use pbs_api_types::{Authid, Operation, VerificationJobConfig}; > use proxmox_rest_server::WorkerTask; > use pbs_datastore::DataStore; > > @@ -22,7 +22,7 @@ pub fn do_verification_job( > to_stdout: bool, > ) -> Result { > > - let datastore = DataStore::lookup_datastore(&verification_job.store)?; > + let datastore = DataStore::lookup_datastore(&verification_job.store, Some(Operation::Read))?; > > let outdated_after = verification_job.outdated_after; > let ignore_verified_snapshots = verification_job.ignore_verified.unwrap_or(true);