1 use anyhow
::{bail, Error}
;
3 use ::serde
::{Deserialize, Serialize}
;
5 use proxmox
::api
::{api, Router, RpcEnvironment}
;
6 use proxmox
::tools
::fs
::open_file_locked
;
8 use crate::api2
::types
::*;
9 use crate::config
::sync
::{self, SyncJobConfig}
;
11 // fixme: add access permissions
18 description
: "List configured jobs.",
20 items
: { type: sync::SyncJobConfig }
,
23 /// List all sync jobs
24 pub fn list_sync_jobs(
26 mut rpcenv
: &mut dyn RpcEnvironment
,
27 ) -> Result
<Vec
<SyncJobConfig
>, Error
> {
29 let (config
, digest
) = sync
::config()?
;
31 let list
= config
.convert_to_typed_array("sync")?
;
33 rpcenv
["digest"] = proxmox
::tools
::digest_to_hex(&digest
).into();
43 schema
: JOB_ID_SCHEMA
,
46 schema
: DATASTORE_SCHEMA
,
49 schema
: REMOTE_ID_SCHEMA
,
52 schema
: DATASTORE_SCHEMA
,
55 schema
: REMOVE_VANISHED_BACKUPS_SCHEMA
,
60 schema
: SINGLE_LINE_COMMENT_SCHEMA
,
64 schema
: SYNC_SCHEDULE_SCHEMA
,
69 /// Create a new sync job.
70 pub fn create_sync_job(param
: Value
) -> Result
<(), Error
> {
72 let _lock
= open_file_locked(sync
::SYNC_CFG_LOCKFILE
, std
::time
::Duration
::new(10, 0))?
;
74 let sync_job
: sync
::SyncJobConfig
= serde_json
::from_value(param
.clone())?
;
76 let (mut config
, _digest
) = sync
::config()?
;
78 if let Some(_
) = config
.sections
.get(&sync_job
.id
) {
79 bail
!("job '{}' already exists.", sync_job
.id
);
82 config
.set_data(&sync_job
.id
, "sync", &sync_job
)?
;
84 sync
::save_config(&config
)?
;
93 schema
: JOB_ID_SCHEMA
,
98 description
: "The sync job configuration.",
99 type: sync
::SyncJobConfig
,
102 /// Read a sync job configuration.
103 pub fn read_sync_job(
105 mut rpcenv
: &mut dyn RpcEnvironment
,
106 ) -> Result
<SyncJobConfig
, Error
> {
107 let (config
, digest
) = sync
::config()?
;
109 let sync_job
= config
.lookup("sync", &id
)?
;
110 rpcenv
["digest"] = proxmox
::tools
::digest_to_hex(&digest
).into();
116 #[derive(Serialize, Deserialize)]
117 #[serde(rename_all="kebab-case")]
118 #[allow(non_camel_case_types)]
119 /// Deletable property name
120 pub enum DeletableProperty
{
121 /// Delete the comment property.
123 /// Delete the job schedule.
125 /// Delete the remove-vanished flag.
134 schema
: JOB_ID_SCHEMA
,
137 schema
: DATASTORE_SCHEMA
,
141 schema
: REMOTE_ID_SCHEMA
,
145 schema
: DATASTORE_SCHEMA
,
149 schema
: REMOVE_VANISHED_BACKUPS_SCHEMA
,
154 schema
: SINGLE_LINE_COMMENT_SCHEMA
,
158 schema
: SYNC_SCHEDULE_SCHEMA
,
161 description
: "List of properties to delete.",
165 type: DeletableProperty
,
170 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
175 /// Update sync job config.
176 pub fn update_sync_job(
178 store
: Option
<String
>,
179 remote
: Option
<String
>,
180 remote_store
: Option
<String
>,
181 remove_vanished
: Option
<bool
>,
182 comment
: Option
<String
>,
183 schedule
: Option
<String
>,
184 delete
: Option
<Vec
<DeletableProperty
>>,
185 digest
: Option
<String
>,
186 ) -> Result
<(), Error
> {
188 let _lock
= open_file_locked(sync
::SYNC_CFG_LOCKFILE
, std
::time
::Duration
::new(10, 0))?
;
190 // pass/compare digest
191 let (mut config
, expected_digest
) = sync
::config()?
;
193 if let Some(ref digest
) = digest
{
194 let digest
= proxmox
::tools
::hex_to_digest(digest
)?
;
195 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
198 let mut data
: sync
::SyncJobConfig
= config
.lookup("sync", &id
)?
;
200 if let Some(delete
) = delete
{
201 for delete_prop
in delete
{
203 DeletableProperty
::comment
=> { data.comment = None; }
,
204 DeletableProperty
::schedule
=> { data.schedule = None; }
,
205 DeletableProperty
::remove_vanished
=> { data.remove_vanished = None; }
,
210 if let Some(comment
) = comment
{
211 let comment
= comment
.trim().to_string();
212 if comment
.is_empty() {
215 data
.comment
= Some(comment
);
219 if let Some(store
) = store { data.store = store; }
220 if let Some(remote
) = remote { data.remote = remote; }
221 if let Some(remote_store
) = remote_store { data.remote_store = remote_store; }
224 if schedule
.is_some() { data.schedule = schedule; }
225 if remove_vanished
.is_some() { data.remove_vanished = remove_vanished; }
227 config
.set_data(&id
, "sync", &data
)?
;
229 sync
::save_config(&config
)?
;
239 schema
: JOB_ID_SCHEMA
,
243 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
248 /// Remove a sync job configuration
249 pub fn delete_sync_job(id
: String
, digest
: Option
<String
>) -> Result
<(), Error
> {
251 let _lock
= open_file_locked(sync
::SYNC_CFG_LOCKFILE
, std
::time
::Duration
::new(10, 0))?
;
253 let (mut config
, expected_digest
) = sync
::config()?
;
255 if let Some(ref digest
) = digest
{
256 let digest
= proxmox
::tools
::hex_to_digest(digest
)?
;
257 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
260 match config
.sections
.get(&id
) {
261 Some(_
) => { config.sections.remove(&id); }
,
262 None
=> bail
!("job '{}' does not exist.", id
),
265 sync
::save_config(&config
)?
;
267 crate::config
::jobstate
::remove_state_file("syncjob", &id
)?
;
272 const ITEM_ROUTER
: Router
= Router
::new()
273 .get(&API_METHOD_READ_SYNC_JOB
)
274 .put(&API_METHOD_UPDATE_SYNC_JOB
)
275 .delete(&API_METHOD_DELETE_SYNC_JOB
);
277 pub const ROUTER
: Router
= Router
::new()
278 .get(&API_METHOD_LIST_SYNC_JOBS
)
279 .post(&API_METHOD_CREATE_SYNC_JOB
)
280 .match_all("id", &ITEM_ROUTER
);