1 //! Datastore Synchronization Job Management
3 use anyhow
::{bail, format_err, Error}
;
6 use proxmox_sys
::sortable
;
8 list_subdirs_api_method
, ApiMethod
, Router
, RpcEnvironment
, RpcEnvironmentType
, SubdirMap
,
11 use proxmox_schema
::api
;
13 use pbs_api_types
::{DATASTORE_SCHEMA, JOB_ID_SCHEMA, Authid, SyncJobConfig, SyncJobStatus}
;
15 use pbs_config
::CachedUserInfo
;
21 check_sync_job_modify_access
,
22 check_sync_job_read_access
,
29 compute_schedule_status
,
38 schema
: DATASTORE_SCHEMA
,
44 description
: "List configured jobs and their status.",
46 items
: { type: SyncJobStatus }
,
49 description
: "Limited to sync jobs where user has Datastore.Audit on target datastore, and Remote.Audit on source remote.",
50 permission
: &Permission
::Anybody
,
53 /// List all sync jobs
54 pub fn list_sync_jobs(
55 store
: Option
<String
>,
57 mut rpcenv
: &mut dyn RpcEnvironment
,
58 ) -> Result
<Vec
<SyncJobStatus
>, Error
> {
60 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
61 let user_info
= CachedUserInfo
::new()?
;
63 let (config
, digest
) = sync
::config()?
;
65 let job_config_iter
= config
66 .convert_to_typed_array("sync")?
68 .filter(|job
: &SyncJobConfig
| {
69 if let Some(store
) = &store
{
75 .filter(|job
: &SyncJobConfig
| {
76 check_sync_job_read_access(&user_info
, &auth_id
, job
)
79 let mut list
= Vec
::new();
81 for job
in job_config_iter
{
82 let last_state
= JobState
::load("syncjob", &job
.id
)
83 .map_err(|err
| format_err
!("could not open statefile for {}: {}", &job
.id
, err
))?
;
85 let status
= compute_schedule_status(&last_state
, job
.schedule
.as_deref())?
;
87 list
.push(SyncJobStatus { config: job, status }
);
90 rpcenv
["digest"] = hex
::encode(&digest
).into();
99 schema
: JOB_ID_SCHEMA
,
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
,
108 /// Runs the sync jobs manually.
112 rpcenv
: &mut dyn RpcEnvironment
,
113 ) -> Result
<String
, Error
> {
114 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
115 let user_info
= CachedUserInfo
::new()?
;
117 let (config
, _digest
) = sync
::config()?
;
118 let sync_job
: SyncJobConfig
= config
.lookup("sync", &id
)?
;
120 if !check_sync_job_modify_access(&user_info
, &auth_id
, &sync_job
) {
121 bail
!("permission check failed");
124 let job
= Job
::new("syncjob", &id
)?
;
126 let to_stdout
= rpcenv
.env_type() == RpcEnvironmentType
::CLI
;
128 let upid_str
= do_sync_job(job
, sync_job
, &auth_id
, None
, to_stdout
)?
;
134 const SYNC_INFO_SUBDIRS
: SubdirMap
= &[
138 .post(&API_METHOD_RUN_SYNC_JOB
)
142 const SYNC_INFO_ROUTER
: Router
= Router
::new()
143 .get(&list_subdirs_api_method
!(SYNC_INFO_SUBDIRS
))
144 .subdirs(SYNC_INFO_SUBDIRS
);
147 pub const ROUTER
: Router
= Router
::new()
148 .get(&API_METHOD_LIST_SYNC_JOBS
)
149 .match_all("id", &SYNC_INFO_ROUTER
);