pf-tools commit: r538 [ccaillet-guest] - /trunk/lib/PFTools/Disk.pm
parmelan-guest at users.alioth.debian.org
parmelan-guest at users.alioth.debian.org
Mon Aug 20 13:38:24 UTC 2007
Author: ccaillet-guest
Date: Mon Aug 20 13:38:23 2007
New Revision: 538
URL: http://svn.debian.org/wsvn/pf-tools/?sc=1&rev=538
Log:
Adding disk management lib part 1
Added:
trunk/lib/PFTools/Disk.pm
Added: trunk/lib/PFTools/Disk.pm
URL: http://svn.debian.org/wsvn/pf-tools/trunk/lib/PFTools/Disk.pm?rev=538&op=file
==============================================================================
--- trunk/lib/PFTools/Disk.pm (added)
+++ trunk/lib/PFTools/Disk.pm Mon Aug 20 13:38:23 2007
@@ -1,0 +1,381 @@
+package PFTools::Disk ;
+##
+## $Id: Conf.pm 459 2007-03-07 15:16:32Z ccaillet-guest $
+##
+## Copyright (C) 2005 Olivier MOLTENI <olivier at molteni.net>
+##
+## This program is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License
+## as published by the Free Software Foundation; either version 2
+## of the License, or (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+##
+
+use strict;
+use warnings;
+
+use Exporter;
+
+our @ISA = ( 'Exporter' ) ;
+
+our @EXPORT = qw(
+ $DEBUG
+);
+
+our @EXPORT_OK = qw();
+
+#
+# Global(s) var(s)
+#
+
+### Command vars
+my $MDADM = '/sbin/mdadm' ;
+my $DRBDADM = '/sbin/drbdadm' ;
+my $MKFS = 'mkfs.' ;
+my $SFDISK = '/sbin/sfdisk' ;
+my $FDISK = '/sbin/fdisk' ;
+my $HALT = '/sbin/halt' ;
+my $ECHO = '/bin/echo' ;
+
+### Env vars
+our $DEBUG = 0 ;
+my $VERBOSE = 0 ;
+
+if ( $DEBUG ) { $VERBOSE = 1 ; }
+
+# Checking if all commands vars exists
+foreach my $cmd ( $MDADM, $MKFS, $SFDISK, $FDISK, $HALT, $ECHO ) {
+ if ( ! -e $cmd ) {
+ warn "Command ".$cmd." doesn't exist\n" if ( $VERBOSE ) ;
+ exit 1 ;
+ }
+}
+
+### /proc definitions for different files
+my $PROC_PART = '/proc/partitions' ;
+my $PROC_RAID = '/proc/mdstat' ;
+my $PROC_SCSI = '/proc/scsi/scsi' ;
+my $PROC_DRBD = '/proc/drbd' ;
+
+### Pattern(s) for misc checks
+my $DISK_DEV_PATTERN = '(h|s)d[a-z]([\\d]+)?' ;
+my $RAID_DEV_PATTERN = 'md' ;
+my $RAID_DEV = 'md0' ;
+my $RAID_DEV_STATUS = '(active sync|removed|faulty)' ;
+my $RAID_DEV_PART = $DISK_DEV_PATTERN.'\4' ;
+my $RAID_PART_NUM = '4' ;
+my $RAID_PART_TYPE = 'fd' ;
+my $RAID_FS = 'ext3' ;
+my $DRBD_DEV_PATTERN = 'drbd' ;
+my $DRBD_DEV = 'drbd0' ;
+
+
+
+#
+# System check and analysis ...
+#
+
+sub GetDiskDevice () {
+ # Call parameter(s)
+
+ # Local(s) var(s)
+ my $part ;
+ my $result = {};
+
+ if ( ! open ( $part, $PROC_PART ) ) {
+ warn "GetDiskDevice -- Unable to parse ".$PROC_PART." for analysing disk structures\n" if ( $VERBOSE ) ;
+ return undef ;
+ } else {
+ # Parsing /proc/partitions file
+ while ( <$part> ) {
+ next if ( /^$/ ) ;
+ if ( /^\s*([\d]+)\s+([\d]+)\s+([\d]+)\s+([^\s]+)$/ ) {
+ my ( $major, $minor, $block_size, $name ) = ( $1, $2, $3, $4 ) ;
+ if ( $name =~ /^$DISK_DEV_PATTERN$/ ) {
+ push ( @{$result->{'disk'}}, $name ) ;
+ if ( ! defined $result->{$name} ) { $result->{$name} = 0 ; }
+ }
+ if ( $name =~ /^$DISK_DEV_PATTERN[\d]+$/ ) { $result->{$name} +=1 }
+ if ( $name =~ /^$RAID_DEV_PATTERN[\d]+$/ ) { push ( @{$result->{'raid'}}, $name ) ; }
+ if ( $name =~ /^$DRBD_DEV_PATTERN[\d]+$/ ) { push ( @{$result->{'drbd'}}, $name ) ; }
+ }
+ }
+ close ( $part ) ;
+ }
+ return $result ;
+}
+
+sub GetDiskGeometry ($) {
+ # Call parameter(s)
+ my ( $device ) = @_ ;
+ # Local(s) var(s)
+ my $geo = {} ;
+ my ( $pad, $cyls, $heads, $sectors ) ;
+
+ if ( $device !~ /^$DISK_DEV_PATTERN$/ ) {
+ warn "GetDiskGeometry -- Wrong device name ".$device." : unable to get geometry\n" if ( $VERBOSE ) ;
+ return undef ;
+ }
+ # Retrieving geometry by sfdisk command
+ my $cmd = $SFDISK.' -f -g /dev/'.$device ;
+ $geo->{'name'} = $device ;
+ ( $pad, $cyls, $pad, $heads, $pad, $sectors ) = split ( /\s+/, `$cmd` ) ;
+ if ( $cyls == 0 || $heads == 0 || $sectors == 0 ) {
+ warn "GetDiskGeometry -- Invalid values retriveved by sfdisk for device ".$device."\n" if ( $VERBOSE ) ;
+ return undef ;
+ }
+ $geo->{'cyls'} = $cyls ;
+ $geo->{'heads'} = $heads ;
+ $geo->{'sectors'} = $sectors ;
+ return $geo ;
+}
+
+sub GetAllGeometry ($) {
+ # Call parameter(s)
+ my ( $dev_list ) = @_ ;
+ # Local(s) var(s)
+ my $geo = {} ;
+
+ foreach my $disk ( @{$dev_list->{'disk'}} ) {
+ $geo->{$disk} = GetDiskGeometry ( $disk ) ;
+ if ( ! defined ( $geo->{$disk} ) ) {
+ warn "GetAllGeometry -- Cannot retrieve geometry for all disks : see message bellow\n" if ( $VERBOSE ) ;
+ return undef ;
+ }
+ }
+ return $geo ;
+}
+
+sub CheckDiskGeometry ($) {
+ # Call parameter(s)
+ my ( $device, $ref_wanted ) = @_ ;
+ # Local(s) var(s)
+ my $ref_geo_device = {} ;
+ my ( $check_name, $wanted_name ) ;
+
+ if ( ref ( $device ) ne 'HASH' ) {
+ # $device is not an HASHREF on disk geometry
+ if ( $device !~ /^$DISK_DEV_PATTERN$/ ) {
+ warn "CheckDiskGeometry -- Wrong device name ".$device." : unable to check geometry\n" if ( $VERBOSE ) ;
+ return 0 ;
+ }
+ $ref_geo_device = GetDiskGeometry ( $device ) ;
+ if ( ! defined ( $ref_geo_device ) ) {
+ warn "CheckDiskGeometry -- Unable to retrive geometry for device ".$device."\n" if ( $VERBOSE ) ;
+ return 0 ;
+ }
+ } else {
+ $ref_geo_device = $device ;
+ }
+ $check_name = $ref_geo_device->{'name'} ;
+ $wanted_name = $ref_wanted->{'name'} ;
+ foreach my $char ( keys %{$ref_wanted} ) {
+ if ( $ref_geo_device->{$char} != $ref_wanted->{$char} ) {
+ warn "CheckDiskGeometry -- Device ".$check_name." and reference device ".$wanted_name." have not the same geometry\n" if ( $VERBOSE ) ;
+ return 0 ;
+ }
+ }
+ return 1 ;
+}
+
+sub CheckAllGeometry ($) {
+ # Call parameter(s)
+ my ( $ref_wanted ) = @_ ;
+ # Local(s) var(s)
+ my ( $dev_list, $all_geo_dev ) ;
+
+ $dev_list = GetDiskDevice () ;
+ if ( ! defined ( $dev_list ) ) {
+ warn "CheckAllGeometry -- Unable to get devices list on host\n" if ( $VERBOSE ) ;
+ return 0 ;
+ }
+ $all_geo_dev = GetAllGeometry ( $dev_list ) ;
+ if ( ! defined ( $all_geo_dev ) ) {
+ warn "CheckAllGeometry -- Unable to retrieve one ore more geometry : see error bellow\n" if ( $VERBOSE ) ;
+ return 0 ;
+ }
+
+ foreach my $disk ( keys %{$all_geo_dev} ) {
+ if ( ! CheckDiskGeometry ( $ref_wanted ) ) {
+ warn "CheckAllGeometry -- One ore more disk(s) has not the same geometry see error bellow\n" if ( $VERBOSE ) ;
+ return 0 ;
+ }
+ }
+ return 1 ;
+}
+
+sub CheckRaidArray ($) {
+ # Call parameter(s)
+ my ( $raid_dev ) = @_ ;
+ # Local(s) var(s)
+ my $part ;
+ my $stat = {} ;
+
+ if ( ! open ( $part, $MDADM.' -D '.$raid_dev ) ) {
+ print STDERR 'Unable to analyse raid status for RAID array '.$raid_dev."\n" ;
+ return undef ;
+ }
+ $stat->{'failed'} = 0 ;
+ while ( <$part> ) {
+ if ( /^\s*Failed Devices : ([\d]+)$/ && $1 > 0 ) {
+ $stat->{'failed'} = $1 ;
+ } elsif ( $stat->{'failed'} ) {
+ if ( /^\s*([\d]+)\s([\d]+)\s*([\d]+)\s*([\d]+)\s*([$RAID_DEV_STATUS])\s*($RAID_DEV_PART)$/ ) {
+ my ( $number, $major, $minor, $raid_num, $status, $device ) = ( $1, $2, $3, $4, $5, $6 ) ;
+ if ( $status !~ /^fault|failed$/ ) {
+ next ;
+ } else {
+ $device =~ s/[\d]$// ;
+ push ( @{$stat->{'failed_dev'}}, $device ) ;
+ }
+ } elsif ( /^\s*UUID : ([^\s]+)$/ ) {
+ $stat->{'uid'} = $1 ;
+ }
+ }
+ }
+ close ( $part ) ;
+ return $stat ;
+}
+
+sub CheckArrayRecovery ($) {
+ # Call parameter(s)
+ my ( $raid_dev ) = @_ ;
+ # Local(s) var(s)
+ my ( $proc, $build, $active, $check, $fail, $last_size ) ;
+
+ $active = $fail = $last_size = $check = 0 ;
+ $build = 1 ;
+ while ( ! $active ) {
+ if ( ! open ( $proc, $PROC_RAID ) ) {
+ print STDERR "" ;
+ }
+ # [>....................] recovery = 0.1% (90880/56998528) finish=93.9min speed=10097K/sec
+ while ( <$proc> ) {
+ if ( /^$raid_dev : .*$/) { $check = 1 ; }
+ if ( /^\s*(\[[^\]]+\])\s*recovery =\s*([\d]+.[\d+]%) \(([\d]+)\/[\d]+\).+$/ && $check ) {
+ if ( ! $last_size ) {
+ $last_size = $3 ;
+ } elsif ( $last_size == $3 ) {
+ if ( $fail == 3 ) {
+ print STDERR "Failure during array RAID operation\n" ;
+ return 0 ;
+ } else {
+ $fail += 1 ;
+ }
+ } else {
+ $fail = 0 ;
+ }
+ print $1.' '.$2."\r" ;
+ sleep 1 ;
+ $build = 1 ;
+ }
+ if ( /^unused devices: .*$/ && $build ){
+ $build = 0 ;
+ } else {
+ $active = 1 ;
+ }
+ }
+ }
+ return 1 ;
+}
+
+sub CheckDrbdSyncer ($) {
+ # Call parameter(s)
+ my ( $drbd_dev ) = @_ ;
+ # Local(s) var(s)
+ my ( $proc, $num_drbd, $build, $active, $check, $fail, $last_size ) ;
+
+ $drbd_dev =~ /^drbd([\d])$/ ;
+
+ $num_drbd = $1 ;
+ $active = $fail = $last_size = $check = 0 ;
+ $build = 1 ;
+ while ( ! $active ) {
+ if ( ! open ( $proc, $PROC_DRBD ) ) {
+ print STDERR "" ;
+ return 0 ;
+ }
+ # 0: cs:SyncSource st:Primary/Secondary ld:Consistent
+ # ns:38460 nr:0 dw:0 dr:38460 al:0 bm:10431 lo:0 pe:18 ua:0 ap:0
+ # [>...................] sync'ed: 0.1% (166822/166859)M
+ # finish: 4:56:34 speed: 9,596 (9,596) K/sec
+ while ( <$proc> ) {
+ if ( /^\s([\d]): cs:([^\s]+) st:([^\/]+)\/([^\s]+) ld:([^\s]+)$/ ) {
+ next if ( $1 != $num_drbd ) ;
+ if ( $2 eq 'SyncSource' ) {
+ $check = 1 ;
+ } elsif ( $2 eq 'Connected' ) {
+ $active = 1 ;
+ }
+ } elsif ( /^\s*(\[[^\]]+\]) sync'ed: ([\d]+\.[\d]+\%) \(([\d]+)\/[\d]+\)+$/ && $check ) {
+ if ( ! $last_size ) {
+ $last_size = $3 ;
+ } elsif ( $last_size == $3 ) {
+ if ( $fail == 3 ) {
+ print STDERR "Failure during array RAID operation\n" ;
+ return 0 ;
+ } else {
+ $fail += 1 ;
+ }
+ } else {
+ $fail = 0 ;
+ }
+ print $1.' '.$2."\r" ;
+ $check = 0 ;
+ sleep 1 ;
+ }
+ }
+ }
+ return 1 ;
+}
+
+#
+# Managing scsi disk(s) (add, remove)
+#
+
+sub ManageScsiDevice ($$) {
+ # Call parameter(s)
+ my ( $ref_device, $action ) = @_ ;
+ # Local(s) var(s)
+ my $cmd ;
+
+ if ( ref ( $ref_device ) ne 'ARRAY' ) {
+ warn "ManageScsiDevice -- Wrong device definition for managing SCSI channel(s)\n" if ( $VERBOSE ) ;
+ return 0 ;
+ }
+ if ( $action eq 'add' ) {
+ $cmd = $ECHO.' "scsi add-single-device '.join ( " ", @{$ref_device} ).'" > '.$PROC_SCSI ;
+ } elsif ( $action eq 'mod' ) {
+ $cmd = $ECHO.' "scsi remove-single-device '.join ( " ", @{$ref_device} ).'" > '.$PROC_SCSI ;
+ } else {
+ warn "ManageScsiDevice -- Wrong action parameter ".$action."\n" if ( $VERBOSE ) ;
+ return 0 ;
+ }
+
+ if ( $DEBUG ) {
+ print 'Exec :'.$cmd."\n" ;
+ } else {
+ `$cmd` ;
+ if ( $? << 8 ) {
+ warn "Problem when managing SCSI device ".join ( " ", @{$ref_device} )."\n" if ( $VERBOSE ) ;
+ return 0 ;
+ }
+ }
+ return 1 ;
+}
+
+#
+# Managing RAID array(s) (create, add a disk ...)
+#
+
+#
+# Managing DRBD cluster(s)
+#
More information about the Pf-tools-commits
mailing list