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