]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/tape/changer.rs
tape: rename DRIVE_ID_SCHEMA to DRIVE_NAME_SCHEMA
[proxmox-backup.git] / src / api2 / tape / changer.rs
CommitLineData
cafd51bf
DM
1use std::path::Path;
2
5d908606
DM
3use anyhow::Error;
4use serde_json::Value;
5
6use proxmox::api::{api, Router, SubdirMap};
7use proxmox::list_subdirs_api_method;
8
9use 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 49pub 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 120pub 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
148pub fn scan_changers(_param: Value) -> Result<Vec<TapeDeviceInfo>, Error> {
149
150 let list = linux_tape_changer_list();
151
152 Ok(list)
153}
154
155const SUBDIRS: SubdirMap = &[
156 (
157 "scan",
158 &Router::new()
159 .get(&API_METHOD_SCAN_CHANGERS)
160 ),
161];
162
163pub const ROUTER: Router = Router::new()
164 .get(&list_subdirs_api_method!(SUBDIRS))
165 .subdirs(SUBDIRS);