Work on 3ware support
authorJamie Cameron <jcameron@webmin.com>
Mon, 12 Jan 2009 03:33:39 +0000 (03:33 +0000)
committerJamie Cameron <jcameron@webmin.com>
Mon, 12 Jan 2009 03:33:39 +0000 (03:33 +0000)
smart-status/CHANGELOG
smart-status/action.cgi
smart-status/images/smallicon.gif
smart-status/index.cgi
smart-status/smart-status-lib.pl
smart-status/status_monitor.pl

index 4b1e0cd..8e105a2 100644 (file)
@@ -9,3 +9,4 @@ ATA mode is now used by default on CentOS and Redhat Enterprise versions 5 and a
 ---- Changes since 1.440 ----
 SCSI drives are visible in the System and Server Status module.
 The SMART status monitor now has an option to only alert if the error count on a drive has increased.
+Improved support for 3ware drives, so that the underlying disks are now detected and can be reported on separately.
index 44311d3..fa70184 100755 (executable)
@@ -7,17 +7,18 @@ $mode = $in{'short'} ? "short" :
        $in{'ext'} ? "ext" : "data";
 &ui_print_header(undef, $text{$mode.'_title'}, "");
 
-@drives = &fdisk::list_disks_partitions();
-($d) = grep { $_->{'device'} eq $in{'drive'} } @drives;
+@drives = &list_smart_disks_partitions();
+($d) = grep { $_->{'device'} eq $in{'drive'} &&
+             $_->{'3ware'} == $in{'3ware'} } @drives;
 print &text($mode."_doing", $d->{'desc'}),"\n";
 if ($mode eq "short") {
-       ($ok, $out) = &short_test($in{'drive'});
+       ($ok, $out) = &short_test($in{'drive'}, $d);
        }
 elsif ($mode eq "ext") {
-       ($ok, $out) = &ext_test($in{'drive'});
+       ($ok, $out) = &ext_test($in{'drive'}, $d);
        }
 elsif ($mode eq "data") {
-       ($ok, $out) = &data_test($in{'drive'});
+       ($ok, $out) = &data_test($in{'drive'}, $d);
        }
 print "<pre>$out</pre>\n";
 if ($ok) {
index e69de29..a4bc6b2 100644 (file)
Binary files a/smart-status/images/smallicon.gif and b/smart-status/images/smallicon.gif differ
index 1f631ee..067c62e 100755 (executable)
@@ -26,9 +26,7 @@ if (!$ver) {
                 &text('index_version', $ver));
 
 # Get list of drives
-@drives = grep { $_->{'type'} eq 'ide' ||
-                $_->{'type'} eq 'scsi' } &fdisk::list_disks_partitions();
-@drives = sort { $a->{'device'} cmp $b->{'device'} } @drives;
+@drives = &list_smart_disks_partitions();
 if (!@drives) {
        &ui_print_endpage($text{'index_eidescsi'});
        }
@@ -63,9 +61,10 @@ sub show_drive
 {
 print &ui_form_start("action.cgi");
 print &ui_hidden("drive", $_[0]->{'device'});
+print &ui_hidden("3ware", $_[0]->{'3ware'});
 print &ui_table_start(&text('index_drive', "<tt>$_[0]->{'device'}</tt>"),
                      undef, 2);
-local $st = &get_drive_status($_[0]->{'device'});
+local $st = &get_drive_status($_[0]->{'device'}, $_[0]);
 print &ui_table_row($text{'index_desc'},
                    $_[0]->{'desc'});
 if ($_[0]->{'cylsize'}) {
index 58a630e..1d4d59d 100644 (file)
@@ -1,15 +1,19 @@
-# Functions for getting SMART status
+=head1 smart-status-lib.pl
+
+Functions for getting SMART status
+
+=cut
 
 do '../web-lib.pl';
 &init_config();
 do '../ui-lib.pl';
 &foreign_require("fdisk", "fdisk-lib.pl");
-$extra_args = $config{'extra'};
-if ($config{'ata'}) {
-       $extra_args .= " -d ata";
-       }
 
-# get_smart_version()
+=head2 get_smart_version()
+
+Returns the version number of the SMART tools on this system
+
+=cut
 sub get_smart_version
 {
 if (!defined($smartctl_version_cache)) {
@@ -21,12 +25,62 @@ if (!defined($smartctl_version_cache)) {
 return $smartctl_version_cache;
 }
 
-# get_drive_status(device)
-# Returns a hash reference containing the status of some drive
+=head2 list_smart_disks_partitions
+
+Returns a sorted list of disks that can support SMART.
+May include faked-up 3ware devices
+
+=cut
+sub list_smart_disks_partitions
+{
+local @drives = grep { $_->{'type'} eq 'ide' ||
+                      $_->{'type'} eq 'scsi' } &fdisk::list_disks_partitions();
+local @rv;
+local $threecount = 0;
+foreach my $d (@drives) {
+       if ($d->{'type'} eq 'scsi' && $d->{'model'} =~ /3ware/i) {
+               # Actually a 3ware RAID device .. but we want to probe the
+               # underlying real disks, so add fake devices for them
+               my $count = &count_3ware_disks($d);
+               for(my $i=0; $i<$count; $i++) {
+                       push(@rv, { 'device' => '/dev/twe'.$threecount,
+                                   'prefix' => '/dev/twe'.$threecount,
+                                   'desc' => '3ware physical disk '.$i,
+                                   'type' => 'scsi',
+                                   '3ware' => $i,
+                                 });
+                       }
+               $threecount++;
+               }
+       else {
+               push(@rv, $d);
+               }
+       }
+return sort { $a->{'device'} cmp $b->{'device'} ||
+             $a->{'3ware'} <=> $b->{'3ware'} } @rv;
+}
+
+=head2 count_3ware_disks(&drive)
+
+Returns the number of physical disks on some 3ware RAID device.
+
+=cut
+sub count_3ware_disks
+{
+return 4;      # XXX
+}
+
+=head2 get_drive_status(device-name, [&drive])
+
+Returns a hash reference containing the status of some drive
+
+=cut
 sub get_drive_status
 {
+local ($device, $drive) = @_;
 local %rv;
-local $qd = quotemeta($_[0]);
+local $qd = quotemeta($device);
+local $extra_args = &get_extra_args($device, $drive);
 if (&get_smart_version() > 5.0) {
        # Use new command format
 
@@ -141,13 +195,16 @@ if ($config{'attribs'}) {
 return \%rv;
 }
 
-# short_test(drive)
+# short_test(device, [&drive])
 # Starts a short drive test, and returns 1 for success or 0 for failure, plus
 # any output.
 sub short_test
 {
+local ($device, $drive) = @_;
+local $qm = quotemeta($device);
+local $extra_args = &get_extra_args($device, $drive);
 if (&get_smart_version() > 5.0) {
-       local $out = &backquote_logged("$config{'smartctl'} $extra_args -t short $_[0] 2>&1");
+       local $out = &backquote_logged("$config{'smartctl'} $extra_args -t short $qm 2>&1");
        if ($? || $out !~ /testing has begun/i) {
                return (0, $out);
                }
@@ -156,7 +213,7 @@ if (&get_smart_version() > 5.0) {
                }
        }
 else {
-       local $out = &backquote_logged("$config{'smartctl'} $extra_args -S $_[0] 2>&1");
+       local $out = &backquote_logged("$config{'smartctl'} $extra_args -S $qm 2>&1");
        if ($? || $out !~ /test has begun/i) {
                return (0, $out);
                }
@@ -166,13 +223,16 @@ else {
        }
 }
 
-# ext_test(drive)
+# ext_test(device, [&drive])
 # Starts an extended drive test, and returns 1 for success or 0 for failure,
 # plus any output.
 sub ext_test
 {
+local ($device, $drive) = @_;
+local $qm = quotemeta($device);
+local $extra_args = &get_extra_args($device, $drive);
 if (&get_smart_version() > 5.0) {
-       local $out = &backquote_logged("$config{'smartctl'} $extra_args -t long $_[0] 2>&1");
+       local $out = &backquote_logged("$config{'smartctl'} $extra_args -t long $qm 2>&1");
        if ($? || $out !~ /testing has begun/i) {
                return (0, $out);
                }
@@ -181,7 +241,7 @@ if (&get_smart_version() > 5.0) {
                }
        }
 else {
-       local $out = &backquote_logged("$config{'smartctl'} $extra_args -X $_[0] 2>&1");
+       local $out = &backquote_logged("$config{'smartctl'} $extra_args -X $qm 2>&1");
        if ($? || $out !~ /test has begun/i) {
                return (0, $out);
                }
@@ -191,13 +251,16 @@ else {
        }
 }
 
-# data_test(drive)
+# data_test(device, [&drive])
 # Starts offline data collection, and returns 1 for success or 0 for failure,
 # plus any output.
 sub data_test
 {
+local ($device, $drive) = @_;
+local $qm = quotemeta($device);
+local $extra_args = &get_extra_args($device, $drive);
 if (&get_smart_version() > 5.0) {
-       local $out = &backquote_logged("$config{'smartctl'} $extra_args -t offline $_[0] 2>&1");
+       local $out = &backquote_logged("$config{'smartctl'} $extra_args -t offline $qm 2>&1");
        if ($? || $out !~ /testing has begun/i) {
                return (0, $out);
                }
@@ -206,7 +269,7 @@ if (&get_smart_version() > 5.0) {
                }
        }
 else {
-       local $out = &backquote_logged("$config{'smartctl'} $extra_args -O $_[0] 2>&1");
+       local $out = &backquote_logged("$config{'smartctl'} $extra_args -O $qm 2>&1");
        if ($? || $out !~ /test has begun/i) {
                return (0, $out);
                }
@@ -216,5 +279,27 @@ else {
        }
 }
 
+=head2 get_extra_args(device, [&drive])
+
+Returns extra command-line args to smartctl, needed for some drive type.
+
+=cut
+sub get_extra_args
+{
+local ($device, $drive) = @_;
+if (!$drive) {
+       ($drive) = grep { $_->{'device'} eq $device }
+                       &list_smart_disks_partitions();
+       }
+local $extra_args = $config{'extra'};
+if ($drive && defined($drive->{'3ware'})) {
+       $extra_args .= " -d 3ware,$drive->{'3ware'}";
+       }
+elsif ($config{'ata'}) {
+       $extra_args .= " -d ata";
+       }
+return $extra_args;
+}
+
 1;
 
index e9740ae..c68875c 100644 (file)
@@ -22,7 +22,15 @@ if (!-r $_[1]->{'drive'}) {
        return { 'up' => -1,
                 'desc' => $text{'monitor_nosuch'} };
        }
-local $st = &get_drive_status($_[1]->{'drive'});
+local @drives = &list_smart_disks_partitions();
+local ($d) = grep { $_->{'device'} eq $_[1]->{'drive'} &&
+                   $_->{'3ware'} eq $_[1]->{'3ware'} } @drives;
+if (!$d) {
+       # Not in list?!
+       return { 'up' => -1,
+                'desc' => $text{'monitor_nosuch'} };
+       }
+local $st = &get_drive_status($d->{'drive'}, $d);
 
 # Record number of errors since last time
 local %errors;
@@ -64,15 +72,15 @@ else {
 sub status_monitor_dialog
 {
 local $rv;
-local @drives = grep { $_->{'type'} eq 'ide' ||
-                      $_->{'type'} eq 'scsi' } &fdisk::list_disks_partitions();
-@drives = sort { $a->{'device'} cmp $b->{'device'} } @drives;
-local ($inlist) = grep { $_->{'device'} eq $_[1]->{'drive'} } @drives;
+local @drives = &list_smart_disks_partitions();
+local ($inlist) = grep { $_->{'device'} eq $_[1]->{'drive'} &&
+                        $_->{'3ware'} eq $_[1]->{'3ware'} } @drives;
 $inlist = 1 if (!$_[1]->{'drive'});
 $rv .= &ui_table_row($text{'monitor_drive'},
       &ui_select("drive", !$_[1]->{'drive'} ? $drives[0]->{'device'} :
-                          $inlist ? $_[1]->{'drive'} : undef,
-                [ (map { [ $_->{'device'},
+                          $inlist ? $inlist->{'drive'}.':'.$inlist->{'3ware'} :
+                                    undef,
+                [ (map { [ $_->{'device'}.':'.$_->{'3ware'},
                           $_->{'desc'}.($_->{'model'} ?
                                " ($_->{'model'})" : "") ] } @drives),
                   [ "", $text{'monitor_other'} ] ]).
@@ -89,8 +97,14 @@ return $rv;
 # Parse form for selecting a rule
 sub status_monitor_parse
 {
-$_[1]->{'drive'} = $_[2]->{'drive'} || $_[2]->{'other'};
-$_[1]->{'drive'} =~ /^\S+$/ || &error($text{'monitor_edrive'});
+if ($_[2]->{'drive'}) {
+       ($_[1]->{'drive'}, $_[1]->{'3ware'}) = split(/:/, $_[2]->{'drive'});
+       }
+else {
+       $_[1]->{'drive'} = $_[2]->{'other'};
+       $_[1]->{'3ware'} = undef;
+       $_[1]->{'drive'} =~ /^\S+$/ || &error($text{'monitor_edrive'});
+       }
 $_[1]->{'errors'} = $_[2]->{'errors'};
 }