/[smeserver]/rpms/e-smith-base/sme10/e-smith-base-5.8.0-rewrite_manageraid.patch
ViewVC logotype

Annotation of /rpms/e-smith-base/sme10/e-smith-base-5.8.0-rewrite_manageraid.patch

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.3 - (hide annotations) (download)
Sun Jun 6 20:38:52 2021 UTC (3 years, 1 month ago) by jpp
Branch: MAIN
CVS Tags: HEAD
Changes since 1.2: +0 -0 lines
FILE REMOVED
5.8.1

1 chrissn 1.1 diff -urN e-smith-base-5.8.0.old/root/sbin/e-smith/add_drive_to_raid e-smith-base-5.8.0/root/sbin/e-smith/add_drive_to_raid
2     --- e-smith-base-5.8.0.old/root/sbin/e-smith/add_drive_to_raid 2008-03-26 16:49:00.000000000 +0000
3     +++ e-smith-base-5.8.0/root/sbin/e-smith/add_drive_to_raid 2020-12-23 17:45:39.455641041 +0000
4     @@ -31,133 +31,96 @@
5     GetOptions(\%options, 'f', 'force');
6    
7     my $force = $options{f} || $options{force};
8     -
9     my $newdev = $ARGV[0] || die "usage:\n\n\tadd_drive_to_raid [-f] dev\n\n";
10     -
11     +my $target_drive = "/dev/$newdev";
12     my $raid = require "/sbin/e-smith/console-menu-items/manageRAID.pl";
13    
14     +# Log STDOUT from this point on and return STDERR back to the console
15     +my $pid = open(STDOUT, "|-");
16     +die gettext("Can't fork"), ": $!\n" unless defined $pid;
17     +
18     +unless ($pid)
19     +{
20     + exec qw(/usr/bin/logger -p local1.info -t add_drive_to_raid);
21     +}
22     +
23     +# Get dictionary of active md devices and sort by size
24     my %devices = $raid->get_raid_details();
25     my @devices = sort { $devices{$a}{DeviceSize} <=> $devices{$b}{DeviceSize} } keys %devices;
26    
27     die "There are no RAID devices configured\n" unless $#devices >= 0;
28    
29     +# Get dictionary of all partitions from /proc/partitions
30     my %partitions = $raid->get_partitions();
31     my @partitions;
32    
33     -my $minsize = 0;
34     -
35     -die "/dev/$newdev is not a block special device\n" unless -b "/dev/$newdev";
36     +die "$target_drive is not a block special device\n" unless -b $target_drive;
37    
38     +# Calculate min size of new disk to accomodate active md devices
39     +my $minsize = 0;
40     for my $dev (@devices)
41     {
42     - die "/dev/$newdev is already in use\n" if grep m#^$newdev$#, @{$devices{$dev}{UsedDisks}};
43     + die "$target_drive is already in use\n" if grep m#^$newdev$#, @{$devices{$dev}{UsedDisks}};
44     $minsize += $devices{$dev}{DeviceSize} + 65;
45     }
46    
47     -die "/dev/$newdev is not large enough\n" unless $partitions{$newdev}{blocks} >= $minsize;
48     -
49     -die "/dev/$newdev already contains partitions\n" unless $force or ! grep m#^$newdev.+$#, keys %partitions;
50     +die "$target_drive is not large enough\n" unless $partitions{$newdev}{blocks} >= $minsize;
51     +die "$target_drive already contains partitions\n" unless $force or ! grep m#^$newdev.+$#, keys %partitions;
52    
53     -my $pid = open(STDERR, "|-");
54     -die gettext("Can't fork"), ": $!\n" unless defined $pid;
55     -
56     -unless ($pid)
57     -{
58     - exec qw(/usr/bin/logger -p local1.info -t add_drive_to_raid);
59     +# Find a healthy drive hosting our /boot partition to use as our template
60     +my @srcdrives = qx(df /boot --output=source | grep /dev/ | xargs -r lsblk -lnsp | grep disk);
61     +die "Unable to identify existing boot device - manual intervention required\n" unless (scalar @srcdrives) >= 1;
62     +my ($source_drive) = $srcdrives[0] =~ /(\S+)/;
63     +print "Using $source_drive as source partition template.\n";
64     +
65     +# Check if it's MBR or GPT
66     +my $pttype = qx(blkid -o value -s PTTYPE $source_drive);
67     +chomp $pttype;
68     +die "Unable to identify source partition table type for $source_drive\n" unless $pttype;
69     +print "$source_drive partition table type is $pttype\n";
70     +
71     +# Clear disk in preparation
72     +print "Wiping $target_drive...\n";
73     +system("wipefs", "-a", $target_drive) == 0
74     + or die "Error clearing existing partition table on $target_drive\n";
75     +
76     +# Copy new partition layout
77     +print "Copying partition table from $source_drive to $target_drive...\n";
78     +if ($pttype eq 'dos') {
79     + system("sfdisk -d $source_drive | sfdisk -qf --no-reread $target_drive") == 0
80     + or die "Error copying MBR partition table to $target_drive\n";
81     +} elsif ($pttype eq 'gpt') {
82     + system("sgdisk", "-R", $target_drive, $source_drive) == 0
83     + or die "Error copying GPT partition table to $target_drive\n";
84     + system("sgdisk", "-G", $target_drive) == 0
85     + or die "Error randomising GUID on $target_drive\n";
86     +} else {
87     + die "Couldn't interpret partition table type '$pttype' on $source_drive\n";
88     }
89    
90     -unless (open(OUTPUT, "-|"))
91     -{
92     - my $boot = "*";
93     - my $pid = open(SFDISK, "|-");
94     - if ($pid)
95     - {
96     - # parent
97     - for my $dev (@devices)
98     - {
99     - unless ($dev eq $devices[$#devices])
100     - {
101     - print SFDISK ",", $devices{$dev}{DeviceSize} + 65, ",fd,$boot\n";
102     - }
103     - else
104     - {
105     - print SFDISK ",,fd,$boot\n";
106     - }
107     - $boot = "-";
108     - }
109     - print SFDISK ",0\n" for (1..4);
110     - close(SFDISK) || die "SFDISK kid exited $?\n";
111     - }
112     - else
113     - {
114     - # child
115     - exec("/sbin/sfdisk", "-uB", "--no-reread", "--force", "/dev/$newdev")
116     - or die "can't exec program: $!\n";
117     - # NOTREACHED
118     - }
119     -
120     - print "\nChecking partitions on /dev/$newdev...\n";
121     - sleep(3);
122     - my $good;
123     - my $cnt = 0;
124     - do {
125     - $cnt++;
126     - $good = 1;
127     - sleep(1);
128     -
129     - %partitions = $raid->get_partitions();
130     - @partitions = sort grep m#^$newdev.+$#, keys %partitions;
131     - if ( $#devices == $#partitions ) {
132     - foreach my $part ( 0..($#devices-1) ) {
133     - $good &= $partitions{$partitions[$part]}{blocks} >= $devices{$devices[$part]}{DeviceSize} + 64;
134     - $good &= $partitions{$partitions[$part]}{blocks} <= $devices{$devices[$part]}{DeviceSize} + 68;
135     - $good &= -b "/dev/$partitions[$part]" || 0;
136     - }
137     - $good &= $partitions{$partitions[$#devices]}{blocks} >= $devices{$devices[$#devices]}{DeviceSize} + 64;
138     - $good &= -b "/dev/$partitions[$#devices]" || 0;
139     - } else {
140     - $good = 0;
141     - }
142     - } until ( $good || $cnt > 60 );
143     - print "\n";
144     -
145     - die "\nPartitions on /dev/$newdev aren't correct. Reboot may be necessary.\n" unless $good;
146     -
147     - sleep(3);
148     - foreach my $part (0..$#devices)
149     - {
150     - print "Going to add /dev/$partitions[$part] to $devices[$part]\n";
151     - system("/sbin/mdadm", $devices[$part], "--add", "/dev/$partitions[$part]");
152     - sleep(2);
153     - }
154     -
155     - print "\nWaiting for boot partition to sync before installing grub...\n";
156     - sleep(15);
157     -
158     - $pid = open(GRUB, "|-");
159     - if ($pid)
160     - {
161     - # parent
162     - print GRUB "device (hd0) /dev/$newdev\n";
163     - print GRUB "root (hd0,0)\n";
164     - print GRUB "setup (hd0)\n";
165     - print GRUB "quit\n";
166     - close(GRUB) || die "GRUB kid exited $?\n";
167     - exit(0);
168     - }
169     - else
170     - {
171     - # child
172     - exec("/sbin/grub", "--no-floppy", "--batch")
173     - or die "can't exec program: $!\n";
174     - # NOTREACHED
175     - }
176     -}
177     -while(<OUTPUT>)
178     +# Pause to sync
179     +sleep(3);
180     +
181     +# Install GRUB
182     +print "Installing GRUB on $target_drive...\n";
183     +system("grub2-install", "--recheck", $target_drive) == 0
184     + or warn "Warning - error installing GRUB to $target_drive\n";
185     +
186     +# Loop through RAID devices and add the corresponding new partitions
187     +my @srcparts;
188     +my $srcpart;
189     +my $tgtpart;
190     +foreach my $part (0..$#devices)
191     {
192     - print "$_";
193     - next unless $_;
194     - warn "$_";
195     + # Find the matching source drive partition and substitute the name
196     + @srcparts = qx(mdadm -v --detail --scan $devices[$part]);
197     + foreach my $s (@srcparts) {($srcpart) = $s =~ /devices=(\Q$source_drive\E\d+)/};
198     + $tgtpart = $srcpart =~ s/\Q$source_drive/$target_drive/r;
199     +
200 chrissn 1.2 + print "Adding $tgtpart to $devices[$part]\n";
201 chrissn 1.1 + system("/sbin/mdadm", $devices[$part], "--add", $tgtpart) == 0
202     + or die "Error adding $tgtpart to $devices[$part]";
203     }
204     -close(OUTPUT) or die "Closing stdin pipe reported: $!\n";
205    
206     +# Finished
207 chrissn 1.2 +print "Successfully added $target_drive to RAID!\n";
208 chrissn 1.1 \ No newline at end of file
209     diff -urN e-smith-base-5.8.0.old/root/sbin/e-smith/console-menu-items/manageRAID.pl e-smith-base-5.8.0/root/sbin/e-smith/console-menu-items/manageRAID.pl
210     --- e-smith-base-5.8.0.old/root/sbin/e-smith/console-menu-items/manageRAID.pl 2020-12-23 17:42:19.991247057 +0000
211     +++ e-smith-base-5.8.0/root/sbin/e-smith/console-menu-items/manageRAID.pl 2020-12-23 17:46:12.587310812 +0000
212     @@ -3,10 +3,11 @@
213     use warnings;
214     use esmith::console;
215     use Locale::gettext;
216     +use Taint::Util;
217    
218     use Data::Dumper;
219    
220     -use constant DEBUG_MANAGE_RAID => 1;
221     +use constant DEBUG_MANAGE_RAID => 0;
222    
223     sub new
224     {
225     @@ -35,11 +36,12 @@
226     my ($rc, $choice);
227    
228     use POSIX qw(strftime);
229     +
230     + SCAN:
231     my $today = strftime "%A %B %e, %Y %H:%M:%S", localtime;
232     my $title = gettext("Disk redundancy status as of") . " " . $today,
233     my $text = gettext("Current RAID status:") . "\n\n" .
234     join("", get_raid_status()) . "\n\n";
235     -
236     my %devices = get_raid_details();
237    
238     warn $text if DEBUG_MANAGE_RAID;
239     @@ -52,31 +54,40 @@
240     return;
241     }
242    
243     + # Determine the status of each array
244     my @unclean = ();
245     my @recovering = ();
246     + my @failed = ();
247     my %used_disks = ();
248    
249     for my $dev (keys %devices)
250     {
251     - $used_disks{$_}++ for (@{$devices{$dev}{UsedDisks}});
252     + $used_disks{$_}++ for (@{$devices{$dev}{UsedDisks}});
253    
254     - if ($devices{$dev}{State} =~ /recovering|resync/)
255     - {
256     + if ($devices{$dev}{FailedDevices} > 0) {
257     + push @failed, "$dev => " . $devices{$dev}{FailedDevices};
258     + }
259     +
260     + if ($devices{$dev}{State} =~ /recovering|resync/) {
261     push @recovering, "$dev => " . $devices{$dev}{State};
262     next;
263     }
264    
265     next if ($devices{$dev}{State} =~ /^(clean|active)\s*$/);
266     -
267     push @unclean, "$dev => " . $devices{$dev}{State};
268     }
269    
270     - warn "used_disks: " . Dumper(\%used_disks) . "\n" if DEBUG_MANAGE_RAID;
271     -
272     warn "unclean: @unclean\n" if DEBUG_MANAGE_RAID;
273     -
274     warn "recovering: @recovering\n" if DEBUG_MANAGE_RAID;
275     + warn "failed: @failed\n" if DEBUG_MANAGE_RAID;
276     + warn "used_disks: " . Dumper(\%used_disks) . "\n" if DEBUG_MANAGE_RAID;
277    
278     + # Check for any spare disks we could add
279     + my %free_disks = map {$_ => 1} get_disks();
280     + delete $free_disks{$_} for keys %used_disks;
281     + warn "free_disks: " . Dumper(\%free_disks) . "\n" if DEBUG_MANAGE_RAID;
282     +
283     + # Report status and return if recovering
284     if (scalar @recovering)
285     {
286     $text .= gettext("A RAID resynchronization is in progress.");
287     @@ -84,29 +95,33 @@
288     return;
289     }
290    
291     - unless (scalar @unclean)
292     + # Report status and return if arrays are inconsistent
293     + if ((scalar @unclean && scalar @unclean != scalar keys %devices) || (scalar @failed && scalar @failed != scalar keys %devices))
294     {
295     - $text .= gettext("All RAID devices are in clean state");
296     + $text .= gettext("Only some of the RAID devices are unclean or contain failed disks.") .
297     + "\n\n" .
298     + gettext("Manual intervention may be required.") . "\n\n";
299     +
300     ($rc, $choice) = $console->message_page(title => $title, text => $text);
301     return;
302     }
303    
304     - unless (scalar @unclean == scalar keys %devices)
305     + # Report status if arrays are clean and continue if a spare disk is available or there's only one disk in the system
306     + unless (scalar @unclean || scalar @failed)
307     {
308     - $text .= gettext("Only some of the RAID devices are unclean.") .
309     - "\n\n" .
310     - gettext("Manual intervention may be required.") . "\n\n";
311     -
312     + $text .= gettext("All RAID devices are in a clean state.");
313     + ($rc, $choice) = $console->message_page(title => $title, text => $text);
314     + return unless scalar keys %free_disks > 0 || scalar keys %used_disks == 1;
315     + }
316     +
317     + # Report status if all arrays are dirty and continue
318     + if ((scalar @unclean && scalar @unclean == scalar keys %devices) || (scalar @failed && scalar @failed == scalar keys %devices))
319     + {
320     + $text .= gettext("All RAID devices are in an unclean state or contain failed disks.");
321     ($rc, $choice) = $console->message_page(title => $title, text => $text);
322     - return;
323     }
324    
325     - my %free_disks = map {$_ => 1} get_disks();
326     -
327     - delete $free_disks{$_} for keys %used_disks;
328     -
329     - warn "free_disks: " . Dumper(\%free_disks) . "\n" if DEBUG_MANAGE_RAID;
330     -
331     + # Summarise disk assignments
332     my $disk_status = gettext("Current disk status:") . "\n\n";
333     $disk_status .= gettext("Installed disks") . ": " .
334     join(" ", get_disks()) . "\n";
335     @@ -115,50 +130,64 @@
336     $disk_status .= gettext("Free disks") . ": " .
337     join(" ", keys %free_disks) . "\n";
338    
339     - if (scalar keys %used_disks == 1 and scalar keys %free_disks == 0)
340     + # Spare disk scenarios
341     + # Scenario 1 - single disk or degraded array with no spare - warn
342     + if ((scalar @unclean || scalar @failed || scalar keys %used_disks == 1) && scalar keys %free_disks == 0)
343     {
344     - $text .= gettext("Your system only has a single disk drive installed or is using hardware mirroring. If you would like to enable software mirroring, please shut down, install a second disk drive (of the same capacity) and then return to this screen.");
345     + $text = $disk_status .
346     + "\n\n" .
347     + gettext("To ensure continued redundancy, please shut down, install another drive of the same capacity and then return to this screen.");
348    
349     ($rc, $choice) = $console->message_page(title => $title, text => $text);
350     return;
351     }
352    
353     - unless (scalar keys %used_disks == 1 and
354     - scalar keys %free_disks == scalar keys %used_disks)
355     + # Scenario 2 - no spares and not degraded so something has gone wrong
356     + if (scalar keys %free_disks == 0)
357     {
358     - $text .= gettext("The free and used disk count must equal one.") .
359     - "\n\n" .
360     - gettext("Manual intervention may be required.") . "\n\n" .
361     - $disk_status;
362     + $text = $disk_status .
363     + "\n\n" .
364     + gettext("Your RAID devices are in an inconsistent state, and no spare drives were detected. You may need to manually remove a failed drive from your arrays using mdadm.");
365    
366     ($rc, $choice) = $console->message_page(title => $title, text => $text);
367     return;
368     }
369    
370     - my @cmd = ("/sbin/e-smith/add_drive_to_raid", "-f", join("", keys %free_disks));
371     + # Scenario 3 - multiple spares
372     + if (scalar keys %free_disks > 1)
373     + {
374     + $text = $disk_status .
375     + "\n\n" .
376     + gettext("Multiple spare drives have been detected. This utility can only add one drive at a time. Please either shut down and remove all but one of your spare drives, or configure your array manually.");
377    
378     + ($rc, $choice) = $console->message_page(title => $title, text => $text);
379     + return;
380     + }
381     +
382     + # Scenario 4 - single spare ready to add
383     $text = $disk_status .
384     "\n\n" .
385     gettext("There is an unused disk drive in your system. Do you want to add it to the existing RAID array(s)?") .
386     - "\n\n" .
387     - gettext("WARNING: ALL DATA ON THE NEW DISK WILL BE DESTROYED!") .
388     - "\n"
389     - ;
390     + "\n\n" .
391     + gettext("WARNING: ALL DATA ON THE NEW DISK WILL BE DESTROYED!") .
392     + "\n";
393    
394     ($rc, $choice) = $console->yesno_page(title => $title, text => $text, defaultno => 1);
395     return unless ($rc == 0);
396    
397     + my @cmd = ("/sbin/e-smith/add_drive_to_raid", "-f", join("", keys %free_disks));
398     my $cmd_out = qx( @cmd 2>&1 );
399     - unless ($? == 0)
400     - {
401     - $text = gettext("The command failed:") . " @cmd" .
402     - "\n\n" . $cmd_out . "\n\n" .
403     - gettext("This configuration is not yet fully supported in these screens.");
404     + untaint $cmd_out;
405    
406     - ($rc, $choice) = $console->message_page(title => $title, text => $text);
407     - return;
408     + if ($? == 0) {
409     + $text = "\nSuccessfully added /dev/" . join("", keys %free_disks) . " to RAID!";
410     + } else {
411     + $text = gettext("The command failed:") . " @cmd" .
412     + "\n\n" . $cmd_out . "\n\n";
413     }
414     -
415     +
416     + ($rc, $choice) = $console->message_page(title => $title, text => $text);
417     + goto SCAN;
418     }
419    
420     sub get_raid_status
421     @@ -185,7 +214,7 @@
422    
423     while (<MDADM>)
424     {
425     - push @devices, $1 if ( m:ARRAY (/dev/md/\d+): )
426     + push @devices, $1 if ( m:ARRAY (/dev/md/\w+): )
427     }
428     close MDADM;
429    
430     @@ -203,7 +232,7 @@
431     my ($key, $value) = ($1, $2);
432     $key =~ s/\s//g;
433    
434     - # Allow for different mdadm output formats for DeviceSize
435     + # Allow for different mdadm output formats for DeviceSize
436     $key =~ s/UsedDevSize/DeviceSize/;
437    
438     $devices{$dev}{$key} = $value;

admin@koozali.org
ViewVC Help
Powered by ViewVC 1.2.1 RSS 2.0 feed