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();
24 // fixme: define better schemas
25 pub const DIR_NAME_SCHEMA
: Schema
= StringSchema
::new("Directory name").schema();
30 schema
: DATASTORE_SCHEMA
,
33 schema
: DIR_NAME_SCHEMA
,
37 schema
: SINGLE_LINE_COMMENT_SCHEMA
,
41 schema
: GC_SCHEDULE_SCHEMA
,
45 schema
: PRUNE_SCHEDULE_SCHEMA
,
49 schema
: VERIFY_SCHEDULE_SCHEMA
,
53 schema
: PRUNE_SCHEMA_KEEP_LAST
,
57 schema
: PRUNE_SCHEMA_KEEP_HOURLY
,
61 schema
: PRUNE_SCHEMA_KEEP_DAILY
,
65 schema
: PRUNE_SCHEMA_KEEP_WEEKLY
,
69 schema
: PRUNE_SCHEMA_KEEP_MONTHLY
,
73 schema
: PRUNE_SCHEMA_KEEP_YEARLY
,
77 #[serde(rename_all="kebab-case")]
78 #[derive(Serialize,Deserialize)]
79 /// Datastore configuration properties.
80 pub struct DataStoreConfig
{
82 #[serde(skip_serializing_if="Option::is_none")]
83 pub comment
: Option
<String
>,
85 #[serde(skip_serializing_if="Option::is_none")]
86 pub gc_schedule
: Option
<String
>,
87 #[serde(skip_serializing_if="Option::is_none")]
88 pub prune_schedule
: Option
<String
>,
89 #[serde(skip_serializing_if="Option::is_none")]
90 pub verify_schedule
: Option
<String
>,
91 #[serde(skip_serializing_if="Option::is_none")]
92 pub keep_last
: Option
<u64>,
93 #[serde(skip_serializing_if="Option::is_none")]
94 pub keep_hourly
: Option
<u64>,
95 #[serde(skip_serializing_if="Option::is_none")]
96 pub keep_daily
: Option
<u64>,
97 #[serde(skip_serializing_if="Option::is_none")]
98 pub keep_weekly
: Option
<u64>,
99 #[serde(skip_serializing_if="Option::is_none")]
100 pub keep_monthly
: Option
<u64>,
101 #[serde(skip_serializing_if="Option::is_none")]
102 pub keep_yearly
: Option
<u64>,
105 fn init() -> SectionConfig
{
106 let obj_schema
= match DataStoreConfig
::API_SCHEMA
{
107 Schema
::Object(ref obj_schema
) => obj_schema
,
111 let plugin
= SectionConfigPlugin
::new("datastore".to_string(), Some(String
::from("name")), obj_schema
);
112 let mut config
= SectionConfig
::new(&DATASTORE_SCHEMA
);
113 config
.register_plugin(plugin
);
118 pub const DATASTORE_CFG_FILENAME
: &str = "/etc/proxmox-backup/datastore.cfg";
119 pub const DATASTORE_CFG_LOCKFILE
: &str = "/etc/proxmox-backup/.datastore.lck";
121 pub fn config() -> Result
<(SectionConfigData
, [u8;32]), Error
> {
123 let content
= proxmox
::tools
::fs
::file_read_optional_string(DATASTORE_CFG_FILENAME
)?
;
124 let content
= content
.unwrap_or(String
::from(""));
126 let digest
= openssl
::sha
::sha256(content
.as_bytes());
127 let data
= CONFIG
.parse(DATASTORE_CFG_FILENAME
, &content
)?
;
131 pub fn save_config(config
: &SectionConfigData
) -> Result
<(), Error
> {
132 let raw
= CONFIG
.write(DATASTORE_CFG_FILENAME
, &config
)?
;
134 let backup_user
= crate::backup
::backup_user()?
;
135 let mode
= nix
::sys
::stat
::Mode
::from_bits_truncate(0o0640);
136 // set the correct owner/group/permissions while saving file
137 // owner(rw) = root, group(r)= backup
138 let options
= CreateOptions
::new()
140 .owner(nix
::unistd
::ROOT
)
141 .group(backup_user
.gid
);
143 replace_file(DATASTORE_CFG_FILENAME
, raw
.as_bytes(), options
)?
;
148 // shell completion helper
149 pub fn complete_datastore_name(_arg
: &str, _param
: &HashMap
<String
, String
>) -> Vec
<String
> {
151 Ok((data
, _digest
)) => data
.sections
.iter().map(|(id
, _
)| id
.to_string()).collect(),
152 Err(_
) => return vec
![],
156 pub fn complete_acl_path(_arg
: &str, _param
: &HashMap
<String
, String
>) -> Vec
<String
> {
157 let mut list
= Vec
::new();
159 list
.push(String
::from("/"));
160 list
.push(String
::from("/storage"));
161 list
.push(String
::from("/storage/"));
163 if let Ok((data
, _digest
)) = config() {
164 for id
in data
.sections
.keys() {
165 list
.push(format
!("/storage/{}", id
));
172 pub fn complete_calendar_event(_arg
: &str, _param
: &HashMap
<String
, String
>) -> Vec
<String
> {
173 // just give some hints about possible values
174 ["minutely", "hourly", "daily", "mon..fri", "0:0"]
175 .iter().map(|s
| String
::from(*s
)).collect()