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 685EF71064 for ; Fri, 1 Oct 2021 10:29:03 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 5BCC928EA7 for ; Fri, 1 Oct 2021 10:28:33 +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 3AA4728E9A for ; Fri, 1 Oct 2021 10:28:32 +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 0C4DB453D3; Fri, 1 Oct 2021 10:28:32 +0200 (CEST) Message-ID: <041bd568-2ef0-68a5-eb99-1548a8b1fab4@proxmox.com> Date: Fri, 1 Oct 2021 10:28:30 +0200 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:93.0) Gecko/20100101 Thunderbird/93.0 Content-Language: en-US To: Proxmox Backup Server development discussion , Hannes Laimer References: <20210928100548.4873-1-h.laimer@proxmox.com> <20210928100548.4873-5-h.laimer@proxmox.com> From: Dominik Csapak In-Reply-To: <20210928100548.4873-5-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 2.078 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 -3.499 Looks like a legit reply (A) SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: Re: [pbs-devel] [PATCH proxmox-backup 4/5] jobs/api2: add checks for maintenance 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: Fri, 01 Oct 2021 08:29:03 -0000 On 9/28/21 12:05, Hannes Laimer wrote: > --- > src/api2/admin/datastore.rs | 48 +++++++++++++++++++++++++++++++++---- > src/api2/pull.rs | 5 +++- > src/server/gc_job.rs | 5 ++-- > src/server/prune_job.rs | 4 +++- > src/server/verify_job.rs | 5 ++-- > 5 files changed, 56 insertions(+), 11 deletions(-) > > diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs > index 7e9a0ee0..f5ed6603 100644 > --- a/src/api2/admin/datastore.rs > +++ b/src/api2/admin/datastore.rs > @@ -29,7 +29,7 @@ use pxar::EntryKind; > use pbs_api_types::{ Authid, BackupContent, Counts, CryptMode, > DataStoreListItem, GarbageCollectionStatus, GroupListItem, > SnapshotListItem, SnapshotVerifyState, PruneOptions, > - DataStoreStatus, RRDMode, RRDTimeFrameResolution, > + DataStoreStatus, RRDMode, RRDTimeFrameResolution, MaintenanceType, > BACKUP_ARCHIVE_NAME_SCHEMA, BACKUP_ID_SCHEMA, BACKUP_TIME_SCHEMA, > BACKUP_TYPE_SCHEMA, DATASTORE_SCHEMA, > IGNORE_VERIFIED_BACKUPS_SCHEMA, UPID_SCHEMA, > @@ -83,6 +83,7 @@ fn check_priv_or_backup_owner( > auth_id: &Authid, > required_privs: u64, > ) -> Result<(), Error> { > + store.check_maintenance(MaintenanceType::Offline)?; > let user_info = CachedUserInfo::new()?; > let privs = user_info.lookup_privs(&auth_id, &["datastore", store.name()]); > > @@ -97,7 +98,7 @@ fn read_backup_index( > store: &DataStore, > backup_dir: &BackupDir, > ) -> Result<(BackupManifest, Vec), Error> { > - > + store.check_maintenance(MaintenanceType::Offline)?; > let (manifest, index_size) = store.load_manifest(backup_dir)?; > > let mut result = Vec::new(); > @@ -125,7 +126,7 @@ fn get_all_snapshot_files( > store: &DataStore, > info: &BackupInfo, > ) -> Result<(BackupManifest, Vec), Error> { > - > + store.check_maintenance(MaintenanceType::Offline)?; > let (manifest, mut files) = read_backup_index(&store, &info.backup_dir)?; > > let file_set = files.iter().fold(HashSet::new(), |mut acc, item| { > @@ -172,6 +173,9 @@ pub fn list_groups( > let user_privs = user_info.lookup_privs(&auth_id, &["datastore", &store]); > > let datastore = DataStore::lookup_datastore(&store)?; > + > + datastore.check_maintenance(MaintenanceType::Offline)?; > + > let list_all = (user_privs & PRIV_DATASTORE_AUDIT) != 0; > > let backup_groups = BackupInfo::list_backup_groups(&datastore.base_path())?; > @@ -267,9 +271,11 @@ pub fn delete_group( > ) -> Result { > > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > + let datastore = DataStore::lookup_datastore(&store)?; > + > + datastore.check_maintenance(MaintenanceType::ReadOnly)?; > > let group = BackupGroup::new(backup_type, backup_id); > - let datastore = DataStore::lookup_datastore(&store)?; > > check_priv_or_backup_owner(&datastore, &group, &auth_id, PRIV_DATASTORE_MODIFY)?; > > @@ -316,6 +322,8 @@ pub fn list_snapshot_files( > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > let datastore = DataStore::lookup_datastore(&store)?; > > + datastore.check_maintenance(MaintenanceType::Offline)?; > + > let snapshot = BackupDir::new(backup_type, backup_id, backup_time)?; > > check_priv_or_backup_owner(&datastore, snapshot.group(), &auth_id, PRIV_DATASTORE_AUDIT | PRIV_DATASTORE_READ)?; > @@ -362,9 +370,12 @@ pub fn delete_snapshot( > ) -> Result { > > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > + > + let datastore = DataStore::lookup_datastore(&store)?; > + > + datastore.check_maintenance(MaintenanceType::ReadOnly)?; > > let snapshot = BackupDir::new(backup_type, backup_id, backup_time)?; > - let datastore = DataStore::lookup_datastore(&store)?; > > check_priv_or_backup_owner(&datastore, snapshot.group(), &auth_id, PRIV_DATASTORE_MODIFY)?; > > @@ -415,6 +426,8 @@ pub fn list_snapshots ( > > let datastore = DataStore::lookup_datastore(&store)?; > > + datastore.check_maintenance(MaintenanceType::Offline)?; > + > let base_path = datastore.base_path(); > > let groups = match (backup_type, backup_id) { > @@ -686,6 +699,9 @@ pub fn verify( > rpcenv: &mut dyn RpcEnvironment, > ) -> Result { > let datastore = DataStore::lookup_datastore(&store)?; > + > + datastore.check_maintenance(MaintenanceType::Offline)?; > + > let ignore_verified = ignore_verified.unwrap_or(true); > > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > @@ -832,6 +848,8 @@ pub fn prune( > > let datastore = DataStore::lookup_datastore(&store)?; > > + datastore.check_maintenance(MaintenanceType::ReadOnly)?; > + > check_priv_or_backup_owner(&datastore, &group, &auth_id, PRIV_DATASTORE_MODIFY)?; > > let worker_id = format!("{}:{}/{}", store, &backup_type, &backup_id); > @@ -1035,6 +1053,8 @@ pub fn garbage_collection_status( > > let datastore = DataStore::lookup_datastore(&store)?; > > + datastore.check_maintenance(MaintenanceType::Offline)?; > + i was confused here at first, why garbage collect why garbage collect needs only read access, then noticed it's the status. but the status is not really a 'read' operation on the datastore? its more like the config or a task log since it only shows the status of the last gc > let status = datastore.last_gc_status(); > > Ok(status) > @@ -1111,6 +1131,8 @@ pub fn download_file( > let store = required_string_param(¶m, "store")?; > let datastore = DataStore::lookup_datastore(store)?; > > + datastore.check_maintenance(MaintenanceType::Offline)?; > + > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > > let file_name = required_string_param(¶m, "file-name")?.to_owned(); > @@ -1181,6 +1203,8 @@ pub fn download_file_decoded( > let store = required_string_param(¶m, "store")?; > let datastore = DataStore::lookup_datastore(store)?; > > + datastore.check_maintenance(MaintenanceType::Offline)?; > + > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > > let file_name = required_string_param(¶m, "file-name")?.to_owned(); > @@ -1372,6 +1396,8 @@ pub fn catalog( > ) -> Result, Error> { > let datastore = DataStore::lookup_datastore(&store)?; > > + datastore.check_maintenance(MaintenanceType::Offline)?; > + > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > > let backup_dir = BackupDir::new(backup_type, backup_id, backup_time)?; > @@ -1442,6 +1468,8 @@ pub fn pxar_file_download( > let store = required_string_param(¶m, "store")?; > let datastore = DataStore::lookup_datastore(&store)?; > > + datastore.check_maintenance(MaintenanceType::Offline)?; > + > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > > let filepath = required_string_param(¶m, "filepath")?.to_owned(); > @@ -1597,6 +1625,8 @@ pub fn get_group_notes( > ) -> Result { > let datastore = DataStore::lookup_datastore(&store)?; > > + datastore.check_maintenance(MaintenanceType::Offline)?; > + > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > let backup_group = BackupGroup::new(backup_type, backup_id); > > @@ -1639,6 +1669,8 @@ pub fn set_group_notes( > ) -> Result<(), Error> { > let datastore = DataStore::lookup_datastore(&store)?; > > + datastore.check_maintenance(MaintenanceType::ReadOnly)?; > + > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > let backup_group = BackupGroup::new(backup_type, backup_id); > > @@ -1681,6 +1713,8 @@ pub fn get_notes( > ) -> Result { > let datastore = DataStore::lookup_datastore(&store)?; > > + datastore.check_maintenance(MaintenanceType::Offline)?; > + > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > let backup_dir = BackupDir::new(backup_type, backup_id, backup_time)?; > > @@ -1732,6 +1766,8 @@ pub fn set_notes( > ) -> Result<(), Error> { > let datastore = DataStore::lookup_datastore(&store)?; > > + datastore.check_maintenance(MaintenanceType::ReadOnly)?; > + > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > let backup_dir = BackupDir::new(backup_type, backup_id, backup_time)?; > > @@ -1777,6 +1813,8 @@ pub fn set_backup_owner( > > let datastore = DataStore::lookup_datastore(&store)?; > > + datastore.check_maintenance(MaintenanceType::ReadOnly)?; > + > let backup_group = BackupGroup::new(backup_type, backup_id); > > let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; > diff --git a/src/api2/pull.rs b/src/api2/pull.rs > index ea8faab8..b1669288 100644 > --- a/src/api2/pull.rs > +++ b/src/api2/pull.rs > @@ -9,7 +9,7 @@ use proxmox::api::{ApiMethod, Router, RpcEnvironment, Permission}; > > use pbs_client::{HttpClient, BackupRepository}; > use pbs_api_types::{ > - Remote, Authid, SyncJobConfig, > + Remote, Authid, SyncJobConfig, MaintenanceType, > DATASTORE_SCHEMA, REMOTE_ID_SCHEMA, REMOVE_VANISHED_BACKUPS_SCHEMA, > PRIV_DATASTORE_BACKUP, PRIV_DATASTORE_PRUNE, PRIV_REMOTE_READ, > }; > @@ -71,6 +71,9 @@ pub fn do_sync_job( > to_stdout: bool, > ) -> Result { > > + let datastore = DataStore::lookup_datastore(&sync_job.store)?; > + datastore.check_maintenance(MaintenanceType::ReadOnly)?; > + > let job_id = format!("{}:{}:{}:{}", > sync_job.remote, > sync_job.remote_store, > diff --git a/src/server/gc_job.rs b/src/server/gc_job.rs > index 794fe146..be04b635 100644 > --- a/src/server/gc_job.rs > +++ b/src/server/gc_job.rs > @@ -1,7 +1,7 @@ > use std::sync::Arc; > use anyhow::Error; > > -use pbs_api_types::Authid; > +use pbs_api_types::{Authid, MaintenanceType}; > use pbs_tools::task_log; > use pbs_datastore::DataStore; > use proxmox_rest_server::WorkerTask; > @@ -16,7 +16,8 @@ pub fn do_garbage_collection_job( > schedule: Option, > to_stdout: bool, > ) -> Result { > - > + datastore.check_maintenance(MaintenanceType::ReadOnly)?; > + > let store = datastore.name().to_string(); > > let (email, notify) = crate::server::lookup_datastore_notify_settings(&store); > diff --git a/src/server/prune_job.rs b/src/server/prune_job.rs > index fc6443e9..84131634 100644 > --- a/src/server/prune_job.rs > +++ b/src/server/prune_job.rs > @@ -5,7 +5,7 @@ use anyhow::Error; > 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, MaintenanceType, PRIV_DATASTORE_MODIFY, PruneOptions}; > use pbs_config::CachedUserInfo; > use pbs_tools::{task_log, task_warn}; > use proxmox_rest_server::WorkerTask; > @@ -20,6 +20,8 @@ pub fn prune_datastore( > datastore: Arc, > dry_run: bool, > ) -> Result<(), Error> { > + datastore.check_maintenance(MaintenanceType::ReadOnly)?; > + > task_log!(worker, "Starting datastore prune on store \"{}\"", store); > > if dry_run { > diff --git a/src/server/verify_job.rs b/src/server/verify_job.rs > index 6aba97c9..3b2b1472 100644 > --- a/src/server/verify_job.rs > +++ b/src/server/verify_job.rs > @@ -1,7 +1,7 @@ > use anyhow::{format_err, Error}; > > use pbs_tools::task_log; > -use pbs_api_types::{Authid, VerificationJobConfig}; > +use pbs_api_types::{Authid, VerificationJobConfig, MaintenanceType}; > use proxmox_rest_server::WorkerTask; > use pbs_datastore::DataStore; > > @@ -21,9 +21,10 @@ pub fn do_verification_job( > schedule: Option, > to_stdout: bool, > ) -> Result { > - > let datastore = DataStore::lookup_datastore(&verification_job.store)?; > > + datastore.check_maintenance(MaintenanceType::ReadOnly)?; > + why does a verification write access? because of the verify status in the manifest? imho that reason would be good to have in a comment > let outdated_after = verification_job.outdated_after; > let ignore_verified_snapshots = verification_job.ignore_verified.unwrap_or(true); > >