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