Fixed up 3ware support, added HP smart array support
authorJamie Cameron <jcameron@webmin.com>
Wed, 14 Jan 2009 01:34:17 +0000 (01:34 +0000)
committerJamie Cameron <jcameron@webmin.com>
Wed, 14 Jan 2009 01:34:17 +0000 (01:34 +0000)
smart-status/CHANGELOG
smart-status/action.cgi
smart-status/index.cgi
smart-status/lang/en
smart-status/smart-status-lib.pl
smart-status/status_monitor.pl

index 8e105a2..4f2655f 100644 (file)
@@ -9,4 +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.
+Improved support for 3ware and HP RAID devices, so that the underlying disks are now detected and can be reported on separately.
index fa70184..52c6264 100755 (executable)
@@ -9,7 +9,7 @@ $mode = $in{'short'} ? "short" :
 
 @drives = &list_smart_disks_partitions();
 ($d) = grep { $_->{'device'} eq $in{'drive'} &&
-             $_->{'3ware'} == $in{'3ware'} } @drives;
+             $_->{'subdisk'} == $in{'subdisk'} } @drives;
 print &text($mode."_doing", $d->{'desc'}),"\n";
 if ($mode eq "short") {
        ($ok, $out) = &short_test($in{'drive'}, $d);
index 067c62e..63c509b 100755 (executable)
@@ -36,14 +36,16 @@ if ($config{'mode'} == 1 || $in{'drive'}) {
        print &ui_form_start("index.cgi");
        print "<b>$text{'index_show'}</b>\n";
        print &ui_select("drive", $in{'drive'},
-                        [ map { [ $_->{'device'},
+                        [ map { [ $_->{'device'}.":".$_->{'subdisk'},
                                   $_->{'desc'}.($_->{'model'} ? " ($_->{'model'})" : "") ] } @drives ],
                         1, 0, 0, 0, "onChange='form.submit()'");
        print &ui_submit($text{'index_ok'}),"\n";
        print &ui_form_end();
 
        if ($in{'drive'}) {
-               ($d) = grep { $_->{'device'} eq $in{'drive'} } @drives;
+               ($device, $subdisk) = split(/:/, $in{'drive'});
+               ($d) = grep { $_->{'device'} eq $device &&
+                             $_->{'subdisk'} == $subdisk } @drives;
                &show_drive($d);
                }
        }
@@ -61,9 +63,13 @@ 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);
+print &ui_hidden("subdisk", $_[0]->{'subdisk'});
+local $h = defined($_[0]->{'subdisk'}) ?
+       &text('index_drivesub', "<tt>$_[0]->{'device'}</tt>",
+                               $_[0]->{'subdisk'}) :
+       &text('index_drive', "<tt>$_[0]->{'device'}</tt>");
+print &ui_table_start($h, "width=100%", 4,
+                     [ "width=30%", undef, "width=30%", undef ]);
 local $st = &get_drive_status($_[0]->{'device'}, $_[0]);
 print &ui_table_row($text{'index_desc'},
                    $_[0]->{'desc'});
@@ -87,18 +93,32 @@ if ($st->{'support'} && $st->{'enabled'}) {
                                    "</font>");
                }
        print &ui_table_row($text{'index_check'},
-                           $st->{'check'} ? $text{'yes'} : "<font color=#ff0000>$text{'no'}</font>");
-       if ($config{'attribs'}) {
-               print &ui_table_hr();
-               local $a;
-               foreach $a (@{$st->{'attribs'}}) {
-                       next if ($a->[0] =~ /UDMA CRC Error Count/i); # too long
-                       print &ui_table_row($a->[0],
-                               $a->[2] =~ /^\s*(seconds|minutes|hours|days|months|years|weeks)\s*/i || !$a->[2] ? $a->[1]." ".$a->[2] : $a->[2]);
-                       }
-               }
+                           $st->{'check'} ? $text{'yes'} :
+                               "<font color=#ff0000>$text{'no'}</font>");
        }
 print &ui_table_end();
