]> git.proxmox.com Git - proxmox-backup.git/blob - src/api2/config/remote.rs
5dcd673930863415de7b3ec334402d450a4c1058
[proxmox-backup.git] / src / api2 / config / remote.rs
1 use anyhow::{bail, Error};
2 use serde_json::Value;
3
4 use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission};
5
6 use crate::api2::types::*;
7 use crate::config::remote;
8 use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
9
10 #[api(
11 input: {
12 properties: {},
13 },
14 returns: {
15 description: "The list of configured remotes (with config digest).",
16 type: Array,
17 items: {
18 type: Object,
19 description: "Remote configuration (without password).",
20 properties: {
21 name: {
22 schema: REMOTE_ID_SCHEMA,
23 },
24 comment: {
25 optional: true,
26 schema: SINGLE_LINE_COMMENT_SCHEMA,
27 },
28 host: {
29 schema: DNS_NAME_OR_IP_SCHEMA,
30 },
31 userid: {
32 schema: PROXMOX_USER_ID_SCHEMA,
33 },
34 fingerprint: {
35 optional: true,
36 schema: CERT_FINGERPRINT_SHA256_SCHEMA,
37 },
38 },
39 },
40 },
41 access: {
42 permission: &Permission::Privilege(&[], PRIV_SYS_AUDIT, false),
43 },
44 )]
45 /// List all remotes
46 pub fn list_remotes(
47 _param: Value,
48 _info: &ApiMethod,
49 _rpcenv: &mut dyn RpcEnvironment,
50 ) -> Result<Value, Error> {
51
52 let (config, digest) = remote::config()?;
53
54 let value = config.convert_to_array("name", Some(&digest), &["password"]);
55
56 Ok(value.into())
57 }
58
59 #[api(
60 protected: true,
61 input: {
62 properties: {
63 name: {
64 schema: REMOTE_ID_SCHEMA,
65 },
66 comment: {
67 optional: true,
68 schema: SINGLE_LINE_COMMENT_SCHEMA,
69 },
70 host: {
71 schema: DNS_NAME_OR_IP_SCHEMA,
72 },
73 userid: {
74 schema: PROXMOX_USER_ID_SCHEMA,
75 },
76 password: {
77 schema: remote::REMOTE_PASSWORD_SCHEMA,
78 },
79 fingerprint: {
80 optional: true,
81 schema: CERT_FINGERPRINT_SHA256_SCHEMA,
82 },
83 },
84 },
85 access: {
86 permission: &Permission::Privilege(&[], PRIV_SYS_MODIFY, false),
87 },
88 )]
89 /// Create new remote.
90 pub fn create_remote(name: String, param: Value) -> Result<(), Error> {
91
92 let _lock = crate::tools::open_file_locked(remote::REMOTE_CFG_LOCKFILE, std::time::Duration::new(10, 0))?;
93
94 let remote: remote::Remote = serde_json::from_value(param.clone())?;
95
96 let (mut config, _digest) = remote::config()?;
97
98 if let Some(_) = config.sections.get(&name) {
99 bail!("remote '{}' already exists.", name);
100 }
101
102 config.set_data(&name, "remote", &remote)?;
103
104 remote::save_config(&config)?;
105
106 Ok(())
107 }
108
109 #[api(
110 input: {
111 properties: {
112 name: {
113 schema: REMOTE_ID_SCHEMA,
114 },
115 },
116 },
117 returns: {
118 description: "The remote configuration (with config digest).",
119 type: remote::Remote,
120 },
121 access: {
122 permission: &Permission::Privilege(&[], PRIV_SYS_AUDIT, false),
123 }
124 )]
125 /// Read remote configuration data.
126 pub fn read_remote(name: String) -> Result<Value, Error> {
127 let (config, digest) = remote::config()?;
128 let mut data = config.lookup_json("remote", &name)?;
129 data.as_object_mut().unwrap()
130 .insert("digest".into(), proxmox::tools::digest_to_hex(&digest).into());
131 Ok(data)
132 }
133
134 #[api(
135 protected: true,
136 input: {
137 properties: {
138 name: {
139 schema: REMOTE_ID_SCHEMA,
140 },
141 comment: {
142 optional: true,
143 schema: SINGLE_LINE_COMMENT_SCHEMA,
144 },
145 host: {
146 optional: true,
147 schema: DNS_NAME_OR_IP_SCHEMA,
148 },
149 userid: {
150 optional: true,
151 schema: PROXMOX_USER_ID_SCHEMA,
152 },
153 password: {
154 optional: true,
155 schema: remote::REMOTE_PASSWORD_SCHEMA,
156 },
157 fingerprint: {
158 optional: true,
159 schema: CERT_FINGERPRINT_SHA256_SCHEMA,
160 },
161 digest: {
162 optional: true,
163 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
164 },
165 },
166 },
167 access: {
168 permission: &Permission::Privilege(&[], PRIV_SYS_MODIFY, false),
169 },
170 )]
171 /// Update remote configuration.
172 pub fn update_remote(
173 name: String,
174 comment: Option<String>,
175 host: Option<String>,
176 userid: Option<String>,
177 password: Option<String>,
178 fingerprint: Option<String>,
179 digest: Option<String>,
180 ) -> Result<(), Error> {
181
182 let _lock = crate::tools::open_file_locked(remote::REMOTE_CFG_LOCKFILE, std::time::Duration::new(10, 0))?;
183
184 let (mut config, expected_digest) = remote::config()?;
185
186 if let Some(ref digest) = digest {
187 let digest = proxmox::tools::hex_to_digest(digest)?;
188 crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
189 }
190
191 let mut data: remote::Remote = config.lookup("remote", &name)?;
192
193 if let Some(comment) = comment {
194 let comment = comment.trim().to_string();
195 if comment.is_empty() {
196 data.comment = None;
197 } else {
198 data.comment = Some(comment);
199 }
200 }
201 if let Some(host) = host { data.host = host; }
202 if let Some(userid) = userid { data.userid = userid; }
203 if let Some(password) = password { data.password = password; }
204
205 // fixme: howto delete a fingeprint?
206 if let Some(fingerprint) = fingerprint { data.fingerprint = Some(fingerprint); }
207
208 config.set_data(&name, "remote", &data)?;
209
210 remote::save_config(&config)?;
211
212 Ok(())
213 }
214
215 #[api(
216 protected: true,
217 input: {
218 properties: {
219 name: {
220 schema: REMOTE_ID_SCHEMA,
221 },
222 },
223 },
224 access: {
225 permission: &Permission::Privilege(&[], PRIV_SYS_MODIFY, false),
226 },
227 )]
228 /// Remove a remote from the configuration file.
229 pub fn delete_remote(name: String) -> Result<(), Error> {
230
231 // fixme: locking ?
232 // fixme: check digest ?
233
234 let (mut config, _digest) = remote::config()?;
235
236 match config.sections.get(&name) {
237 Some(_) => { config.sections.remove(&name); },
238 None => bail!("remote '{}' does not exist.", name),
239 }
240
241 Ok(())
242 }
243
244 const ITEM_ROUTER: Router = Router::new()
245 .get(&API_METHOD_READ_REMOTE)
246 .put(&API_METHOD_UPDATE_REMOTE)
247 .delete(&API_METHOD_DELETE_REMOTE);
248
249 pub const ROUTER: Router = Router::new()
250 .get(&API_METHOD_LIST_REMOTES)
251 .post(&API_METHOD_CREATE_REMOTE)
252 .match_all("name", &ITEM_ROUTER);