]>
Commit | Line | Data |
---|---|---|
cafd51bf DM |
1 | use std::path::Path; |
2 | ||
5d908606 DM |
3 | use anyhow::Error; |
4 | use serde_json::Value; | |
5 | ||
6 | use proxmox::api::{api, Router, SubdirMap}; | |
7 | use proxmox::list_subdirs_api_method; | |
8 | ||
9 | use crate::{ | |
10 | config, | |
11 | api2::types::{ | |
12 | CHANGER_ID_SCHEMA, | |
13 | ScsiTapeChanger, | |
14 | TapeDeviceInfo, | |
15 | MtxStatusEntry, | |
16 | MtxEntryKind, | |
17 | }, | |
18 | tape::{ | |
cafd51bf | 19 | TAPE_STATUS_DIR, |
5d908606 | 20 | ElementStatus, |
cafd51bf DM |
21 | OnlineStatusMap, |
22 | Inventory, | |
23 | MediaStateDatabase, | |
5d908606 DM |
24 | linux_tape_changer_list, |
25 | mtx_status, | |
cafd51bf | 26 | mtx_status_to_online_set, |
5d908606 DM |
27 | mtx_transfer, |
28 | }, | |
29 | }; | |
30 | ||
31 | ||
32 | #[api( | |
33 | input: { | |
34 | properties: { | |
35 | name: { | |
36 | schema: CHANGER_ID_SCHEMA, | |
37 | }, | |
38 | }, | |
39 | }, | |
40 | returns: { | |
41 | description: "A status entry for each drive and slot.", | |
42 | type: Array, | |
43 | items: { | |
44 | type: MtxStatusEntry, | |
45 | }, | |
46 | }, | |
47 | )] | |
48 | /// Get tape changer status | |
42cb9bd6 | 49 | pub async fn get_status(name: String) -> Result<Vec<MtxStatusEntry>, Error> { |
5d908606 DM |
50 | |
51 | let (config, _digest) = config::drive::config()?; | |
52 | ||
53 | let data: ScsiTapeChanger = config.lookup("changer", &name)?; | |
54 | ||
42cb9bd6 DM |
55 | let status = tokio::task::spawn_blocking(move || { |
56 | mtx_status(&data.path) | |
57 | }).await??; | |
5d908606 | 58 | |
cafd51bf | 59 | let state_path = Path::new(TAPE_STATUS_DIR); |
5d908606 DM |
60 | let inventory = Inventory::load(state_path)?; |
61 | ||
62 | let mut map = OnlineStatusMap::new(&config)?; | |
63 | let online_set = mtx_status_to_online_set(&status, &inventory); | |
64 | map.update_online_status(&name, online_set)?; | |
65 | ||
66 | let mut state_db = MediaStateDatabase::load(state_path)?; | |
67 | state_db.update_online_status(&map)?; | |
5d908606 DM |
68 | |
69 | let mut list = Vec::new(); | |
70 | ||
71 | for (id, drive_status) in status.drives.iter().enumerate() { | |
72 | let entry = MtxStatusEntry { | |
73 | entry_kind: MtxEntryKind::Drive, | |
74 | entry_id: id as u64, | |
75 | changer_id: match &drive_status.status { | |
76 | ElementStatus::Empty => None, | |
77 | ElementStatus::Full => Some(String::new()), | |
78 | ElementStatus::VolumeTag(tag) => Some(tag.to_string()), | |
79 | }, | |
80 | loaded_slot: drive_status.loaded_slot, | |
81 | }; | |
82 | list.push(entry); | |
83 | } | |
84 | ||
85 | for (id, slot_status) in status.slots.iter().enumerate() { | |
86 | let entry = MtxStatusEntry { | |
87 | entry_kind: MtxEntryKind::Slot, | |
88 | entry_id: id as u64 + 1, | |
89 | changer_id: match &slot_status { | |
90 | ElementStatus::Empty => None, | |
91 | ElementStatus::Full => Some(String::new()), | |
92 | ElementStatus::VolumeTag(tag) => Some(tag.to_string()), | |
93 | }, | |
94 | loaded_slot: None, | |
95 | }; | |
96 | list.push(entry); | |
97 | } | |
98 | ||
99 | Ok(list) | |
100 | } | |
101 | ||
102 | #[api( | |
103 | input: { | |
104 | properties: { | |
105 | name: { | |
106 | schema: CHANGER_ID_SCHEMA, | |
107 | }, | |
108 | from: { | |
109 | description: "Source slot number", | |
110 | minimum: 1, | |
111 | }, | |
112 | to: { | |
113 | description: "Destination slot number", | |
114 | minimum: 1, | |
115 | }, | |
116 | }, | |
117 | }, | |
118 | )] | |
119 | /// Transfers media from one slot to another | |
42cb9bd6 | 120 | pub async fn transfer( |
5d908606 DM |
121 | name: String, |
122 | from: u64, | |
123 | to: u64, | |
124 | ) -> Result<(), Error> { | |
125 | ||
126 | let (config, _digest) = config::drive::config()?; | |
127 | ||
128 | let data: ScsiTapeChanger = config.lookup("changer", &name)?; | |
129 | ||
42cb9bd6 DM |
130 | tokio::task::spawn_blocking(move || { |
131 | mtx_transfer(&data.path, from, to) | |
132 | }).await? | |
5d908606 DM |
133 | } |
134 | ||
135 | #[api( | |
136 | input: { | |
137 | properties: {}, | |
138 | }, | |
139 | returns: { | |
140 | description: "The list of autodetected tape changers.", | |
141 | type: Array, | |
142 | items: { | |
143 | type: TapeDeviceInfo, | |
144 | }, | |
145 | }, | |
146 | )] | |
147 | /// Scan for SCSI tape changers | |
148 | pub fn scan_changers(_param: Value) -> Result<Vec<TapeDeviceInfo>, Error> { | |
149 | ||
150 | let list = linux_tape_changer_list(); | |
151 | ||
152 | Ok(list) | |
153 | } | |
154 | ||
155 | const SUBDIRS: SubdirMap = &[ | |
156 | ( | |
157 | "scan", | |
158 | &Router::new() | |
159 | .get(&API_METHOD_SCAN_CHANGERS) | |
160 | ), | |
161 | ]; | |
162 | ||
163 | pub const ROUTER: Router = Router::new() | |
164 | .get(&list_subdirs_api_method!(SUBDIRS)) | |
165 | .subdirs(SUBDIRS); |