]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/config/changer.rs
tape: add changer configuration API
[proxmox-backup.git] / src / api2 / config / changer.rs
CommitLineData
50bf10ad
DM
1use anyhow::{bail, Error};
2use serde_json::Value;
3
4use proxmox::api::{api, Router, RpcEnvironment};
5
6use 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
35pub 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
78pub 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
106pub 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
155pub 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
190pub 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
224pub fn scan_changers(_param: Value) -> Result<Vec<TapeDeviceInfo>, Error> {
225
226 let list = linux_tape_changer_list();
227
228 Ok(list)
229}
230
231pub const SCAN_CHANGERS: Router = Router::new()
232 .get(&API_METHOD_SCAN_CHANGERS);
233
234
235const 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
241pub const ROUTER: Router = Router::new()
242 .get(&API_METHOD_LIST_CHANGERS)
243 .post(&API_METHOD_CREATE_CHANGER)
244 .match_all("name", &ITEM_ROUTER);