]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/pull.rs
api2/pull: refactor priv checking and creating pull parameters
[proxmox-backup.git] / src / api2 / pull.rs
CommitLineData
eb506c83 1//! Sync datastore from remote server
268687dd 2use std::sync::{Arc};
eb506c83 3
07ad6470 4use anyhow::{format_err, Error};
de8ec041
DM
5
6use proxmox::api::api;
404d78c4 7use proxmox::api::{ApiMethod, Router, RpcEnvironment, Permission};
de8ec041
DM
8
9use crate::server::{WorkerTask};
07ad6470
DM
10use crate::backup::DataStore;
11use crate::client::{HttpClient, HttpClientOptions, BackupRepository, pull::pull_store};
de8ec041 12use crate::api2::types::*;
07ad6470
DM
13use crate::config::{
14 remote,
15 acl::{PRIV_DATASTORE_BACKUP, PRIV_DATASTORE_PRUNE, PRIV_REMOTE_READ},
16 cached_user_info::CachedUserInfo,
17};
de8ec041 18
268687dd
DC
19
20pub fn check_pull_privs(
21 username: &str,
22 store: &str,
23 remote: &str,
24 remote_store: &str,
25 delete: bool,
26) -> Result<(), Error> {
27
28 let user_info = CachedUserInfo::new()?;
29
30 user_info.check_privs(username, &["datastore", store], PRIV_DATASTORE_BACKUP, false)?;
31 user_info.check_privs(username, &["remote", remote, remote_store], PRIV_REMOTE_READ, false)?;
32
33 if delete {
34 user_info.check_privs(username, &["datastore", store], PRIV_DATASTORE_PRUNE, false)?;
35 }
36
37 Ok(())
38}
39
40pub async fn get_pull_parameters(
41 store: &str,
42 remote: &str,
43 remote_store: &str,
44) -> Result<(HttpClient, BackupRepository, Arc<DataStore>), Error> {
45
46 let tgt_store = DataStore::lookup_datastore(store)?;
47
48 let (remote_config, _digest) = remote::config()?;
49 let remote: remote::Remote = remote_config.lookup("remote", remote)?;
50
51 let options = HttpClientOptions::new()
52 .password(Some(remote.password.clone()))
53 .fingerprint(remote.fingerprint.clone());
54
55 let client = HttpClient::new(&remote.host, &remote.userid, options)?;
56 let _auth_info = client.login() // make sure we can auth
57 .await
58 .map_err(|err| format_err!("remote connection to '{}' failed - {}", remote.host, err))?;
59
60 let src_repo = BackupRepository::new(Some(remote.userid), Some(remote.host), remote_store.to_string());
61
62 Ok((client, src_repo, tgt_store))
63}
64
de8ec041
DM
65#[api(
66 input: {
67 properties: {
68 store: {
69 schema: DATASTORE_SCHEMA,
70 },
94609e23
DM
71 remote: {
72 schema: REMOTE_ID_SCHEMA,
de8ec041
DM
73 },
74 "remote-store": {
75 schema: DATASTORE_SCHEMA,
76 },
b4900286
DM
77 "remove-vanished": {
78 schema: REMOVE_VANISHED_BACKUPS_SCHEMA,
4b4eba0b 79 optional: true,
4b4eba0b 80 },
de8ec041
DM
81 },
82 },
404d78c4 83 access: {
365f0f72 84 // Note: used parameters are no uri parameters, so we need to test inside function body
54552dda 85 description: r###"The user needs Datastore.Backup privilege on '/datastore/{store}',
8247db5b 86and needs to own the backup group. Remote.Read is required on '/remote/{remote}/{remote-store}'.
ec67af9a 87The delete flag additionally requires the Datastore.Prune privilege on '/datastore/{store}'.
54552dda 88"###,
365f0f72 89 permission: &Permission::Anybody,
404d78c4 90 },
de8ec041 91)]
eb506c83
DM
92/// Sync store from other repository
93async fn pull (
de8ec041 94 store: String,
94609e23 95 remote: String,
de8ec041 96 remote_store: String,
b4900286 97 remove_vanished: Option<bool>,
de8ec041
DM
98 _info: &ApiMethod,
99 rpcenv: &mut dyn RpcEnvironment,
100) -> Result<String, Error> {
101
102 let username = rpcenv.get_user().unwrap();
b4900286 103 let delete = remove_vanished.unwrap_or(true);
4b4eba0b 104
268687dd 105 check_pull_privs(&username, &store, &remote, &remote_store, delete)?;
de8ec041 106
268687dd 107 let (client, src_repo, tgt_store) = get_pull_parameters(&store, &remote, &remote_store).await?;
de8ec041
DM
108
109 // fixme: set to_stdout to false?
110 let upid_str = WorkerTask::spawn("sync", Some(store.clone()), &username.clone(), true, move |worker| async move {
111
112 worker.log(format!("sync datastore '{}' start", store));
113
54552dda 114 pull_store(&worker, &client, &src_repo, tgt_store.clone(), delete, username).await?;
de8ec041
DM
115
116 worker.log(format!("sync datastore '{}' end", store));
117
118 Ok(())
119 })?;
120
121 Ok(upid_str)
122}
123
124pub const ROUTER: Router = Router::new()
eb506c83 125 .post(&API_METHOD_PULL);