+
+# Show extra attributes
+if ($config{'attribs'} && @{$st->{'attribs'}}) {
+       print &ui_hidden_table_start($text{'index_attrs'}, "width=100%", 2,
+                                    "attrs", 1, [ "width=30%" ]);
+       foreach my $a (@{$st->{'attribs'}}) {
+               next if ($a->[0] =~ /UDMA CRC Error Count/i); # too long
+               print &ui_table_row($a->[0],
+                       $a->[2] =~ /^\s*(seconds|minutes|hours|days|months|years|weeks)\s*/i || !$a->[2] ? $a->[1]." ".$a->[2] : $a->[2]);
+               }
+       print &ui_hidden_table_end();
+       }
+
+# Show raw data from smartctl
+if ($config{'attribs'} && $st->{'raw'}) {
+       print &ui_hidden_table_start($text{'index_raw'}, "width=100%", 2,
+                                    "raw", @{$st->{'attribs'}} ? 0 : 1);
+       print &ui_table_row(undef,
+               "<pre>".&html_escape($st->{'raw'})."</pre>", 2);
+       print &ui_hidden_table_end();
+       }
+
 if ($st->{'support'} && $st->{'enabled'}) {
        print &ui_form_end([ [ "short", $text{'index_short'} ],
                             [ "ext", $text{'index_ext'} ],
index 578fb42..a9b2615 100644 (file)
@@ -6,6 +6,7 @@ index_show=Show status of drive:
 index_ok=Show
 index_eidescsi=No IDE or SCSI drives were found on your system.
 index_drive=Status of drive $1
+index_drivesub=Status of drive $1, disk $2
 index_desc=Location
 index_size=Drive size
 index_model=Make and model
@@ -17,6 +18,8 @@ index_ext=Extended Self Test
 index_data=Data Collection Test
 index_errors=Errors logged
 index_ecount=$1 errors detected
+index_attrs=Additional SMART attributes
+index_raw=Full SMART status report
 index_return=module index
 
 monitor_type=SMART Drive Check
index 1d4d59d..9b40086 100644 (file)
@@ -33,41 +33,65 @@ 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) {
+foreach my $d (&fdisk::list_disks_partitions()) {
+       if (($d->{'type'} eq 'scsi' || $d->{'type'} eq 'raid') &&
+           $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);
+               my $count = &count_subdisks($d, "3ware");
                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,
+                                   'subtype' => '3ware',
+                                   'subdisk' => $i,
                                  });
                        }
                $threecount++;
                }
-       else {
+       elsif ($d->{'device'} =~ /^\/dev\/cciss\/(.*)$/) {
+               # HP Smart Array .. add underlying disks
+               my $count = &count_subdisks($d, "cciss");
+               for(my $i=0; $i<$count; $i++) {
+                       push(@rv, { 'device' => $d->{'device'},
+                                   'prefix' => $d->{'device'},
+                                   'desc' => 'HP Smart Array physical disk '.$i,
+                                   'type' => 'scsi',
+                                   'subtype' => 'cciss',
+                                   'subdisk' => $i,
+                                 });
+                       }
+               }
+       elsif ($d->{'type'} eq 'scsi' || $d->{'type'} eq 'ide') {
+               # Some other disk
                push(@rv, $d);
                }
        }
 return sort { $a->{'device'} cmp $b->{'device'} ||
-             $a->{'3ware'} <=> $b->{'3ware'} } @rv;
+             $a->{'subdisk'} <=> $b->{'subdisk'} } @rv;
 }
 
-=head2 count_3ware_disks(&drive)
+=head2 count_subdisks(&drive, type)
 
-Returns the number of physical disks on some 3ware RAID device.
+Returns the number of sub-disks for a hardware RAID device, by calling
+smartctl on them until failure.
 
 =cut
