@ -1,6 +1,7 @@
use std ::fs ;
use std ::fs ;
use regex ::{ Regex } ;
use regex ::{ Regex } ;
use rocket ::serde ::{ Serialize } ;
use rocket ::serde ::{ Serialize } ;
use lazy_static ::lazy_static ;
#[ derive(Serialize) ]
#[ derive(Serialize) ]
#[ serde(crate = " rocket::serde " ) ]
#[ serde(crate = " rocket::serde " ) ]
@ -33,11 +34,12 @@ pub fn parse_mdstat() -> MdRaidSystem {
fn parse_mdstat_str ( contents : String ) -> MdRaidSystem {
fn parse_mdstat_str ( contents : String ) -> MdRaidSystem {
let mut md_raids = Vec ::new ( ) ;
let mut md_raids = Vec ::new ( ) ;
// todo avoid recompiling regex every time
lazy_static! {
let re = Regex ::new ( r "([a-z_]{2,5}[0-9]{1,3})\s:\s(active|started|faulty)\s(raid[0-9])\s((?:\s?[a-z]{1,10}[0-9]{0,2}\[[0-9]])+)" ) . unwrap ( ) ;
static ref RE : Regex = Regex ::new ( r "([a-z_]{2,5}[0-9]{1,3})\s:\s(active|started|faulty)\s(raid[0-9])\s((?:\s?[a-z]{1,10}[0-9]{0,2}\[[0-9]])+)" ) . unwrap ( ) ;
let re_personalities = Regex ::new ( r "Personalities\s:\s((?:\s?\[(?:raid[0-9]|linear|multipath|faulty)])+)" ) . unwrap ( ) ;
static ref RE_PERSONALITIES : Regex = Regex ::new ( r "Personalities\s:\s((?:\s?\[(?:raid[0-9]|linear|multipath|faulty)])+)" ) . unwrap ( ) ;
}
for cap in re . captures_iter ( & contents ) {
for cap in RE . captures_iter ( & contents ) {
if cap . len ( ) ! = 5 {
if cap . len ( ) ! = 5 {
// todo error handling
// todo error handling
continue
continue
@ -45,6 +47,7 @@ fn parse_mdstat_str(contents: String) -> MdRaidSystem {
let devicesplit = cap [ 4 ] . split ( " " ) ;
let devicesplit = cap [ 4 ] . split ( " " ) ;
let mut devices = Vec ::new ( ) ;
let mut devices = Vec ::new ( ) ;
for i in devicesplit {
for i in devicesplit {
let i = format! ( " /dev/ {i} " ) ;
// remove brackets
// remove brackets
match i . split ( " [ " ) . next ( ) {
match i . split ( " [ " ) . next ( ) {
None = > println! ( " no [ in device string!? " ) ,
None = > println! ( " no [ in device string!? " ) ,
@ -53,7 +56,7 @@ fn parse_mdstat_str(contents: String) -> MdRaidSystem {
}
}
let raid = MdRaid {
let raid = MdRaid {
name : cap [ 1 ] . to_string ( ) ,
name : format ! ( " /dev/{} " , cap[ 1 ] . to_string ( ) ) ,
faulty : & cap [ 2 ] = = " faulty " ,
faulty : & cap [ 2 ] = = " faulty " ,
level : cap [ 3 ] . to_string ( ) ,
level : cap [ 3 ] . to_string ( ) ,
devices ,
devices ,
@ -63,7 +66,7 @@ fn parse_mdstat_str(contents: String) -> MdRaidSystem {
}
}
let mut supp_levels : Vec < String > = Vec ::new ( ) ;
let mut supp_levels : Vec < String > = Vec ::new ( ) ;
match re_personalities . captures ( & contents ) {
match RE_PERSONALITIES . captures ( & contents ) {
None = > { }
None = > { }
Some ( res ) = > {
Some ( res ) = > {
if res . len ( ) = = 2 {
if res . len ( ) = = 2 {
@ -102,6 +105,7 @@ unused devices: <none>
#[ test ]
#[ test ]
fn single_special_name ( ) {
fn single_special_name ( ) {
let exp = r # "{"raids":[{"devices":["/dev/sde1","/dev/sdf1","/dev/sdb1","/dev/sdd1","/dev/sdc1"],"faulty":false,"level":"raid5","name":"/dev/md_d0"}],"supported_levels":["raid1","raid6","raid5","raid4"]}"# ;
assert_eq! ( json! ( parse_mdstat_str ( r # "
assert_eq! ( json! ( parse_mdstat_str ( r # "
Personalities : [raid1] [raid6] [raid5] [raid4]
Personalities : [raid1] [raid6] [raid5] [raid4]
md_d0 : active raid5 sde1[0] sdf1[4] sdb1[5] sdd1[2] sdc1[1]
md_d0 : active raid5 sde1[0] sdf1[4] sdb1[5] sdd1[2] sdc1[1]
@ -109,11 +113,12 @@ md_d0 : active raid5 sde1[0] sdf1[4] sdb1[5] sdd1[2] sdc1[1]
bitmap: 0/10 pages [0KB], 16384KB chunk
bitmap: 0/10 pages [0KB], 16384KB chunk
unused devices: <none>
unused devices: <none>
"# . to_string ( ) ) ) . to_string ( ) , r # "{"raids":[{"devices":["sde1","sdf1","sdb1","sdd1","sdc1"],"faulty":false,"level":"raid5","name":"md_d0"}],"supported_levels":["raid1","raid6","raid5","raid4"]}"# ) ;
"# . to_string ( ) ) ) . to_string ( ) , exp ) ;
}
}
#[ test ]
#[ test ]
fn rebuilding_array ( ) {
fn rebuilding_array ( ) {
let exp = r # "{"raids":[{"devices":["/dev/sdh1","/dev/sdg1","/dev/sdf1","/dev/sde1","/dev/sdd1","/dev/sdc1"],"faulty":false,"level":"raid5","name":"/dev/md127"}],"supported_levels":["raid1","raid6","raid5","raid4"]}"# ;
assert_eq! ( json! ( parse_mdstat_str ( r # "
assert_eq! ( json! ( parse_mdstat_str ( r # "
Personalities : [raid1] [raid6] [raid5] [raid4]
Personalities : [raid1] [raid6] [raid5] [raid4]
md127 : active raid5 sdh1[6] sdg1[4] sdf1[3] sde1[2] sdd1[1] sdc1[0]
md127 : active raid5 sdh1[6] sdg1[4] sdf1[3] sde1[2] sdd1[1] sdc1[0]
@ -121,12 +126,13 @@ md127 : active raid5 sdh1[6] sdg1[4] sdf1[3] sde1[2] sdd1[1] sdc1[0]
[==>..................] recovery = 12.6% (37043392/292945152) finish=127.5min speed=33440K/sec
[==>..................] recovery = 12.6% (37043392/292945152) finish=127.5min speed=33440K/sec
unused devices: <none>
unused devices: <none>
"# . to_string ( ) ) ) . to_string ( ) , r # "{"raids":[{"devices":["sdh1","sdg1","sdf1","sde1","sdd1","sdc1"],"faulty":false,"level":"raid5","name":"md127"}],"supported_levels":["raid1","raid6","raid5","raid4"]}"# ) ;
"# . to_string ( ) ) ) . to_string ( ) , exp ) ;
}
}
#[ test ]
#[ test ]
fn test3 ( ) {
fn test3 ( ) {
let exp = r # "{"raids":[{"devices":["/dev/sda3","/dev/sdb3"],"faulty":false,"level":"raid0","name":"/dev/md2"},{"devices":["/dev/sda2","/dev/sdb2"],"faulty":false,"level":"raid1","name":"/dev/md1"},{"devices":["/dev/sda1","/dev/sdb1"],"faulty":false,"level":"raid1","name":"/dev/md0"}],"supported_levels":["linear","raid0","raid1"]}"# ;
assert_eq! ( json! ( parse_mdstat_str ( r # "
assert_eq! ( json! ( parse_mdstat_str ( r # "
Personalities : [linear] [raid0] [raid1] [raid10] [raid6] [raid5] [raid4]
Personalities : [linear] [raid0] [raid1] [raid10] [raid6] [raid5] [raid4]
md2 : active raid0 sda3[0] sdb3[1]
md2 : active raid0 sda3[0] sdb3[1]
@ -137,11 +143,12 @@ md1 : active raid1 sda2[0] sdb2[1]
md0 : active raid1 sda1[0] sdb1[1]
md0 : active raid1 sda1[0] sdb1[1]
2490176 blocks [2/2] [UU]
2490176 blocks [2/2] [UU]
"# . to_string ( ) ) ) . to_string ( ) , r # "{"raids":[{"devices":["sda3","sdb3"],"faulty":false,"level":"raid0","name":"md2"},{"devices":["sda2","sdb2"],"faulty":false,"level":"raid1","name":"md1"},{"devices":["sda1","sdb1"],"faulty":false,"level":"raid1","name":"md0"}],"supported_levels":["linear","raid0","raid1"]}"# ) ;
"# . to_string ( ) ) ) . to_string ( ) , exp ) ;
}
}
#[ test ]
#[ test ]
fn lots_of_devices ( ) {
fn lots_of_devices ( ) {
let exp = r # "{"raids":[{"devices":["/dev/sdb2","/dev/sda2"],"faulty":false,"level":"raid1","name":"/dev/md1"},{"devices":["/dev/sdb3","/dev/sda3"],"faulty":false,"level":"raid1","name":"/dev/md2"},{"devices":["/dev/sdl1","/dev/sdk1","/dev/sdj1","/dev/sdi1","/dev/sdh1","/dev/sdg1","/dev/sdf1","/dev/sde1","/dev/sdd1","/dev/sdc1"],"faulty":false,"level":"raid5","name":"/dev/md3"},{"devices":["/dev/sdb1","/dev/sda1"],"faulty":false,"level":"raid1","name":"/dev/md0"}],"supported_levels":["raid1","raid6","raid5","raid4"]}"# ;
assert_eq! ( json! ( parse_mdstat_str ( r # "
assert_eq! ( json! ( parse_mdstat_str ( r # "
Personalities : [raid1] [raid6] [raid5] [raid4]
Personalities : [raid1] [raid6] [raid5] [raid4]
md1 : active raid1 sdb2[1] sda2[0]
md1 : active raid1 sdb2[1] sda2[0]
@ -157,6 +164,6 @@ md0 : active raid1 sdb1[1] sda1[0]
16787776 blocks [2/2] [UU]
16787776 blocks [2/2] [UU]
unused devices: <none>
unused devices: <none>
"# . to_string ( ) ) ) . to_string ( ) , r # "{"raids":[{"devices":["sdb2","sda2"],"faulty":false,"level":"raid1","name":"md1"},{"devices":["sdb3","sda3"],"faulty":false,"level":"raid1","name":"md2"},{"devices":["sdl1","sdk1","sdj1","sdi1","sdh1","sdg1","sdf1","sde1","sdd1","sdc1"],"faulty":false,"level":"raid5","name":"md3"},{"devices":["sdb1","sda1"],"faulty":false,"level":"raid1","name":"md0"}],"supported_levels":["raid1","raid6","raid5","raid4"]}"# ) ;
"# . to_string ( ) ) ) . to_string ( ) , exp ) ;
}
}
}
}