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