]> git.proxmox.com Git - proxmox-backup.git/blob - src/api2/config/datastore.rs
src/config/acl.rs: rtename PRTIV_DATASTORE_ALLOCATE to PRIV_DATASTORE_MODIFY
[proxmox-backup.git] / src / api2 / config / datastore.rs
1 use std::path::PathBuf;
2
3 use anyhow::{bail, Error};
4 use serde_json::Value;
5
6 use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission};
7
8 use crate::api2::types::*;
9 use crate::backup::*;
10 use crate::config::datastore;
11 use crate::config::acl::{PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_MODIFY};
12
13 #[api(
14 input: {
15 properties: {},
16 },
17 returns: {
18 description: "List the configured datastores (with config digest).",
19 type: Array,
20 items: {
21 description: "Datastore configuration.",
22 properties: {
23 name: {
24 schema: DATASTORE_SCHEMA,
25 },
26 path: {
27 schema: datastore::DIR_NAME_SCHEMA,
28 },
29 comment: {
30 optional: true,
31 schema: SINGLE_LINE_COMMENT_SCHEMA,
32 },
33 },
34 },
35 },
36 access: {
37 permission: &Permission::Privilege(&["datastore"], PRIV_DATASTORE_AUDIT, false),
38 },
39 )]
40 /// List all datastores
41 pub fn list_datastores(
42 _param: Value,
43 _info: &ApiMethod,
44 _rpcenv: &mut dyn RpcEnvironment,
45 ) -> Result<Value, Error> {
46
47 let (config, digest) = datastore::config()?;
48
49 Ok(config.convert_to_array("name", Some(&digest), &[]))
50 }
51
52 #[api(
53 protected: true,
54 input: {
55 properties: {
56 name: {
57 schema: DATASTORE_SCHEMA,
58 },
59 comment: {
60 optional: true,
61 schema: SINGLE_LINE_COMMENT_SCHEMA,
62 },
63 path: {
64 schema: datastore::DIR_NAME_SCHEMA,
65 },
66 },
67 },
68 access: {
69 permission: &Permission::Privilege(&["datastore"], PRIV_DATASTORE_MODIFY, false),
70 },
71 )]
72 /// Create new datastore config.
73 pub fn create_datastore(name: String, param: Value) -> Result<(), Error> {
74
75 let _lock = crate::tools::open_file_locked(datastore::DATASTORE_CFG_LOCKFILE, std::time::Duration::new(10, 0))?;
76
77 let datastore: datastore::DataStoreConfig = serde_json::from_value(param.clone())?;
78
79 let (mut config, _digest) = datastore::config()?;
80
81 if let Some(_) = config.sections.get(&name) {
82 bail!("datastore '{}' already exists.", name);
83 }
84
85 let path: PathBuf = datastore.path.clone().into();
86
87 let backup_user = crate::backup::backup_user()?;
88 let _store = ChunkStore::create(&name, path, backup_user.uid, backup_user.gid)?;
89
90 config.set_data(&name, "datastore", &datastore)?;
91
92 datastore::save_config(&config)?;
93
94 Ok(())
95 }
96
97 #[api(
98 input: {
99 properties: {
100 name: {
101 schema: DATASTORE_SCHEMA,
102 },
103 },
104 },
105 returns: {
106 description: "The datastore configuration (with config digest).",
107 type: datastore::DataStoreConfig,
108 },
109 access: {
110 permission: &Permission::Privilege(&["datastore", "{name}"], PRIV_DATASTORE_AUDIT, false),
111 },
112 )]
113 /// Read a datastore configuration.
114 pub fn read_datastore(name: String) -> Result<Value, Error> {
115 let (config, digest) = datastore::config()?;
116 let mut data = config.lookup_json("datastore", &name)?;
117 data.as_object_mut().unwrap()
118 .insert("digest".into(), proxmox::tools::digest_to_hex(&digest).into());
119 Ok(data)
120 }
121
122 #[api(
123 protected: true,
124 input: {
125 properties: {
126 name: {
127 schema: DATASTORE_SCHEMA,
128 },
129 comment: {
130 optional: true,
131 schema: SINGLE_LINE_COMMENT_SCHEMA,
132 },
133 digest: {
134 optional: true,
135 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
136 },
137 },
138 },
139 access: {
140 permission: &Permission::Privilege(&["datastore", "{name}"], PRIV_DATASTORE_MODIFY, false),
141 },
142 )]
143 /// Update datastore config.
144 pub fn update_datastore(
145 name: String,
146 comment: Option<String>,
147 digest: Option<String>,
148 ) -> Result<(), Error> {
149
150 let _lock = crate::tools::open_file_locked(datastore::DATASTORE_CFG_LOCKFILE, std::time::Duration::new(10, 0))?;
151
152 // pass/compare digest
153 let (mut config, expected_digest) = datastore::config()?;
154
155 if let Some(ref digest) = digest {
156 let digest = proxmox::tools::hex_to_digest(digest)?;
157 crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
158 }
159
160 let mut data: datastore::DataStoreConfig = config.lookup("datastore", &name)?;
161
162 if let Some(comment) = comment {
163 let comment = comment.trim().to_string();
164 if comment.is_empty() {
165 data.comment = None;
166 } else {
167 data.comment = Some(comment);
168 }
169 }
170
171 config.set_data(&name, "datastore", &data)?;
172
173 datastore::save_config(&config)?;
174
175 Ok(())
176 }
177
178 #[api(
179 protected: true,
180 input: {
181 properties: {
182 name: {
183 schema: DATASTORE_SCHEMA,
184 },
185 digest: {
186 optional: true,
187 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
188 },
189 },
190 },
191 access: {
192 permission: &Permission::Privilege(&["datastore", "{name}"], PRIV_DATASTORE_MODIFY, false),
193 },
194 )]
195 /// Remove a datastore configuration.
196 pub fn delete_datastore(name: String, digest: Option<String>) -> Result<(), Error> {
197
198 let _lock = crate::tools::open_file_locked(datastore::DATASTORE_CFG_LOCKFILE, std::time::Duration::new(10, 0))?;
199
200 let (mut config, expected_digest) = datastore::config()?;
201
202 if let Some(ref digest) = digest {
203 let digest = proxmox::tools::hex_to_digest(digest)?;
204 crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
205 }
206
207 match config.sections.get(&name) {
208 Some(_) => { config.sections.remove(&name); },
209 None => bail!("datastore '{}' does not exist.", name),
210 }
211
212 datastore::save_config(&config)?;
213
214 Ok(())
215 }
216
217 const ITEM_ROUTER: Router = Router::new()
218 .get(&API_METHOD_READ_DATASTORE)
219 .put(&API_METHOD_UPDATE_DATASTORE)
220 .delete(&API_METHOD_DELETE_DATASTORE);
221
222 pub const ROUTER: Router = Router::new()
223 .get(&API_METHOD_LIST_DATASTORES)
224 .post(&API_METHOD_CREATE_DATASTORE)
225 .match_all("name", &ITEM_ROUTER);