]> git.proxmox.com Git - proxmox-backup.git/blob - src/api2/types/tape/drive.rs
add missing file pbs-api-types/src/remote.rs
[proxmox-backup.git] / src / api2 / types / tape / drive.rs
1 //! Types for tape drive API
2 use std::convert::TryFrom;
3
4 use anyhow::{bail, Error};
5 use serde::{Deserialize, Serialize};
6
7 use proxmox::api::{
8 api,
9 schema::{Schema, IntegerSchema, StringSchema, Updater},
10 };
11
12 use crate::api2::types::{
13 PROXMOX_SAFE_ID_FORMAT,
14 CHANGER_NAME_SCHEMA,
15 OptionalDeviceIdentification,
16 };
17
18 pub const DRIVE_NAME_SCHEMA: Schema = StringSchema::new("Drive Identifier.")
19 .format(&PROXMOX_SAFE_ID_FORMAT)
20 .min_length(3)
21 .max_length(32)
22 .schema();
23
24 pub const LTO_DRIVE_PATH_SCHEMA: Schema = StringSchema::new(
25 "The path to a LTO SCSI-generic tape device (i.e. '/dev/sg0')")
26 .schema();
27
28 pub const CHANGER_DRIVENUM_SCHEMA: Schema = IntegerSchema::new(
29 "Associated changer drive number (requires option changer)")
30 .minimum(0)
31 .maximum(255)
32 .default(0)
33 .schema();
34
35 #[api(
36 properties: {
37 name: {
38 schema: DRIVE_NAME_SCHEMA,
39 }
40 }
41 )]
42 #[derive(Serialize,Deserialize)]
43 /// Simulate tape drives (only for test and debug)
44 #[serde(rename_all = "kebab-case")]
45 pub struct VirtualTapeDrive {
46 pub name: String,
47 /// Path to directory
48 pub path: String,
49 /// Virtual tape size
50 #[serde(skip_serializing_if="Option::is_none")]
51 pub max_size: Option<usize>,
52 }
53
54 #[api(
55 properties: {
56 name: {
57 schema: DRIVE_NAME_SCHEMA,
58 },
59 path: {
60 schema: LTO_DRIVE_PATH_SCHEMA,
61 },
62 changer: {
63 schema: CHANGER_NAME_SCHEMA,
64 optional: true,
65 },
66 "changer-drivenum": {
67 schema: CHANGER_DRIVENUM_SCHEMA,
68 optional: true,
69 },
70 }
71 )]
72 #[derive(Serialize,Deserialize,Updater)]
73 #[serde(rename_all = "kebab-case")]
74 /// Lto SCSI tape driver
75 pub struct LtoTapeDrive {
76 #[updater(skip)]
77 pub name: String,
78 pub path: String,
79 #[serde(skip_serializing_if="Option::is_none")]
80 pub changer: Option<String>,
81 #[serde(skip_serializing_if="Option::is_none")]
82 pub changer_drivenum: Option<u64>,
83 }
84
85 #[api(
86 properties: {
87 config: {
88 type: LtoTapeDrive,
89 },
90 info: {
91 type: OptionalDeviceIdentification,
92 },
93 },
94 )]
95 #[derive(Serialize,Deserialize)]
96 #[serde(rename_all = "kebab-case")]
97 /// Drive list entry
98 pub struct DriveListEntry {
99 #[serde(flatten)]
100 pub config: LtoTapeDrive,
101 #[serde(flatten)]
102 pub info: OptionalDeviceIdentification,
103 /// the state of the drive if locked
104 #[serde(skip_serializing_if="Option::is_none")]
105 pub state: Option<String>,
106 }
107
108 #[api()]
109 #[derive(Serialize,Deserialize)]
110 /// Medium auxiliary memory attributes (MAM)
111 pub struct MamAttribute {
112 /// Attribute id
113 pub id: u16,
114 /// Attribute name
115 pub name: String,
116 /// Attribute value
117 pub value: String,
118 }
119
120 #[api()]
121 #[derive(Serialize,Deserialize,Copy,Clone,Debug)]
122 pub enum TapeDensity {
123 /// Unknown (no media loaded)
124 Unknown,
125 /// LTO1
126 LTO1,
127 /// LTO2
128 LTO2,
129 /// LTO3
130 LTO3,
131 /// LTO4
132 LTO4,
133 /// LTO5
134 LTO5,
135 /// LTO6
136 LTO6,
137 /// LTO7
138 LTO7,
139 /// LTO7M8
140 LTO7M8,
141 /// LTO8
142 LTO8,
143 }
144
145 impl TryFrom<u8> for TapeDensity {
146 type Error = Error;
147
148 fn try_from(value: u8) -> Result<Self, Self::Error> {
149 let density = match value {
150 0x00 => TapeDensity::Unknown,
151 0x40 => TapeDensity::LTO1,
152 0x42 => TapeDensity::LTO2,
153 0x44 => TapeDensity::LTO3,
154 0x46 => TapeDensity::LTO4,
155 0x58 => TapeDensity::LTO5,
156 0x5a => TapeDensity::LTO6,
157 0x5c => TapeDensity::LTO7,
158 0x5d => TapeDensity::LTO7M8,
159 0x5e => TapeDensity::LTO8,
160 _ => bail!("unknown tape density code 0x{:02x}", value),
161 };
162 Ok(density)
163 }
164 }
165
166 #[api(
167 properties: {
168 density: {
169 type: TapeDensity,
170 optional: true,
171 },
172 },
173 )]
174 #[derive(Serialize,Deserialize)]
175 #[serde(rename_all = "kebab-case")]
176 /// Drive/Media status for Lto SCSI drives.
177 ///
178 /// Media related data is optional - only set if there is a medium
179 /// loaded.
180 pub struct LtoDriveAndMediaStatus {
181 /// Vendor
182 pub vendor: String,
183 /// Product
184 pub product: String,
185 /// Revision
186 pub revision: String,
187 /// Block size (0 is variable size)
188 pub blocksize: u32,
189 /// Compression enabled
190 pub compression: bool,
191 /// Drive buffer mode
192 pub buffer_mode: u8,
193 /// Tape density
194 pub density: TapeDensity,
195 /// Media is write protected
196 #[serde(skip_serializing_if="Option::is_none")]
197 pub write_protect: Option<bool>,
198 /// Tape Alert Flags
199 #[serde(skip_serializing_if="Option::is_none")]
200 pub alert_flags: Option<String>,
201 /// Current file number
202 #[serde(skip_serializing_if="Option::is_none")]
203 pub file_number: Option<u64>,
204 /// Current block number
205 #[serde(skip_serializing_if="Option::is_none")]
206 pub block_number: Option<u64>,
207 /// Medium Manufacture Date (epoch)
208 #[serde(skip_serializing_if="Option::is_none")]
209 pub manufactured: Option<i64>,
210 /// Total Bytes Read in Medium Life
211 #[serde(skip_serializing_if="Option::is_none")]
212 pub bytes_read: Option<u64>,
213 /// Total Bytes Written in Medium Life
214 #[serde(skip_serializing_if="Option::is_none")]
215 pub bytes_written: Option<u64>,
216 /// Number of mounts for the current volume (i.e., Thread Count)
217 #[serde(skip_serializing_if="Option::is_none")]
218 pub volume_mounts: Option<u64>,
219 /// Count of the total number of times the medium has passed over
220 /// the head.
221 #[serde(skip_serializing_if="Option::is_none")]
222 pub medium_passes: Option<u64>,
223 /// Estimated tape wearout factor (assuming max. 16000 end-to-end passes)
224 #[serde(skip_serializing_if="Option::is_none")]
225 pub medium_wearout: Option<f64>,
226 }
227
228 #[api()]
229 /// Volume statistics from SCSI log page 17h
230 #[derive(Default, Serialize, Deserialize)]
231 #[serde(rename_all = "kebab-case")]
232 pub struct Lp17VolumeStatistics {
233 /// Volume mounts (thread count)
234 pub volume_mounts: u64,
235 /// Total data sets written
236 pub volume_datasets_written: u64,
237 /// Write retries
238 pub volume_recovered_write_data_errors: u64,
239 /// Total unrecovered write errors
240 pub volume_unrecovered_write_data_errors: u64,
241 /// Total suspended writes
242 pub volume_write_servo_errors: u64,
243 /// Total fatal suspended writes
244 pub volume_unrecovered_write_servo_errors: u64,
245 /// Total datasets read
246 pub volume_datasets_read: u64,
247 /// Total read retries
248 pub volume_recovered_read_errors: u64,
249 /// Total unrecovered read errors
250 pub volume_unrecovered_read_errors: u64,
251 /// Last mount unrecovered write errors
252 pub last_mount_unrecovered_write_errors: u64,
253 /// Last mount unrecovered read errors
254 pub last_mount_unrecovered_read_errors: u64,
255 /// Last mount bytes written
256 pub last_mount_bytes_written: u64,
257 /// Last mount bytes read
258 pub last_mount_bytes_read: u64,
259 /// Lifetime bytes written
260 pub lifetime_bytes_written: u64,
261 /// Lifetime bytes read
262 pub lifetime_bytes_read: u64,
263 /// Last load write compression ratio
264 pub last_load_write_compression_ratio: u64,
265 /// Last load read compression ratio
266 pub last_load_read_compression_ratio: u64,
267 /// Medium mount time
268 pub medium_mount_time: u64,
269 /// Medium ready time
270 pub medium_ready_time: u64,
271 /// Total native capacity
272 pub total_native_capacity: u64,
273 /// Total used native capacity
274 pub total_used_native_capacity: u64,
275 /// Write protect
276 pub write_protect: bool,
277 /// Volume is WORM
278 pub worm: bool,
279 /// Beginning of medium passes
280 pub beginning_of_medium_passes: u64,
281 /// Middle of medium passes
282 pub middle_of_tape_passes: u64,
283 /// Volume serial number
284 pub serial: String,
285 }