From f94893c674b2bc98a8b916152ca5dc5f58a5dd84 Mon Sep 17 00:00:00 2001
From: thomas <kreitler@molgen.mpg.de>
Date: Tue, 22 Jan 2019 11:33:32 +0100
Subject: [PATCH] mxraid_assemble: Improve usability

Creation hint is now complete, the mkfs command is also given.
(bonus!)

Since the array size is calculated, one can infer a reasonable
chunk size. (100TB arrays use 512k, 50TB get 256k, and the
lower limit is 64k)

The new -r option allows to specify non default RAID types, this
might come handy if assembling these scratch-RAIDS.
---
 mxraid/mxraid_assemble | 96 +++++++++++++++++++++++++++++-------------
 1 file changed, 66 insertions(+), 30 deletions(-)

diff --git a/mxraid/mxraid_assemble b/mxraid/mxraid_assemble
index 82150ac9..1746d91f 100755
--- a/mxraid/mxraid_assemble
+++ b/mxraid/mxraid_assemble
@@ -30,17 +30,23 @@ sub exec_usage {
 
     options:
 
-      -a        assemble arrays when run as root
-      -c        check database
-      -d file   alternative database file
-      -h        print this help and exit
-      -l        list arrays on host, with -v will also show candidates
-      -m        monochrome warnings (for the purists)
-      -n label  print config records for new assemblies on host
-      -q        be quiet
-      -v        be more verbose
-      -V        print Version information and exit
-  
+      -a          assemble arrays when run as root
+      -c          check database
+      -d file     alternative database file
+      -h          print this help and exit
+      -l          list arrays on host, with -v will also show candidates
+      -m          monochrome warnings (for the purists)
+      -n label    print config records for new assemblies on host
+      -q          be quiet
+      -r l:d(:m)  config hints, if not a RAID 6 with 16 disks (level, disks, match)
+      -v          be more verbose
+      -V          print Version information and exit
+
+    example (list state and assist in assembling a RAID1):
+
+           mxraid_assemble -lv -n D0014 -r 1:2:flash
+
+
 __HELP
   
 =things to come  
@@ -81,7 +87,7 @@ sub check_enclosures {
 my $ROOT=$<==0?1:0;
 
 my %opts;
-getopts('acd:hlmn:qvV', \%opts) or die "# ERROR: getopts failed, try -h.\n";  # Values in %opts
+getopts('acd:hlmn:qr:vV', \%opts) or die "# ERROR: getopts failed, try -h.\n";  # Values in %opts
 exec_usage if $opts{h};
 exec_version if $opts{V};
 
@@ -154,10 +160,16 @@ if ($opts{n}) {
   my $color = MxRaid::Color->new();
   $do_default_action = 0;
 
-  my ($entry, $cnt) = ('',0);
-  my @candidates;
+  my ($entry, $cnt, $size) = ('', 0, 0);
+  my ($level, $num_wanted, $match) = (6, 16, undef);
+  my $chunk_size = 512;
+  my $dev_no = 0;
   my @mounts = split m/\n/, `cat /proc/self/mounts`;
+  my @candidates;
 
+  if ($opts{r}) {
+    ($level,$num_wanted,$match) = split m/:/, $opts{r};
+  }
   $entry .= $opts{n}.':';
   for my $rec (@{$hd->non_raid_disks()}) {
     my $dev = $rec->[0];
@@ -166,44 +178,68 @@ if ($opts{n}) {
       warn "#  NOTE: /dev/$dev is mounted, skipping.\n" if $VERBOSE >= 2;
       next;
     }
+    if (defined $match) {
+      next unless ($rec->[1] =~ m/$match/i or $rec->[2] =~ m/$match/i);
+    }
     push @candidates, $rec->[0];
     $entry .= ' '.$rec->[1];
+    $size += $rec->[3];
     $cnt++;
   }
 
-  # warn "#  NOTE: got $cnt disk(s), default is 16.\n" if $cnt != 16;
-  # warn "#  NOTE: label '$opts{n}' doesn't look good.\n" unless $opts{n} =~ m/^[CDM][\da-f]\d{3}$/;
-  if ($cnt != 16) {
-    my $msg = "got $cnt disk(s), default is 16.";
+  if ($cnt != $num_wanted) {
+    my $msg = "got $cnt disk(s), expected $num_wanted.";
     $msg = $color->t_red($msg) unless $opts{m};
     print "#  NOTE: $msg\n";
   }
 
-
   if ($opts{n} !~ m/^[CDM][\da-f]\d{3}$/) {
-    my $msg = "label '$opts{n}' doesn't look good.";
+    my $msg = "label '$opts{n}' doesn't follow the CDM scheme.";
     $msg = $color->t_red($msg) unless $opts{m};
     print "#  NOTE: $msg\n";
   }
 
-
-  my $level=6;
-  my $chunk_size=512;
-  my $dev='md127';
   if ($cnt) {
-    print "#  Record for '$MDADMCONF_DB'\n";
+    if ($level == 0) {
+      # do nothing
+    } elsif ($level == 1) {
+      $size /= 2;
+    } elsif ($level == 5 and $cnt>1) {
+      $size = int ((($cnt-1)/$cnt) * $size);
+    } elsif ($level == 6 and $cnt>2) {
+      $size = int ((($cnt-2)/$cnt) * $size);
+    } else {
+      print "#  RAID level $level not handled ($cnt disks)\n";
+    }
+    $size /= 1024**4; # TB
+
+
+    # 100TB -> 512k, 50TB -> 256k
+    while ( $size/$chunk_size < 0.115 and $chunk_size > 64) {
+      $chunk_size/=2;
+    }
+
+    while (-e "/dev/md$dev_no") {
+      $dev_no++;
+      die "# ERROR: out of devices ($dev_no). Stopped", if $dev_no >= 128;
+    }
+
+    my $dev='md'.$dev_no;
+    print "#  Record for '$MDADMCONF_DB'\n\n";
     print $entry;
-    print "\n\n";
-    print "#  Hint for creation with mdadm:\n\n";
+    print "\n\n\n";
+    print "#  Hint for creation with mdadm & mkfs.xfs:\n\n";
     printf "mdadm -C /dev/%s -l %d -n %d -N %s -c %s %s\n\n",
              $dev,
              $level, $cnt,
              $opts{n},
-             '0x0',
+             $chunk_size,
              '/dev/' . join(' /dev/', @candidates);
 
-    my $msg = 'always check the chunk-size (-c)!';
-    printf "# HINT: %s (8TB:512/4TB:256/2TB:128)\n\n", $opts{m}?$msg:$color->t_red($msg);
+    printf "mkfs.xfs -L %s /dev/%s\n\n", lc($opts{n}), $dev;
+
+
+    printf "#  Note: size of array will be %.1f TB\n\n", $size;
   }
 }