]> git.proxmox.com Git - proxmox-backup.git/blob - src/api2/config/changer.rs
tape: rename CHANGER_ID_SCHEMA to CHANGER_NAME_SCHEMA
[proxmox-backup.git] / src / api2 / config / changer.rs
1 use anyhow::{bail, Error};
2 use serde_json::Value;
3
4 use proxmox::api::{api, Router, RpcEnvironment};
5
6 use crate::{
7 config,
8 api2::types::{
9 PROXMOX_CONFIG_DIGEST_SCHEMA,
10 CHANGER_NAME_SCHEMA,
11 LINUX_DRIVE_PATH_SCHEMA,
12 DriveListEntry,
13 ScsiTapeChanger,
14 LinuxTapeDrive,
15 },
16 tape::{
17 linux_tape_changer_list,
18 check_drive_path,
19 lookup_drive,
20 },
21 };
22
23 #[api(
24 protected: true,
25 input: {
26 properties: {
27 name: {
28 schema: CHANGER_NAME_SCHEMA,
29 },
30 path: {
31 schema: LINUX_DRIVE_PATH_SCHEMA,
32 },
33 },
34 },
35 )]
36 /// Create a new changer device
37 pub fn create_changer(
38 name: String,
39 path: String,
40 ) -> Result<(), Error> {
41
42 let _lock = config::drive::lock()?;
43
44 let (mut config, _digest) = config::drive::config()?;
45
46 let linux_changers = linux_tape_changer_list();
47
48 check_drive_path(&linux_changers, &path)?;
49
50 if config.sections.get(&name).is_some() {
51 bail!("Entry '{}' already exists", name);
52 }
53
54 let item = ScsiTapeChanger {
55 name: name.clone(),
56 path,
57 };
58
59 config.set_data(&name, "changer", &item)?;
60
61 config::drive::save_config(&config)?;
62
63 Ok(())
64 }
65
66 #[api(
67 input: {
68 properties: {
69 name: {
70 schema: CHANGER_NAME_SCHEMA,
71 },
72 },
73 },
74 returns: {
75 type: ScsiTapeChanger,
76 },
77
78 )]
79 /// Get tape changer configuration
80 pub fn get_config(
81 name: String,
82 _param: Value,
83 mut rpcenv: &mut dyn RpcEnvironment,
84 ) -> Result<ScsiTapeChanger, Error> {
85
86 let (config, digest) = config::drive::config()?;
87
88 let data: ScsiTapeChanger = config.lookup("changer", &name)?;
89
90 rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
91
92 Ok(data)
93 }
94
95 #[api(
96 input: {
97 properties: {},
98 },
99 returns: {
100 description: "The list of configured changers (with config digest).",
101 type: Array,
102 items: {
103 type: DriveListEntry,
104 },
105 },
106 )]
107 /// List changers
108 pub fn list_changers(
109 _param: Value,
110 mut rpcenv: &mut dyn RpcEnvironment,
111 ) -> Result<Vec<DriveListEntry>, Error> {
112
113 let (config, digest) = config::drive::config()?;
114
115 let linux_changers = linux_tape_changer_list();
116
117 let changer_list: Vec<ScsiTapeChanger> = config.convert_to_typed_array("changer")?;
118
119 let mut list = Vec::new();
120
121 for changer in changer_list {
122 let mut entry = DriveListEntry {
123 name: changer.name,
124 path: changer.path.clone(),
125 changer: None,
126 vendor: None,
127 model: None,
128 serial: None,
129 };
130 if let Some(info) = lookup_drive(&linux_changers, &changer.path) {
131 entry.vendor = Some(info.vendor.clone());
132 entry.model = Some(info.model.clone());
133 entry.serial = Some(info.serial.clone());
134 }
135
136 list.push(entry);
137 }
138
139 rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
140 Ok(list)
141 }
142
143 #[api(
144 protected: true,
145 input: {
146 properties: {
147 name: {
148 schema: CHANGER_NAME_SCHEMA,
149 },
150 path: {
151 schema: LINUX_DRIVE_PATH_SCHEMA,
152 optional: true,
153 },
154 digest: {
155 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
156 optional: true,
157 },
158 },
159 },
160 )]
161 /// Update a tape changer configuration
162 pub fn update_changer(
163 name: String,
164 path: Option<String>,
165 digest: Option<String>,
166 _param: Value,
167 ) -> Result<(), Error> {
168
169 let _lock = config::drive::lock()?;
170
171 let (mut config, expected_digest) = config::drive::config()?;
172
173 if let Some(ref digest) = digest {
174 let digest = proxmox::tools::hex_to_digest(digest)?;
175 crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
176 }
177
178 let mut data: ScsiTapeChanger = config.lookup("changer", &name)?;
179
180 if let Some(path) = path {
181 let changers = linux_tape_changer_list();
182 check_drive_path(&changers, &path)?;
183 data.path = path;
184 }
185
186 config.set_data(&name, "changer", &data)?;
187
188 config::drive::save_config(&config)?;
189
190 Ok(())
191 }
192
193 #[api(
194 protected: true,
195 input: {
196 properties: {
197 name: {
198 schema: CHANGER_NAME_SCHEMA,
199 },
200 },
201 },
202 )]
203 /// Delete a tape changer configuration
204 pub fn delete_changer(name: String, _param: Value) -> Result<(), Error> {
205
206 let _lock = config::drive::lock()?;
207
208 let (mut config, _digest) = config::drive::config()?;
209
210 match config.sections.get(&name) {
211 Some((section_type, _)) => {
212 if section_type != "changer" {
213 bail!("Entry '{}' exists, but is not a changer device", name);
214 }
215 config.sections.remove(&name);
216 },
217 None => bail!("Delete changer '{}' failed - no such entry", name),
218 }
219
220 let drive_list: Vec<LinuxTapeDrive> = config.convert_to_typed_array("linux")?;
221 for drive in drive_list {
222 if let Some(changer) = drive.changer {
223 if changer == name {
224 bail!("Delete changer '{}' failed - used by drive '{}'", name, drive.name);
225 }
226 }
227 }
228
229 config::drive::save_config(&config)?;
230
231 Ok(())
232 }
233
234 const ITEM_ROUTER: Router = Router::new()
235 .get(&API_METHOD_GET_CONFIG)
236 .put(&API_METHOD_UPDATE_CHANGER)
237 .delete(&API_METHOD_DELETE_CHANGER);
238
239
240 pub const ROUTER: Router = Router::new()
241 .get(&API_METHOD_LIST_CHANGERS)
242 .post(&API_METHOD_CREATE_CHANGER)
243 .match_all("name", &ITEM_ROUTER);