2 use lazy_static
::lazy_static
;
3 use std
::collections
::HashMap
;
4 use serde
::{Serialize, Deserialize}
;
16 use proxmox
::tools
::{fs::replace_file, fs::CreateOptions}
;
18 use crate::api2
::types
::*;
21 static ref CONFIG
: SectionConfig
= init();
27 schema
: JOB_ID_SCHEMA
,
30 schema
: DATASTORE_SCHEMA
,
37 schema
: REMOTE_ID_SCHEMA
,
40 schema
: DATASTORE_SCHEMA
,
43 schema
: REMOVE_VANISHED_BACKUPS_SCHEMA
,
48 schema
: SINGLE_LINE_COMMENT_SCHEMA
,
52 schema
: SYNC_SCHEDULE_SCHEMA
,
56 #[serde(rename_all="kebab-case")]
57 #[derive(Serialize,Deserialize,Clone)]
59 pub struct SyncJobConfig
{
62 #[serde(skip_serializing_if="Option::is_none")]
63 pub owner
: Option
<Authid
>,
65 pub remote_store
: String
,
66 #[serde(skip_serializing_if="Option::is_none")]
67 pub remove_vanished
: Option
<bool
>,
68 #[serde(skip_serializing_if="Option::is_none")]
69 pub comment
: Option
<String
>,
70 #[serde(skip_serializing_if="Option::is_none")]
71 pub schedule
: Option
<String
>,
74 impl From
<&SyncJobStatus
> for SyncJobConfig
{
75 fn from(job_status
: &SyncJobStatus
) -> Self {
77 id
: job_status
.id
.clone(),
78 store
: job_status
.store
.clone(),
79 owner
: job_status
.owner
.clone(),
80 remote
: job_status
.remote
.clone(),
81 remote_store
: job_status
.remote_store
.clone(),
82 remove_vanished
: job_status
.remove_vanished
,
83 comment
: job_status
.comment
.clone(),
84 schedule
: job_status
.schedule
.clone(),
89 // FIXME: generate duplicate schemas/structs from one listing?
93 schema
: JOB_ID_SCHEMA
,
96 schema
: DATASTORE_SCHEMA
,
103 schema
: REMOTE_ID_SCHEMA
,
106 schema
: DATASTORE_SCHEMA
,
109 schema
: REMOVE_VANISHED_BACKUPS_SCHEMA
,
114 schema
: SINGLE_LINE_COMMENT_SCHEMA
,
118 schema
: SYNC_SCHEDULE_SCHEMA
,
121 description
: "Estimated time of the next run (UNIX epoch).",
126 description
: "Result of the last run.",
131 description
: "Task UPID of the last run.",
135 "last-run-endtime": {
136 description
: "Endtime of the last run.",
142 #[serde(rename_all="kebab-case")]
143 #[derive(Serialize,Deserialize)]
144 /// Status of Sync Job
145 pub struct SyncJobStatus
{
148 #[serde(skip_serializing_if="Option::is_none")]
149 pub owner
: Option
<Authid
>,
151 pub remote_store
: String
,
152 #[serde(skip_serializing_if="Option::is_none")]
153 pub remove_vanished
: Option
<bool
>,
154 #[serde(skip_serializing_if="Option::is_none")]
155 pub comment
: Option
<String
>,
156 #[serde(skip_serializing_if="Option::is_none")]
157 pub schedule
: Option
<String
>,
158 #[serde(skip_serializing_if="Option::is_none")]
159 pub next_run
: Option
<i64>,
160 #[serde(skip_serializing_if="Option::is_none")]
161 pub last_run_state
: Option
<String
>,
162 #[serde(skip_serializing_if="Option::is_none")]
163 pub last_run_upid
: Option
<String
>,
164 #[serde(skip_serializing_if="Option::is_none")]
165 pub last_run_endtime
: Option
<i64>,
168 fn init() -> SectionConfig
{
169 let obj_schema
= match SyncJobConfig
::API_SCHEMA
{
170 Schema
::Object(ref obj_schema
) => obj_schema
,
174 let plugin
= SectionConfigPlugin
::new("sync".to_string(), Some(String
::from("id")), obj_schema
);
175 let mut config
= SectionConfig
::new(&JOB_ID_SCHEMA
);
176 config
.register_plugin(plugin
);
181 pub const SYNC_CFG_FILENAME
: &str = "/etc/proxmox-backup/sync.cfg";
182 pub const SYNC_CFG_LOCKFILE
: &str = "/etc/proxmox-backup/.sync.lck";
184 pub fn config() -> Result
<(SectionConfigData
, [u8;32]), Error
> {
186 let content
= proxmox
::tools
::fs
::file_read_optional_string(SYNC_CFG_FILENAME
)?
;
187 let content
= content
.unwrap_or(String
::from(""));
189 let digest
= openssl
::sha
::sha256(content
.as_bytes());
190 let data
= CONFIG
.parse(SYNC_CFG_FILENAME
, &content
)?
;
194 pub fn save_config(config
: &SectionConfigData
) -> Result
<(), Error
> {
195 let raw
= CONFIG
.write(SYNC_CFG_FILENAME
, &config
)?
;
197 let backup_user
= crate::backup
::backup_user()?
;
198 let mode
= nix
::sys
::stat
::Mode
::from_bits_truncate(0o0640);
199 // set the correct owner/group/permissions while saving file
200 // owner(rw) = root, group(r)= backup
201 let options
= CreateOptions
::new()
203 .owner(nix
::unistd
::ROOT
)
204 .group(backup_user
.gid
);
206 replace_file(SYNC_CFG_FILENAME
, raw
.as_bytes(), options
)?
;
211 // shell completion helper
212 pub fn complete_sync_job_id(_arg
: &str, _param
: &HashMap
<String
, String
>) -> Vec
<String
> {
214 Ok((data
, _digest
)) => data
.sections
.iter().map(|(id
, _
)| id
.to_string()).collect(),
215 Err(_
) => return vec
![],