lsm/data.rs
1// Copyright (C) 2017-2018 Red Hat, Inc.
2//
3// Permission is hereby granted, free of charge, to any
4// person obtaining a copy of this software and associated
5// documentation files (the "Software"), to deal in the
6// Software without restriction, including without
7// limitation the rights to use, copy, modify, merge,
8// publish, distribute, sublicense, and/or sell copies of
9// the Software, and to permit persons to whom the Software
10// is furnished to do so, subject to the following
11// conditions:
12//
13// The above copyright notice and this permission notice
14// shall be included in all copies or substantial portions
15// of the Software.
16//
17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25// DEALINGS IN THE SOFTWARE.
26//
27// Author: Gris Ge <fge@redhat.com>
28
29use serde::{Deserialize, Deserializer, Serializer};
30use std::mem::transmute;
31
32fn gen_system_class_string() -> String {
33 "System".to_string()
34}
35
36fn gen_pool_class_string() -> String {
37 "Pool".to_string()
38}
39
40fn gen_vol_class_string() -> String {
41 "Volume".to_string()
42}
43
44fn gen_ag_class_string() -> String {
45 "AccessGroup".to_string()
46}
47
48fn gen_fs_class_string() -> String {
49 "FileSystem".to_string()
50}
51fn gen_fs_snap_class_string() -> String {
52 "FsSnapshot".to_string()
53}
54
55fn gen_exp_class_string() -> String {
56 "NfsExport".to_string()
57}
58
59fn gen_disk_class_string() -> String {
60 "Disk".to_string()
61}
62
63/// Represent a storage system. Examples:
64///
65/// * A hardware RAID card, LSI `MegaRAID`
66///
67/// * A storage area network (SAN), e.g. `EMC` VNX, `NetApp` Filer
68///
69/// * A software solution running on commodity hardware, targetd, Nexenta
70///
71/// * A Linux system running NFS service
72#[derive(Serialize, Deserialize, Debug, Clone)]
73pub struct System {
74 #[serde(default = "gen_system_class_string")]
75 class: String,
76 /// Identifier.
77 pub id: String,
78 /// Human friendly name.
79 pub name: String,
80 /// System status stored in bitmap. Valid status value are:
81 ///
82 /// * [`System::STATUS_UNKNOWN`][1]
83 /// * [`System::STATUS_OK`][2]
84 /// * [`System::STATUS_ERROR`][3]
85 /// * [`System::STATUS_DEGRADED`][4]
86 /// * [`System::STATUS_PREDICTIVE_FAILURE`][5]
87 /// * [`System::STATUS_OTHER`][6]
88 ///
89 /// ```rust
90 /// # use lsm::{Client, System};
91 /// #
92 /// # let mut c = Client::new("sim://", None, None).unwrap();
93 /// # let syss = c.systems().unwrap();
94 /// #
95 /// # for s in syss {
96 /// if (s.status & System::STATUS_OK) == 0 {
97 /// println!("System {}/{} is not healthy", s.name, s.id);
98 /// }
99 /// # }
100 /// ```
101 /// [1]: #associatedconstant.STATUS_UNKNOWN
102 /// [2]: #associatedconstant.STATUS_OK
103 /// [3]: #associatedconstant.STATUS_ERROR
104 /// [4]: #associatedconstant.STATUS_DEGRADED
105 /// [5]: #associatedconstant.STATUS_PREDICTIVE_FAILURE
106 /// [6]: #associatedconstant.STATUS_OTHER
107 pub status: u32,
108 /// Additional message for status.
109 pub status_info: String,
110 plugin_data: Option<String>,
111 /// Firmware version.
112 pub fw_version: String,
113 /// Read cache percentage of the system. Valid values are:
114 ///
115 /// * `>0 and < 100` means only a part of whole cache are used for read.
116 /// * `0` means no read cache.
117 /// * `100` means all cache are used for read.
118 /// * [`System::READ_CACHE_PCT_NO_SUPPORT`][1] means no support.
119 /// * [`System::READ_CACHE_PCT_UNKNOWN`][2] means plugin failed to
120 /// detect this value.
121 ///
122 /// [1]: #associatedconstant.READ_CACHE_PCT_NO_SUPPORT
123 /// [2]: #associatedconstant.READ_CACHE_PCT_UNKNOWN
124 pub read_cache_pct: i8,
125 #[serde(deserialize_with = "int_to_sys_mod")]
126 #[serde(serialize_with = "sys_mod_to_int")]
127 /// System mode, currently only supports hardware RAID cards.
128 pub mode: SystemMode,
129}
130
131impl System {
132 /// Plugin does not support querying read cache percentage.
133 pub const READ_CACHE_PCT_NO_SUPPORT: i8 = -2;
134 /// Plugin failed to query read cache percentage.
135 pub const READ_CACHE_PCT_UNKNOWN: i8 = -1;
136
137 /// Plugin failed to query system status.
138 pub const STATUS_UNKNOWN: u32 = 1;
139 /// System is up and healthy.
140 pub const STATUS_OK: u32 = 1 << 1;
141 /// System is in error state.
142 pub const STATUS_ERROR: u32 = 1 << 2;
143 /// System is degraded.
144 pub const STATUS_DEGRADED: u32 = 1 << 3;
145 /// System has potential failure.
146 pub const STATUS_PREDICTIVE_FAILURE: u32 = 1 << 4;
147 /// Vendor specific status.
148 pub const STATUS_OTHER: u32 = 1 << 5;
149}
150
151#[repr(i8)]
152#[derive(Debug, Clone, PartialEq, Copy)]
153pub enum SystemMode {
154 /// Plugin failed to query system mode.
155 Unknown = -2,
156 /// Plugin does not support querying system mode.
157 NoSupport = -1,
158 /// The storage system is a hardware RAID card(like HP SmartArray and LSI
159 /// MegaRAID) and could expose the logical volume(aka, RAIDed virtual disk)
160 /// to OS while hardware RAID card is handling the RAID algorithm. In this
161 /// mode, storage system cannot expose physical disk directly to OS.
162 HardwareRaid = 0,
163 /// The physical disks can be exposed to OS directly without any
164 /// configurations. SCSI enclosure service might be exposed to OS also.
165 Hba = 1,
166}
167
168fn int_to_sys_mod<'de, D: Deserializer<'de>>(
169 deserializer: D,
170) -> ::std::result::Result<SystemMode, D::Error> {
171 let i: i8 = Deserialize::deserialize(deserializer)?;
172 match i {
173 -1..=1 => unsafe { Ok(transmute::<i8, SystemMode>(i)) },
174 _ => Ok(SystemMode::Unknown),
175 }
176}
177
178#[allow(clippy::trivially_copy_pass_by_ref)]
179fn sys_mod_to_int<S: Serializer>(
180 m: &SystemMode,
181 serializer: S,
182) -> ::std::result::Result<S::Ok, S::Error> {
183 serializer.serialize_i8(*m as i8)
184}
185
186/// Represent a storage volume. Also known as LUN(Logical Unit Number) or
187/// Storage Volume or Virtual Disk. The host OS treats it as block devices (one
188/// volume can be exposed as many disks when [multipath I/O][1] is enabled).
189///
190/// [1]: https://en.wikipedia.org/wiki/Multipath_I/O
191#[derive(Serialize, Deserialize, Debug, Clone)]
192pub struct Volume {
193 #[serde(default = "gen_vol_class_string")]
194 class: String,
195 /// Identifier.
196 pub id: String,
197 /// Human friendly name.
198 pub name: String,
199 #[serde(deserialize_with = "int_to_bool")]
200 #[serde(serialize_with = "bool_to_int")]
201 #[serde(rename = "admin_state")]
202 /// Whether volume is online or offline(I/O access disabled by
203 /// administrator.
204 pub enabled: bool,
205 /// Block size.
206 pub block_size: u64,
207 /// Number of blocks.
208 pub num_of_blocks: u64,
209 plugin_data: Option<String>,
210 /// SCSI VPD 0x83 NAA type identifier.
211 /// Udev treat it as `ID_WWN_WITH_EXTENSION`
212 pub vpd83: String,
213 /// Identifier of owner system.
214 pub system_id: String,
215 /// Identifier of owner pool.
216 pub pool_id: String,
217}
218
219impl Volume {
220 /// Retried the usable size of volume in bytes.
221 pub fn size_bytes(&self) -> u64 {
222 self.block_size * self.num_of_blocks
223 }
224}
225
226/// Represent a volume replication type.
227pub enum VolumeReplicateType {
228 /// Plugin failed to detect volume replication type.
229 Unknown = -1,
230 /// Point in time read writeable space efficient copy of data. Also know as
231 /// read writeable snapshot.
232 Clone = 2,
233 /// Full bitwise copy of the data (occupies full space).
234 Copy = 3,
235 /// I/O will be blocked until I/O reached both source and target storage
236 /// systems. There will be no data difference between source and target
237 /// storage systems.
238 MirrorSync = 4,
239 /// I/O will be blocked until I/O reached source storage systems. The
240 /// source storage system will use copy the changes data to target system
241 /// in a predefined interval. There will be a small data differences
242 /// between source and target.
243 MirrorAsync = 5,
244}
245
246#[repr(i32)]
247#[derive(Debug, Clone, PartialEq, Copy)]
248/// Represent a RAID type.
249pub enum RaidType {
250 /// Plugin failed to detect RAID type.
251 Unknown = -1,
252 /// [RAID 0](https://en.wikipedia.org/wiki/Standard_RAID_levels#RAID_0)
253 Raid0 = 0,
254 /// Two disk mirror.
255 Raid1 = 1,
256 /// Byte-level striping with dedicated parity.
257 Raid3 = 3,
258 /// Block-level striping with dedicated parity.
259 Raid4 = 4,
260 /// Block-level striping with distributed parity.
261 Raid5 = 5,
262 /// Block-level striping with two distributed parities. Also known as
263 /// RAID-DP.
264 Raid6 = 6,
265 /// Stripe of mirrors.
266 Raid10 = 10,
267 /// Parity of mirrors.
268 Raid15 = 15,
269 /// Dual parity of mirrors.
270 Raid16 = 16,
271 /// Stripe of parities.
272 Raid50 = 50,
273 /// Stripe of dual parities.
274 Raid60 = 60,
275 /// Mirror of parities.
276 Raid51 = 51,
277 /// Mirror of dual parities.
278 Raid61 = 61,
279 /// Just bunch of disks, no parity, no striping.
280 Jbod = 20,
281 /// This volume contains multiple RAID settings.
282 Mixed = 21,
283 /// Vendor specific RAID type
284 Other = 22,
285}
286
287impl From<i32> for RaidType {
288 fn from(i: i32) -> RaidType {
289 match i {
290 0..=6 | 10 | 15 | 16 | 50 | 60 | 51 | 61 | 20..=22 => unsafe {
291 transmute::<i32, RaidType>(i)
292 },
293 _ => RaidType::Unknown,
294 }
295 }
296}
297
298#[derive(Debug, Clone)]
299/// Represent a Pool member.
300pub enum PoolMember {
301 /// Pool is created from disks.
302 Disk(Disk),
303 /// Pool is allocated from other pool.
304 Pool(Pool),
305}
306
307#[derive(Debug, Clone)]
308/// Represent pool membership information.
309pub struct PoolMemberInfo {
310 /// RAID type
311 pub raid_type: RaidType,
312 /// Pool members.
313 pub members: Vec<PoolMember>,
314}
315
316#[derive(Debug, Clone)]
317/// Represent volume RAID information.
318pub struct VolumeRaidInfo {
319 /// RAID type
320 pub raid_type: RaidType,
321 /// The size of strip on each disk or other storage extent.
322 /// For RAID1/JBOD, it should be set as block size. If plugin failed to
323 /// detect strip size, it should be set as 0.
324 pub strip_size: u32,
325 /// The count of disks used for assembling the RAID group(s) where this
326 /// volume allocated from. For any RAID system using the slice of disk,
327 /// this value indicate how many disk slices are used for the RAID. For
328 /// example, on LVM RAID, the 'disk_count' here indicate the count of PVs
329 /// used for certain volume. Another example, on EMC VMAX, the 'disk_count'
330 /// here indicate how many hyper volumes are used for this volume. For any
331 /// RAID system using remote LUN for data storing, each remote LUN should
332 /// be count as a disk. If the plugin failed to detect disk_count, it
333 /// should be set as 0.
334 pub disk_count: u32,
335 /// The minimum I/O size, device preferred I/O size for random I/O. Any I/O
336 /// size not equal to a multiple of this value may get significant speed
337 /// penalty. Normally it refers to strip size of each disk(extent). If
338 /// plugin failed to detect min_io_size, it should try these values in the
339 /// sequence of: logical sector size -> physical sector size -> 0
340 pub min_io_size: u32,
341 /// The optimal I/O size, device preferred I/O size for sequential I/O.
342 /// Normally it refers to RAID group stripe size. If plugin failed to
343 /// detect opt_io_size, it should be set to 0.
344 pub opt_io_size: u32,
345}
346
347fn int_to_bool<'de, D: Deserializer<'de>>(
348 deserializer: D,
349) -> ::std::result::Result<bool, D::Error> {
350 let i: i32 = Deserialize::deserialize(deserializer)?;
351 match i {
352 1 => Ok(true),
353 _ => Ok(false),
354 }
355}
356
357#[allow(clippy::trivially_copy_pass_by_ref)]
358fn bool_to_int<S: Serializer>(b: &bool, serializer: S) -> ::std::result::Result<S::Ok, S::Error> {
359 if *b {
360 serializer.serialize_i8(1i8)
361 } else {
362 serializer.serialize_i8(0i8)
363 }
364}
365
366#[derive(Serialize, Deserialize, Debug, Clone)]
367pub struct Pool {
368 #[serde(default = "gen_pool_class_string")]
369 class: String,
370 /// Identifier.
371 pub id: String,
372 /// Human friendly name.
373 pub name: String,
374 /// The type of elements this pool could create.
375 /// Valid element types are:
376 ///
377 /// * [`Pool::ELEMENT_TYPE_POOL`][1]
378 /// * [`Pool::ELEMENT_TYPE_VOLUME`][2]
379 /// * [`Pool::ELEMENT_TYPE_FS`][3]
380 /// * [`Pool::ELEMENT_TYPE_DELTA`][4]
381 /// * [`Pool::ELEMENT_TYPE_VOLUME_FULL`][5]
382 /// * [`Pool::ELEMENT_TYPE_VOLUME_THIN`][6]
383 /// * [`Pool::ELEMENT_TYPE_SYS_RESERVED`][7]
384 ///
385 /// The values are stored in bitmap:
386 ///
387 /// ```rust
388 /// # use lsm::{Client, Pool};
389 /// #
390 /// # let mut c = Client::new("sim://", None, None).unwrap();
391 /// # let ps = c.pools().unwrap();
392 /// #
393 /// # for p in ps {
394 /// if (p.element_type & Pool::ELEMENT_TYPE_VOLUME) == 0 {
395 /// println!("Pool {}/{} could create volume", p.name, p.id);
396 /// }
397 /// # }
398 /// ```
399 /// [1]: #associatedconstant.ELEMENT_TYPE_POOL
400 /// [2]: #associatedconstant.ELEMENT_TYPE_VOLUME
401 /// [3]: #associatedconstant.ELEMENT_TYPE_FS
402 /// [4]: #associatedconstant.ELEMENT_TYPE_DELTA
403 /// [5]: #associatedconstant.ELEMENT_TYPE_VOLUME_FULL
404 /// [6]: #associatedconstant.ELEMENT_TYPE_VOLUME_THIN
405 /// [7]: #associatedconstant.ELEMENT_TYPE_SYS_RESERVED
406 pub element_type: u64,
407 /// The actions does not supported by this pool.
408 /// Valid values are:
409 ///
410 /// * [`Pool::UNSUPPORTED_VOLUME_GROW`][1]
411 /// * [`Pool::UNSUPPORTED_VOLUME_SHRINK`][2]
412 ///
413 /// The values are stored in bitmap:
414 ///
415 /// ```rust
416 /// # use lsm::{Client, Pool};
417 /// #
418 /// # let mut c = Client::new("sim://", None, None).unwrap();
419 /// # let ps = c.pools().unwrap();
420 /// #
421 /// # for p in ps {
422 /// if (p.unsupported_actions & Pool::UNSUPPORTED_VOLUME_GROW) == 0 {
423 /// println!("Pool {}/{} cannot grow size of volume", p.name, p.id);
424 /// }
425 /// # }
426 /// ```
427 /// [1]: #associatedconstant.UNSUPPORTED_VOLUME_GROW
428 /// [2]: #associatedconstant.UNSUPPORTED_VOLUME_SHRINK
429 pub unsupported_actions: u64,
430 /// Total space in bytes.
431 pub total_space: u64,
432 /// Free space in bytes.
433 pub free_space: u64,
434 /// Pool status stored in bitmap. Valid status value are:
435 ///
436 /// * [`Pool::STATUS_UNKNOWN`][1]
437 /// * [`Pool::STATUS_OK`][2]
438 /// * [`Pool::STATUS_OTHER`][3]
439 /// * [`Pool::STATUS_DEGRADED`][4]
440 /// * [`Pool::STATUS_ERROR`][5]
441 /// * [`Pool::STATUS_STOPPED`][6]
442 /// * [`Pool::STATUS_STARTING`][7]
443 /// * [`Pool::STATUS_RECONSTRUCTING`][8]
444 /// * [`Pool::STATUS_VERIFYING`][9]
445 /// * [`Pool::STATUS_INITIALIZING`][10]
446 /// * [`Pool::STATUS_GROWING`][11]
447 ///
448 /// ```rust
449 /// # use lsm::{Client, Pool};
450 /// #
451 /// # let mut c = Client::new("sim://", None, None).unwrap();
452 /// # let ps = c.pools().unwrap();
453 /// #
454 /// # for p in ps {
455 /// if (p.status & Pool::STATUS_OK) == 0 {
456 /// println!("Pool {}/{} is not healthy", p.name, p.id);
457 /// }
458 /// # }
459 /// ```
460 /// [1]: #associatedconstant.STATUS_UNKNOWN
461 /// [2]: #associatedconstant.STATUS_OK
462 /// [3]: #associatedconstant.STATUS_OTHER
463 /// [4]: #associatedconstant.STATUS_DEGRADED
464 /// [5]: #associatedconstant.STATUS_ERROR
465 /// [6]: #associatedconstant.STATUS_STOPPED
466 /// [7]: #associatedconstant.STATUS_STARTING
467 /// [8]: #associatedconstant.STATUS_RECONSTRUCTING
468 /// [9]: #associatedconstant.STATUS_VERIFYING
469 /// [10]: #associatedconstant.STATUS_INITIALIZING
470 /// [11]: #associatedconstant.STATUS_GROWING
471 pub status: u64,
472 /// Additional message for status.
473 pub status_info: Option<String>,
474 plugin_data: Option<String>,
475 /// Identifier of owner system.
476 pub system_id: String,
477}
478
479impl Pool {
480 /// This pool could allocate space for sub-pool.
481 pub const ELEMENT_TYPE_POOL: u64 = 1 << 1;
482 /// This pool could create volume.
483 pub const ELEMENT_TYPE_VOLUME: u64 = 1 << 2;
484 /// This pool could create file system.
485 pub const ELEMENT_TYPE_FS: u64 = 1 << 3;
486 /// This pool could hold delta data for snapshots.
487 pub const ELEMENT_TYPE_DELTA: u64 = 1 << 4;
488 /// This pool could create fully allocated volume.
489 pub const ELEMENT_TYPE_VOLUME_FULL: u64 = 1 << 5;
490 /// This pool could create thin provisioned volume.
491 pub const ELEMENT_TYPE_VOLUME_THIN: u64 = 1 << 6;
492 /// This pool is reserved for system internal use.
493 pub const ELEMENT_TYPE_SYS_RESERVED: u64 = 1 << 10;
494
495 /// This pool cannot grow size of its volume.
496 pub const UNSUPPORTED_VOLUME_GROW: u64 = 1;
497 /// This pool cannot shrink size of its volume.
498 pub const UNSUPPORTED_VOLUME_SHRINK: u64 = 1 << 1;
499
500 /// Plugin failed to query pool status.
501 pub const STATUS_UNKNOWN: u64 = 1;
502 /// The data of this pool is accessible with not data lose. But it might
503 /// along with `Pool::STATUS_DEGRADED` to indicate redundancy lose.
504 pub const STATUS_OK: u64 = 1 << 1;
505 /// Vendor specific status. The `Pool.status_info` property will explain
506 /// the detail.
507 pub const STATUS_OTHER: u64 = 1 << 2;
508 /// Pool is lost data redundancy due to I/O error or offline of one or more
509 /// RAID member. Often come with `Pool::STATUS_OK` to indicate data is
510 /// still accessible with not data lose. Example:
511 ///
512 /// * RAID 6 pool lost access to 1 disk or 2 disks.
513 ///
514 /// * RAID 5 pool lost access to 1 disk.
515 pub const STATUS_DEGRADED: u64 = 1 << 4;
516 /// Pool data is not accessible due to some members offline. Example:
517 ///
518 /// * RAID 5 pool lost access to 2 disks.
519 ///
520 /// * RAID 0 pool lost access to 1 disks.
521 pub const STATUS_ERROR: u64 = 1 << 5;
522 /// Pool is stopping by administrator. Pool data is not accessible.
523 pub const STATUS_STOPPED: u64 = 1 << 9;
524 /// Pool is reviving from STOPPED status. Pool data is not accessible yet.
525 pub const STATUS_STARTING: u64 = 1 << 10;
526 /// Pool is reconstructing the hash data or mirror data. Mostly happen
527 /// when disk revive from offline or disk replaced. `Pool.status_info` may
528 /// contain progress of this reconstruction job. Often come with
529 /// `Pool::STATUS_DEGRADED` and `Pool::STATUS_OK`.
530 pub const STATUS_RECONSTRUCTING: u64 = 1 << 12;
531 /// Array is running integrity check on data of current pool. It might be
532 /// started by administrator or array itself. The I/O performance will be
533 /// impacted. Pool.status_info may contain progress of this verification
534 /// job. Often come with `Pool::STATUS_OK` to indicate data is still
535 /// accessible.
536 pub const STATUS_VERIFYING: u64 = 1 << 13;
537 /// Pool is not accessible and performing initializing task. Often happen
538 /// on newly created pool.
539 pub const STATUS_INITIALIZING: u64 = 1 << 14;
540 /// Pool is growing its size and doing internal jobs. `Pool.status_info`
541 /// can contain progress of this growing job. Often come with
542 /// `Pool::STATUS_OK` to indicate data is still accessible.
543 pub const STATUS_GROWING: u64 = 1 << 15;
544}
545
546#[derive(Serialize, Deserialize, Debug, Clone)]
547pub struct Disk {
548 #[serde(default = "gen_disk_class_string")]
549 class: String,
550 /// Identifier.
551 pub id: String,
552 /// Human friendly name.
553 pub name: String,
554 #[serde(deserialize_with = "int_to_disk_type")]
555 #[serde(serialize_with = "disk_type_to_int")]
556 /// Disk type.
557 pub disk_type: DiskType,
558 /// Block size in bytes.
559 pub block_size: u64,
560 /// Count of block.
561 pub num_of_blocks: u64,
562 /// Disk status stored in bitmap. Valid status value are:
563 ///
564 /// * [`Disk::STATUS_UNKNOWN`][1]
565 /// * [`Disk::STATUS_OK`][2]
566 /// * [`Disk::STATUS_OTHER`][3]
567 /// * [`Disk::STATUS_PREDICTIVE_FAILURE`][4]
568 /// * [`Disk::STATUS_ERROR`][5]
569 /// * [`Disk::STATUS_REMOVED`][6]
570 /// * [`Disk::STATUS_STARTING`][7]
571 /// * [`Disk::STATUS_STOPPING`][8]
572 /// * [`Disk::STATUS_STOPPED`][9]
573 /// * [`Disk::STATUS_INITIALIZING`][10]
574 /// * [`Disk::STATUS_MAINTENANCE_MODE`][11]
575 /// * [`Disk::STATUS_SPARE_DISK`][12]
576 /// * [`Disk::STATUS_RECONSTRUCT`][13]
577 /// * [`Disk::STATUS_FREE`][14]
578 ///
579 /// ```rust
580 /// # use lsm::{Client, Disk};
581 /// #
582 /// # let mut c = Client::new("sim://", None, None).unwrap();
583 /// # let ds = c.disks().unwrap();
584 /// #
585 /// # for d in ds {
586 /// if (d.status & Disk::STATUS_OK) == 0 {
587 /// println!("Disk {}/{} is not healthy", d.name, d.id);
588 /// }
589 /// # }
590 /// ```
591 /// [1]: #associatedconstant.STATUS_UNKNOWN
592 /// [2]: #associatedconstant.STATUS_OK
593 /// [3]: #associatedconstant.STATUS_OTHER
594 /// [4]: #associatedconstant.STATUS_PREDICTIVE_FAILURE
595 /// [5]: #associatedconstant.STATUS_ERROR
596 /// [6]: #associatedconstant.STATUS_REMOVED
597 /// [7]: #associatedconstant.STATUS_STARTING
598 /// [8]: #associatedconstant.STATUS_STOPPING
599 /// [9]: #associatedconstant.STATUS_STOPPED
600 /// [10]: #associatedconstant.STATUS_INITIALIZING
601 /// [11]: #associatedconstant.STATUS_MAINTENANCE_MODE
602 /// [12]: #associatedconstant.STATUS_SPARE_DISK
603 /// [13]: #associatedconstant.STATUS_RECONSTRUCT
604 /// [14]: #associatedconstant.STATUS_FREE
605 pub status: u64,
606 plugin_data: Option<String>,
607 /// Identifier of owner system.
608 pub system_id: String,
609 /// Disk location in storage topology.
610 pub location: Option<String>,
611 /// Disk rotation speed - revolutions per minute(RPM):
612 ///
613 /// * `-1` -- Unknown RPM speed.
614 ///
615 /// * `0` -- Non-rotating medium (e.g., SSD).
616 ///
617 /// * `1` -- Rotational disk with unknown speed.
618 ///
619 /// * `> 1` -- Normal rotational disk (e.g., HDD).
620 pub rpm: Option<i32>,
621 #[serde(deserialize_with = "int_to_disk_link_type")]
622 #[serde(serialize_with = "disk_link_type_to_int")]
623 /// Disk data link type.
624 pub link_type: Option<DiskLinkType>,
625 /// SCSI VPD 0x83 NAA type identifier.
626 /// Udev treat it as `ID_WWN_WITH_EXTENSION`
627 pub vpd83: Option<String>,
628}
629
630#[repr(i32)]
631#[derive(Debug, Clone, PartialEq, Copy)]
632/// Represent disk type.
633pub enum DiskType {
634 /// Plugin failed to query disk type.
635 Unknown = 0,
636 /// Vendor specific disk type.
637 Other = 1,
638 /// IDE disk.
639 Ata = 3,
640 /// SATA disk.
641 Sata = 4,
642 /// SAS disk.
643 Sas = 5,
644 /// FC disk.
645 Fc = 6,
646 /// SCSI over PCI-Express.
647 Sop = 7,
648 /// SCSI disk.
649 Scsi = 8,
650 /// Remote LUN from SAN array.
651 Lun = 9,
652 /// Near-Line SAS, just SATA disk + SAS port.
653 NlSas = 51,
654 /// Normal HDD, fall back value if failed to detect HDD type(SAS/SATA/etc).
655 Hdd = 52,
656 /// Solid State Drive.
657 Ssd = 53,
658 /// Hybrid disk uses a combination of HDD and SSD.
659 Hybrid = 54,
660}
661
662fn int_to_disk_type<'de, D: Deserializer<'de>>(
663 deserializer: D,
664) -> ::std::result::Result<DiskType, D::Error> {
665 let i: i32 = Deserialize::deserialize(deserializer)?;
666 match i {
667 0 | 1 | 3..=9 | 51..=54 => unsafe { Ok(transmute::<i32, DiskType>(i)) },
668 _ => Ok(DiskType::Unknown),
669 }
670}
671
672#[allow(clippy::trivially_copy_pass_by_ref)]
673fn disk_type_to_int<S: Serializer>(
674 t: &DiskType,
675 serializer: S,
676) -> ::std::result::Result<S::Ok, S::Error> {
677 serializer.serialize_i32(*t as i32)
678}
679
680#[repr(i32)]
681#[derive(Debug, Clone, PartialEq, Copy)]
682/// Represent disk data link type.
683pub enum DiskLinkType {
684 /// Plugin does not support querying disk link type.
685 NoSupport = -2,
686 /// Plugin failed to query disk link type.
687 Unknown = -1,
688 /// Fibre Channel.
689 Fc = 0,
690 /// Serial Storage Architecture, Old IBM tech.
691 Ssa = 2,
692 /// Serial Bus Protocol, used by IEEE 1394.
693 Sbp = 3,
694 /// SCSI RDMA Protocol.
695 Srp = 4,
696 /// Internet Small Computer System Interface
697 Iscsi = 5,
698 /// Serial Attached SCSI.
699 Sas = 6,
700 /// Automation/Drive Interface Transport. Often used by tape.
701 Adt = 7,
702 /// PATA/IDE or SATA.
703 Ata = 8,
704 /// USB
705 Usb = 9,
706 /// SCSI over PCI-E.
707 Sop = 10,
708 /// PCI-E, e.g. NVMe.
709 PciE = 11,
710}
711
712fn int_to_disk_link_type<'de, D: Deserializer<'de>>(
713 deserializer: D,
714) -> ::std::result::Result<Option<DiskLinkType>, D::Error> {
715 let i: i32 = Deserialize::deserialize(deserializer)?;
716 match i {
717 -2..=11 => unsafe { Ok(Some(transmute::<i32, DiskLinkType>(i))) },
718 _ => Ok(Some(DiskLinkType::Unknown)),
719 }
720}
721
722#[allow(clippy::trivially_copy_pass_by_ref)]
723fn disk_link_type_to_int<S: Serializer>(
724 t: &Option<DiskLinkType>,
725 serializer: S,
726) -> ::std::result::Result<S::Ok, S::Error> {
727 match *t {
728 Some(i) => serializer.serialize_i32(i as i32),
729 None => serializer.serialize_i32(DiskLinkType::Unknown as i32),
730 }
731}
732
733impl Disk {
734 /// Plugin failed to query out the status of disk.
735 pub const STATUS_UNKNOWN: u64 = 1;
736 /// Disk is up and healthy.
737 pub const STATUS_OK: u64 = 1 << 1;
738 /// Vendor specific status.
739 pub const STATUS_OTHER: u64 = 1 << 2;
740 /// Disk is still functional but will fail soon.
741 pub const STATUS_PREDICTIVE_FAILURE: u64 = 1 << 3;
742 /// Error make disk not functional.
743 pub const STATUS_ERROR: u64 = 1 << 4;
744 /// Disk was removed by administrator.
745 pub const STATUS_REMOVED: u64 = 1 << 5;
746 /// Disk is starting up.
747 pub const STATUS_STARTING: u64 = 1 << 6;
748 /// Disk is shutting down.
749 pub const STATUS_STOPPING: u64 = 1 << 7;
750 /// Disk is stopped by administrator.
751 pub const STATUS_STOPPED: u64 = 1 << 8;
752 /// Disk is not functional yet, internal storage system is initializing
753 /// this disk, it could be:
754 ///
755 /// * Initialising new disk.
756 ///
757 /// * Zeroing disk.
758 ///
759 /// * Scrubbing disk data.
760 pub const STATUS_INITIALIZING: u64 = 1 << 9;
761 /// In maintenance for bad sector scan, integrity check and etc It might be
762 /// combined with `Disk::STATUS_OK` or `Disk::STATUS_STOPPED` for online
763 /// maintenance or offline maintenance.
764 pub const STATUS_MAINTENANCE_MODE: u64 = 1 << 10;
765 /// Disk is configured as spare disk.
766 pub const STATUS_SPARE_DISK: u64 = 1 << 11;
767 /// Disk is reconstructing its data.
768 pub const STATUS_RECONSTRUCT: u64 = 1 << 12;
769 /// Indicate the whole disk is not holding any data or acting as a dedicate
770 /// spare disk. This disk could be assigned as a dedicated spare disk or
771 /// used for creating pool. If any spare disk(like those on NetApp ONTAP)
772 /// does not require any explicit action when assigning to pool, it should
773 /// be treated as free disk and marked as
774 /// `Disk::STATUS_FREE | Disk::STATUS_SPARE_DISK`.
775 pub const STATUS_FREE: u64 = 1 << 13;
776}
777
778#[derive(Serialize, Deserialize, Debug, Clone)]
779pub struct FileSystem {
780 #[serde(default = "gen_fs_class_string")]
781 class: String,
782 /// Identifier.
783 pub id: String,
784 /// Human friendly name.
785 pub name: String,
786 /// Total space in bytes.
787 pub total_space: u64,
788 /// Free space in bytes.
789 pub free_space: u64,
790 plugin_data: Option<String>,
791 /// Identifier of owner system.
792 pub system_id: String,
793 /// Identifier of owner pool.
794 pub pool_id: String,
795}
796
797#[derive(Serialize, Deserialize, Debug, Clone)]
798pub struct FileSystemSnapShot {
799 #[serde(default = "gen_fs_snap_class_string")]
800 class: String,
801 /// Identifier.
802 pub id: String,
803 /// Human friendly name.
804 pub name: String,
805 /// POSIX time(epoch time) on creation.
806 pub ts: u64,
807 plugin_data: Option<String>,
808}
809
810#[derive(Serialize, Deserialize, Debug, Clone)]
811pub struct NfsExport {
812 #[serde(default = "gen_exp_class_string")]
813 class: String,
814 /// Identifier.
815 pub id: String,
816 /// Identifier of file system.
817 pub fs_id: String,
818 /// NFS export path.
819 pub export_path: String,
820 /// NFS authentication type.
821 pub auth: String,
822 /// Host list with root access.
823 pub root: Vec<String>,
824 /// Host list with read and write access.
825 pub rw: Vec<String>,
826 /// Host list with read only access.
827 pub ro: Vec<String>,
828 /// User ID for anonymous access.
829 pub anonuid: i64,
830 /// Group ID for anonymous access.
831 pub anongid: i64,
832 /// NFS extra options.
833 pub options: String,
834 plugin_data: Option<String>,
835}
836
837impl NfsExport {
838 /// Default user and group ID for anonymous access.
839 pub const ANON_UID_GID_NA: i64 = -1;
840}
841
842#[derive(Serialize, Deserialize, Debug, Clone)]
843/// Access group is also known as host group on some storage system, it defines
844/// a group of initiators sharing the same access to the volume.
845pub struct AccessGroup {
846 #[serde(default = "gen_ag_class_string")]
847 class: String,
848 /// Identifier
849 pub id: String,
850 /// Human friendly name.
851 pub name: String,
852 /// Initiator list.
853 pub init_ids: Vec<String>,
854 #[serde(deserialize_with = "int_to_init_type")]
855 #[serde(serialize_with = "init_type_to_int")]
856 /// Initiator type.
857 pub init_type: InitiatorType,
858 plugin_data: Option<String>,
859 pub system_id: String,
860}
861
862#[repr(i32)]
863#[derive(Debug, Clone, PartialEq, Copy)]
864pub enum InitiatorType {
865 /// Plugin failed to query initiator type.
866 Unknown = 0,
867 /// Vendor specific initiator type.
868 Other = 1,
869 /// FC or FCoE WWPN
870 Wwpn = 2,
871 /// iSCSI IQN
872 IscsiIqn = 5,
873 /// This access group contains more than 1 type of initiator.
874 Mixed = 7,
875}
876
877fn int_to_init_type<'de, D: Deserializer<'de>>(
878 deserializer: D,
879) -> ::std::result::Result<InitiatorType, D::Error> {
880 let i: i32 = Deserialize::deserialize(deserializer)?;
881 match i {
882 0 | 1 | 2 | 5 | 7 => unsafe { Ok(transmute::<i32, InitiatorType>(i)) },
883 _ => Ok(InitiatorType::Unknown),
884 }
885}
886
887#[allow(clippy::trivially_copy_pass_by_ref)]
888fn init_type_to_int<S: Serializer>(
889 i: &InitiatorType,
890 serializer: S,
891) -> ::std::result::Result<S::Ok, S::Error> {
892 serializer.serialize_i32(*i as i32)
893}
894
895#[allow(dead_code)]
896#[derive(Deserialize, Debug, Clone)]
897/// Represent a target port which is the front-end port of storage system which
898/// storage user/client connect to and get storage service from.
899pub struct TargetPort {
900 /// Identifier.
901 pub id: String,
902 #[serde(deserialize_with = "int_to_port_type")]
903 /// Type of port.
904 pub port_type: PortType,
905 /// The address used by upper layer like FC and iSCSI:
906 ///
907 /// * FC and FCoE: WWPN
908 ///
909 /// * iSCSI: IQN
910 ///
911 /// The string is in lower case, split with `:` every two digits if WWPN.
912 pub service_address: String,
913 /// The address used by network layer like FC and TCP/IP:
914 ///
915 /// * FC/FCoE: WWPN
916 ///
917 /// * iSCSI: `IPv4:Port` or `[IPv6]:Port`
918 ///
919 /// The string is in lower case, split with `:` every two digits if WWPN.
920 pub network_address: String,
921 /// The address used by physical layer like FC-0 and MAC:
922 ///
923 /// * FC and FCoE : WWPN
924 ///
925 /// * iSCSI: MAC
926 ///
927 /// The string is in Lower case, split with `:` every two digits.
928 pub physical_address: String,
929 /// The name of physical port. Administrator could use this name to locate
930 /// the port on storage system. E.g. 'eth0'
931 pub physical_name: String,
932 plugin_data: Option<String>,
933 /// Identifier of owner system.
934 pub system_id: String,
935}
936
937#[repr(i32)]
938#[derive(Debug, Clone, PartialEq, Copy)]
939pub enum PortType {
940 /// Vendor specific initiator type.
941 Other = 1,
942 /// FC port
943 Fc = 2,
944 /// FCoE port
945 FCoE = 3,
946 /// iSCSI port
947 Iscsi = 4,
948}
949
950fn int_to_port_type<'de, D: Deserializer<'de>>(
951 deserializer: D,
952) -> ::std::result::Result<PortType, D::Error> {
953 let i: i32 = Deserialize::deserialize(deserializer)?;
954 match i {
955 1..=4 => unsafe { Ok(transmute::<i32, PortType>(i)) },
956 _ => Ok(PortType::Other),
957 }
958}
959
960#[allow(dead_code)]
961#[derive(Deserialize, Debug, Clone)]
962/// Represent a battery.
963pub struct Battery {
964 /// Identifier.
965 pub id: String,
966 /// Human friendly name.
967 pub name: String,
968 #[serde(rename = "type")]
969 #[serde(deserialize_with = "int_to_battery_type")]
970 /// Battery type.
971 pub battery_type: BatteryType,
972 /// Battery status stored in bitmap. Valid status value are:
973 ///
974 /// * [`Battery::STATUS_UNKNOWN`][1]
975 /// * [`Battery::STATUS_OTHER`][2]
976 /// * [`Battery::STATUS_OK`][3]
977 /// * [`Battery::STATUS_DISCHARGING`][4]
978 /// * [`Battery::STATUS_CHARGING`][5]
979 /// * [`Battery::STATUS_LEARNING`][6]
980 /// * [`Battery::STATUS_DEGRADED`][7]
981 /// * [`Battery::STATUS_ERROR`][8]
982 ///
983 /// ```rust
984 /// # use lsm::{Client, Battery};
985 /// #
986 /// # let mut c = Client::new("sim://", None, None).unwrap();
987 /// # let bs = c.batteries().unwrap();
988 /// #
989 /// # for b in bs {
990 /// if (b.status & Battery::STATUS_OK) == 0 {
991 /// println!("Battery {}/{} is not healthy", b.name, b.id);
992 /// }
993 /// # }
994 /// ```
995 /// [1]: #associatedconstant.STATUS_UNKNOWN
996 /// [2]: #associatedconstant.STATUS_OTHER
997 /// [3]: #associatedconstant.STATUS_OK
998 /// [4]: #associatedconstant.STATUS_DISCHARGING
999 /// [5]: #associatedconstant.STATUS_CHARGING
1000 /// [6]: #associatedconstant.STATUS_LEARNING
1001 /// [7]: #associatedconstant.STATUS_DEGRADED
1002 /// [8]: #associatedconstant.STATUS_ERROR
1003 pub status: u64,
1004 plugin_data: Option<String>,
1005 /// Identifier of owner system.
1006 pub system_id: String,
1007}
1008
1009impl Battery {
1010 /// Plugin failed to query battery status.
1011 pub const STATUS_UNKNOWN: u64 = 1;
1012 /// Vendor specific status.
1013 pub const STATUS_OTHER: u64 = 1 << 1;
1014 /// Battery is healthy and charged.
1015 pub const STATUS_OK: u64 = 1 << 2;
1016 /// Battery is disconnected from power source and discharging.
1017 pub const STATUS_DISCHARGING: u64 = 1 << 3;
1018 /// Battery is not fully charged and charging.
1019 pub const STATUS_CHARGING: u64 = 1 << 4;
1020 /// System is trying to discharge and recharge the battery to learn its
1021 /// capability.
1022 pub const STATUS_LEARNING: u64 = 1 << 5;
1023 /// Battery is degraded and should be checked or replaced.
1024 pub const STATUS_DEGRADED: u64 = 1 << 6;
1025 /// Battery is dead and should be replaced.
1026 pub const STATUS_ERROR: u64 = 1 << 7;
1027}
1028
1029#[repr(i32)]
1030#[derive(Debug, Clone, PartialEq, Copy)]
1031pub enum BatteryType {
1032 /// Plugin failed to detect battery type.
1033 Unknown = 1,
1034 /// Vendor specific battery type.
1035 Other = 2,
1036 /// Chemical battery, e.g. Li-ion battery.
1037 Chemical = 3,
1038 /// Super capacitor.
1039 Capacitor = 4,
1040}
1041
1042fn int_to_battery_type<'de, D: Deserializer<'de>>(
1043 deserializer: D,
1044) -> ::std::result::Result<BatteryType, D::Error> {
1045 let i: i32 = Deserialize::deserialize(deserializer)?;
1046 match i {
1047 1..=4 => unsafe { Ok(transmute::<i32, BatteryType>(i)) },
1048 _ => Ok(BatteryType::Unknown),
1049 }
1050}
1051
1052#[derive(Deserialize, Debug, Clone)]
1053/// Represent capabilities supported by specific system.
1054pub struct Capabilities {
1055 cap: String,
1056}
1057
1058// TODO(Gris Ge): link function to their document URL.
1059#[repr(usize)]
1060/// Represent a capability supported by specific system.
1061pub enum Capability {
1062 /// Support `Client::volumes()`.
1063 Volumes = 20,
1064 /// Support `Client::volume_create()`.
1065 VolumeCreate = 21,
1066 /// Support `Client::volume_resize()`.
1067 VolumeResize = 22,
1068 /// Support `Client::volume_replicate()`.
1069 VolumeReplicate = 23,
1070 /// Support `Client::volume_replicate()` with
1071 /// `VolumeReplicateType::Clone`.
1072 VolumeReplicateClone = 24,
1073 /// Support `Client::volume_replicate()` with
1074 /// `VolumeReplicateType::Copy`.
1075 VolumeReplicateCopy = 25,
1076 /// Support `Client::volume_replicate()` with
1077 /// `VolumeReplicateType::MirrorAsync`.
1078 VolumeReplicateMirrorAsync = 26,
1079 /// Support `Client::volume_replicate()` with
1080 /// `VolumeReplicateType::MirrorSync`.
1081 VolumeReplicateMirrorSync = 27,
1082 /// Support `Client::volume_rep_range_blk_size()`.
1083 VolumeRepRangeBlockSize = 28,
1084 /// Support `Client::volume_rep_range()`.
1085 VolumeRepRange = 29,
1086 /// Support `Client::volume_rep_range()` with `VolumeReplicateType::Clone`.
1087 VolumeRepRangeClone = 30,
1088 /// Support `Client::volume_rep_range()` with `VolumeReplicateType::Copy`.
1089 VolumeRepRangeCopy = 31,
1090 /// Support `Client::volume_delete()`.
1091 VolumeDelete = 33,
1092 /// Support `Client::volume_enable()`.
1093 VolumeEnable = 34,
1094 /// Support `Client::volume_disable()`.
1095 VolumeDisable = 35,
1096 /// Support `Client::volume_mask()`.
1097 VolumeMask = 36,
1098 /// Support `Client::volume_unmask()`.
1099 VolumeUnmask = 37,
1100 /// Support `Client::access_groups()`.
1101 AccessGroups = 38,
1102 /// Support `Client::access_group_create()` with `InitiatorType::Wwpn`.
1103 AccessGroupCreateWwpn = 39,
1104 /// Support `Client::access_group_delete()`.
1105 AccessGroupDelete = 40,
1106 /// Support `Client::access_group_init_add()` with `InitiatorType::Wwpn`.
1107 AccessGroupInitAddWwpn = 41,
1108 /// Support `Client::access_group_init_del()`.
1109 AccessGroupInitDel = 42,
1110 /// Support `Client::vols_masked_to_ag()`.
1111 VolsMaskedToAg = 43,
1112 /// Support `Client::ags_granted_to_vol()`.
1113 AgsGrantedToVol = 44,
1114 /// Support `Client::vol_has_child_dep()`.
1115 VolHasChildDep = 45,
1116 /// Support `Client::vol_child_dep_rm()`.
1117 VolChildDepRm = 46,
1118 /// Support `Client::access_group_create()` with `InitiatorType::IscsiIqn`.
1119 AccessGroupCreateIscsiIqn = 47,
1120 /// Support `Client::access_group_init_add()` with
1121 /// `InitiatorType::IscsiIqn`.
1122 AccessGroupInitAddIscsiIqn = 48,
1123 /// Support `Client::iscsi_chap_auth_set()`.
1124 IscsiChapAuthSet = 53,
1125 /// Support `Client::vol_raid_info()`.
1126 VolRaidInfo = 54,
1127 /// Support `Client::volume_crate()` with
1128 /// `thinp=VolumeCreateArgThinP::Thin` argument.
1129 VolumeThin = 55,
1130 /// Support `Client::batteries()`.
1131 Batteries = 56,
1132 /// Support `Client::vol_cache_info()`.
1133 VolCacheInfo = 57,
1134 /// Support `Client::vol_phy_disk_cache_set().`
1135 VolPhyDiskCacheSet = 58,
1136 /// Indicate the `Client::vol_phy_disk_cache_set()` will change system
1137 /// settings which are effective on all volumes in this storage system.
1138 /// For example, on HPE SmartArray, the physical disk cache setting is a
1139 /// controller level setting.
1140 VolPhysicalDiskCacheSetSystemLevel = 59,
1141 /// Support `Client::vol_write_cache_set()` with
1142 /// `wcp=Cache::Enabled`.
1143 VolWriteCacheSetEnable = 60,
1144 /// Support `Client::vol_write_cache_set()` with
1145 /// `wcp=Cache::Auto`.
1146 VolWriteCacheSetAuto = 61,
1147 /// Support `Client::vol_write_cache_set()` with
1148 /// `wcp=Cache::Disabled`.
1149 VolWriteCacheSetDisabled = 62,
1150 /// Indicate the `Client::vol_write_cache_set()` might also impact read
1151 /// cache policy.
1152 VolWriteCacheSetImpactRead = 63,
1153 /// Indicate the `Client::vol_write_cache_set()` with
1154 /// `wcp=Cache::Enabled` might impact other volumes in the same
1155 /// system.
1156 VolWriteCacheSetWbImpactOther = 64,
1157 /// Support `Client::vol_read_cache_set()`.
1158 VolReadCacheSet = 65,
1159 /// Indicate the `Client::vol_read_cache_set()` might also impact write
1160 /// cache policy.
1161 VolReadCacheSetImpactWrite = 66,
1162 /// Support `Client::fs()`.
1163 Fs = 100,
1164 /// Support `Client::fs_delete()`.
1165 FsDelete = 101,
1166 /// Support `Client::fs_resize()`.
1167 FsResize = 102,
1168 /// Support `Client::fs_create()`.
1169 FsCreate = 103,
1170 /// Support `Client::fs_clone()`.
1171 FsClone = 104,
1172 /// Support `Client::fs_file_clone()`.
1173 FsFileClone = 105,
1174 /// Support `Client::fs_snapshots()`.
1175 FsSnapshots = 106,
1176 /// Support `Client::fs_snapshot_create()`.
1177 FsSnapshotCreate = 107,
1178 /// Support `Client::fs_snapshot_delete()`.
1179 FsSnapshotDelete = 109,
1180 /// Support `Client::fs_snapshot_restore()`.
1181 FsSnapshotRestore = 110,
1182 /// Support `Client::fs_snapshot_restore()` with `files` argument.
1183 FsSnapshotRestoreSpecificFiles = 111,
1184 /// Support `Client::fs_has_child_dep()`.
1185 FsHasChildDep = 112,
1186 /// Support `Client::fs_child_dep_rm()`.
1187 FsChildDepRm = 113,
1188 /// Support `Client::fs_child_dep_rm()` with `files` argument.
1189 FsChildDepRmSpecificFiles = 114,
1190 /// Support `Client:::nfs_exp_auth_type_list()`.
1191 NfsExportAuthTypeList = 120,
1192 /// Support `Client::nfs_exports()`.
1193 NfsExports = 121,
1194 /// Support `Client::fs_export()`.
1195 FsExport = 122,
1196 /// Support `Client::fs_unexport()`.
1197 FsUnexport = 123,
1198 /// Support `Client::fs_export()` with `export_path` argument.
1199 FsExportCustomPath = 124,
1200 /// Support `Client::system_read_cache_pct_set()`
1201 SysReadCachePctSet = 158,
1202 /// Support `Client::systems()` with valid `read_cache_pct` property.
1203 SysReadCachePctGet = 159,
1204 /// Support `Client::systems()` with valid `fw_version` property.
1205 SysFwVersionGet = 160,
1206 /// Support `Client::systems()` with valid `mode` property.
1207 SysModeGet = 161,
1208 /// Support `Client::disks()` with valid `location` property.
1209 DiskLocation = 163,
1210 /// Support `Client::disks()` with valid `rpm` property.
1211 DiskRpm = 164,
1212 /// Support `Client::disks()` with valid `link_type` property.
1213 DiskLinkType = 165,
1214 /// Support `Client::vol_ident_led_on()` and `Client::vol_ident_led_off()`.
1215 VolumeLed = 171,
1216 /// Support `Client::target_ports()`.
1217 TargetPorts = 216,
1218 /// Support `Client::disks()`.
1219 Disks = 220,
1220 /// Support `Client::pool_member_info()`.
1221 PoolMemberInfo = 221,
1222 /// Support `Client::vol_raid_create_cap_get()` and
1223 /// `Client::vol_raid_create()`.
1224 VolumeRaidCreate = 222,
1225 /// Support `Client::disks()` with valid `vpd83` property.
1226 DiskVpd83Get = 223,
1227}
1228
1229impl Capabilities {
1230 /// Check whether specific [`Capacity`][1] is supported or not.
1231 ///
1232 /// [1]: struct.Capacity.html
1233 pub fn is_supported(&self, cap: Capability) -> bool {
1234 let cap_num = cap as usize;
1235 let val = &self.cap[cap_num * 2..cap_num * 2 + 2];
1236 println!("val {}", val);
1237 matches!(val, "01")
1238 }
1239}
1240
1241#[derive(Serialize, Debug, Clone)]
1242// TODO(Gris Ge): Set URL link.
1243/// Represent a block range used `Client::volume_replicate_range()`.
1244pub struct BlockRange {
1245 class: String,
1246 #[serde(rename = "src_block")]
1247 src_blk_addr: u64,
1248 #[serde(rename = "dest_block")]
1249 dst_blk_addr: u64,
1250 #[serde(rename = "block_count")]
1251 blk_count: u64,
1252}
1253
1254impl BlockRange {
1255 /// Create a block range.
1256 pub fn new(src_blk_addr: u64, dst_blk_addr: u64, blk_count: u64) -> BlockRange {
1257 BlockRange {
1258 class: "BlockRange".to_string(),
1259 src_blk_addr,
1260 dst_blk_addr,
1261 blk_count,
1262 }
1263 }
1264}
1265
1266#[derive(Debug, Clone, PartialEq, Copy)]
1267/// Represent a volume cache policy.
1268pub enum CachePolicy {
1269 /// Cache is enabled.
1270 Enabled,
1271 /// Storage system will determine whether to use cache based on
1272 /// battery/capacitor health.
1273 Auto, // Only for write cache
1274 /// Cache is disabled.
1275 Disabled,
1276 /// Plugin failed to query cache setting.
1277 Unknown,
1278 /// Physical disk cache is determined by the disk vendor via physical
1279 /// disks' SCSI caching mode page(`0x08` page).
1280 UseDiskSetting, // Only for physical disk cache
1281}
1282
1283#[derive(Debug, Clone)]
1284/// Represent volume cache information.
1285pub struct VolumeCacheInfo {
1286 /// Write cache setting.
1287 pub write_cache_setting: CachePolicy,
1288 /// Write cache status.
1289 pub write_cache_status: CachePolicy,
1290 /// Read cache setting.
1291 pub read_cache_setting: CachePolicy,
1292 /// Read cache status
1293 pub read_cache_status: CachePolicy,
1294 /// Physical disk cache status.
1295 pub physical_disk_cache_status: CachePolicy,
1296}
1297
1298#[derive(Debug, Clone)]
1299/// Represent NFS access control information.
1300pub struct NfsAccess<'a> {
1301 /// List of hosts with root access.
1302 pub root_list: &'a [&'a str],
1303 /// List of hosts with read and write access.
1304 pub rw_list: &'a [&'a str],
1305 /// List of hosts with read only access.
1306 pub ro_list: &'a [&'a str],
1307 /// UID to map to anonymous
1308 pub anon_uid: Option<i64>,
1309 /// GID to map to anonymous
1310 pub anon_gid: Option<i64>,
1311}
1312
1313// TODO(Gris Ge): Update URL of volume_create() here
1314/// For argument `thinp` of `Client::volume_create()`
1315pub enum VolumeCreateArgThinP {
1316 /// Create fully allocated volume.
1317 Full,
1318 /// Create thin provisioning volume.
1319 Thin,
1320 /// Let storage array to decide the volume provisioning type.
1321 Default,
1322}