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}