-sub count_3ware_disks
+sub count_subdisks
 {
-return 4;      # XXX
+local ($d, $type) = @_;
+local $count = 0;
+while(1) {
+       local $cmd = "$config{'smartctl'} -d $type,$count ".
+                    quotemeta($d->{'device'});
+       &execute_command($cmd);
+       last if ($?);
+       $count++;
+       }
+return $count;
 }
 
 =head2 get_drive_status(device-name, [&drive])
@@ -157,6 +181,7 @@ if ($config{'attribs'}) {
        # Fetch other attributes
        local ($lastline, @attribs);
        local $doneknown = 0;
+       $rv{'raw'} = "";
        open(OUT, "$config{'smartctl'} $extra_args -a $qd |");
        while(<OUT>) {
                s/\r|\n//g;
@@ -188,6 +213,7 @@ if ($config{'attribs'}) {
                        $rv{'errors'} = $1;
                        }
                $lastline = $_;
+               $rv{'raw'} .= $_."\n";
                }
        close(OUT);
        $rv{'attribs'} = \@attribs;
@@ -292,8 +318,8 @@ if (!$drive) {
                        &list_smart_disks_partitions();
        }
 local $extra_args = $config{'extra'};
-if ($drive && defined($drive->{'3ware'})) {
-       $extra_args .= " -d 3ware,$drive->{'3ware'}";
+if ($drive && defined($drive->{'subdisk'})) {
+       $extra_args .= " -d $drive->{'subtype'},$drive->{'subdisk'}";
        }
 elsif ($config{'ata'}) {
        $extra_args .= " -d ata";
index 0cf68d1..72a7adc 100644 (file)
@@ -24,7 +24,7 @@ if (!-r $_[1]->{'drive'}) {
        }
 local @drives = &list_smart_disks_partitions();
 local ($d) = grep { $_->{'device'} eq $_[1]->{'drive'} &&
-                   $_->{'3ware'} eq $_[1]->{'3ware'} } @drives;
+                   $_->{'subdisk'} eq $_[1]->{'subdisk'} } @drives;
 if (!$d) {
        # Not in list?!
        return { 'up' => -1,
@@ -74,13 +74,13 @@ sub status_monitor_dialog
 local $rv;
 local @drives = &list_smart_disks_partitions();
 local ($inlist) = grep { $_->{'device'} eq $_[1]->{'drive'} &&
-                        $_->{'3ware'} eq $_[1]->{'3ware'} } @drives;
+                        $_->{'subdisk'} eq $_[1]->{'subdisk'} } @drives;
 $inlist = 1 if (!$_[1]->{'drive'});
 $rv .= &ui_table_row($text{'monitor_drive'},
       &ui_select("drive", !$_[1]->{'drive'} ? $drives[0]->{'device'} :
-                          $inlist ? $inlist->{'drive'}.':'.$inlist->{'3ware'} :
+                          $inlist ? $inlist->{'drive'}.':'.$inlist->{'subdisk'} :
                                     undef,
-                [ (map { [ $_->{'device'}.':'.$_->{'3ware'},
+                [ (map { [ $_->{'device'}.':'.$_->{'subdisk'},
                           $_->{'desc'}.($_->{'model'} ?
                                " ($_->{'model'})" : "") ] } @drives),
                   [ "", $text{'monitor_other'} ] ]).
@@ -98,11 +98,11 @@ return $rv;
 sub status_monitor_parse
 {
 if ($_[2]->{'drive'}) {
-       ($_[1]->{'drive'}, $_[1]->{'3ware'}) = split(/:/, $_[2]->{'drive'});
+       ($_[1]->{'drive'}, $_[1]->{'subdisk'}) = split(/:/, $_[2]->{'drive'});
        }
 else {
        $_[1]->{'drive'} = $_[2]->{'other'};
-       $_[1]->{'3ware'} = undef;
+       $_[1]->{'subdisk'} = undef;
        $_[1]->{'drive'} =~ /^\S+$/ || &error($text{'monitor_edrive'});
        }
 $_[1]->{'errors'} = $_[2]->{'errors'};