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