]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/admin/sync.rs
update to proxmox-sys 0.2 crate
[proxmox-backup.git] / src / api2 / admin / sync.rs
CommitLineData
d1d74c43 1//! Datastore Synchronization Job Management
bf78f708 2
59af9ca9 3use anyhow::{bail, format_err, Error};
d43f86f3 4use serde_json::Value;
d43f86f3 5
25877d05 6use proxmox_sys::sortable;
6ef1b649
WB
7use proxmox_router::{
8 list_subdirs_api_method, ApiMethod, Router, RpcEnvironment, RpcEnvironmentType, SubdirMap,
9 Permission,
10};
11use proxmox_schema::api;
d43f86f3 12
e3619d41 13use pbs_api_types::{DATASTORE_SCHEMA, JOB_ID_SCHEMA, Authid, SyncJobConfig, SyncJobStatus};
a4e5a0fc 14use pbs_config::sync;
ba3d7e19 15use pbs_config::CachedUserInfo;
e3619d41 16
70842b9e
DM
17use crate::{
18 api2::{
70842b9e
DM
19 pull::do_sync_job,
20 config::sync::{
21 check_sync_job_modify_access,
22 check_sync_job_read_access,
23 },
24 },
70842b9e
DM
25 server::{
26 jobstate::{
27 Job,
28 JobState,
29 compute_schedule_status,
30 },
31 },
32};
d43f86f3
DC
33
34#[api(
35 input: {
d58e6313
DC
36 properties: {
37 store: {
38 schema: DATASTORE_SCHEMA,
39 optional: true,
40 },
41 },
d43f86f3
DC
42 },
43 returns: {
44 description: "List configured jobs and their status.",
45 type: Array,
70842b9e 46 items: { type: SyncJobStatus },
d43f86f3 47 },
59af9ca9
FG
48 access: {
49 description: "Limited to sync jobs where user has Datastore.Audit on target datastore, and Remote.Audit on source remote.",
50 permission: &Permission::Anybody,
51 },
d43f86f3
DC
52)]
53/// List all sync jobs
54pub fn list_sync_jobs(
d58e6313 55 store: Option<String>,
d43f86f3
DC
56 _param: Value,
57 mut rpcenv: &mut dyn RpcEnvironment,
58) -> Result<Vec<SyncJobStatus>, Error> {
59
59af9ca9
FG
60 let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
61 let user_info = CachedUserInfo::new()?;
62
d43f86f3
DC
63 let (config, digest) = sync::config()?;
64
70842b9e 65 let job_config_iter = config
d58e6313
DC
66 .convert_to_typed_array("sync")?
67 .into_iter()
70842b9e 68 .filter(|job: &SyncJobConfig| {
d58e6313
DC
69 if let Some(store) = &store {
70 &job.store == store
71 } else {
72 true
73 }
59af9ca9 74 })
70842b9e
DM
75 .filter(|job: &SyncJobConfig| {
76 check_sync_job_read_access(&user_info, &auth_id, &job)
77 });
78
79 let mut list = Vec::new();
d43f86f3 80
70842b9e 81 for job in job_config_iter {
664d8a27
DC
82 let last_state = JobState::load("syncjob", &job.id)
83 .map_err(|err| format_err!("could not open statefile for {}: {}", &job.id, err))?;
664d8a27 84
70842b9e 85 let status = compute_schedule_status(&last_state, job.schedule.as_deref())?;
8d785899 86
70842b9e 87 list.push(SyncJobStatus { config: job, status });
d43f86f3
DC
88 }
89
25877d05 90 rpcenv["digest"] = hex::encode(&digest).into();
d43f86f3
DC
91
92 Ok(list)
93}
94
95#[api(
96 input: {
97 properties: {
98 id: {
99 schema: JOB_ID_SCHEMA,
100 }
101 }
59af9ca9
FG
102 },
103 access: {
104 description: "User needs Datastore.Backup on target datastore, and Remote.Read on source remote. Additionally, remove_vanished requires Datastore.Prune, and any owner other than the user themselves requires Datastore.Modify",
105 permission: &Permission::Anybody,
106 },
d43f86f3
DC
107)]
108/// Runs the sync jobs manually.
bf78f708 109pub fn run_sync_job(
d43f86f3
DC
110 id: String,
111 _info: &ApiMethod,
112 rpcenv: &mut dyn RpcEnvironment,
113) -> Result<String, Error> {
59af9ca9
FG
114 let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
115 let user_info = CachedUserInfo::new()?;
d43f86f3
DC
116
117 let (config, _digest) = sync::config()?;
118 let sync_job: SyncJobConfig = config.lookup("sync", &id)?;
119
59af9ca9
FG
120 if !check_sync_job_modify_access(&user_info, &auth_id, &sync_job) {
121 bail!("permission check failed");
122 }
d43f86f3 123
93bb51fe 124 let job = Job::new("syncjob", &id)?;
02543a5c 125
bfa942c0
DC
126 let to_stdout = rpcenv.env_type() == RpcEnvironmentType::CLI;
127
128 let upid_str = do_sync_job(job, sync_job, &auth_id, None, to_stdout)?;
d43f86f3
DC
129
130 Ok(upid_str)
131}
132
133#[sortable]
134const SYNC_INFO_SUBDIRS: SubdirMap = &[
135 (
136 "run",
137 &Router::new()
138 .post(&API_METHOD_RUN_SYNC_JOB)
139 ),
140];
141
142const SYNC_INFO_ROUTER: Router = Router::new()
143 .get(&list_subdirs_api_method!(SYNC_INFO_SUBDIRS))
144 .subdirs(SYNC_INFO_SUBDIRS);
145
146
147pub const ROUTER: Router = Router::new()
148 .get(&API_METHOD_LIST_SYNC_JOBS)
149 .match_all("id", &SYNC_INFO_ROUTER);