#!/usr/bin/perl
#
#  $Id: sm_tool 28268 2013-04-02 00:01:58Z teetov $
# -----------------------------------------------------------------------------
#  SM_TOOL - Volume manipulation tool
# -----------------------------------------------------------------------------
#  Author: Alex Titov
#  QA by:
#  Copyright: videoNEXT LLC
# -----------------------------------------------------------------------------
# usage:   sm_tool acquire            - review 'declared' & acquire if possible
#          sm_tool adopt              - TBD: adopt early marked
#          sm_tool scan               - use 'fdisk -l' for a seaching a new vol
#          sm_tool assign id wheels   - move unassigned volume id22 to wheels
#          sm_tool demote id          - move assigned volume id22 to unassigneda
#          sm_tool list               - list all volume in the system
#
# for REQ see: Rally S623:Storage Manager with FRD  TA902: volume tool
# TBD: force umount probe before any mount probe operation
# TBD: option and device if defined

use strict;
use Digest::MD5 qw(md5_base64);
use Data::Dumper;
use File::Basename qw(dirname);
use lib dirname(__FILE__).'/../lib';             # find  SM::Config here
use SM::Config ':all';

# CONS ------------------------------------------------------------------------
my $TOOL=(split(/\//,$0))[-1];			# the actual name of the prog
my $APL=$ENV{APL};
my $SMCONF=SM_CONF;

my $MOUNT    ="sudo $APL/sm/sbin/sm_mount";
my $UMOUNT   ="sudo $APL/sm/sbin/sm_umount";
my $SMSCAN   ="sudo $APL/sm/sbin/sm_scan";      # retrun all disk resources
my $SMARK    ="sudo $APL/sm/sbin/sm_mark";
my $DF       ='df -P';                          # portable df info
                                                # initiate MRTG rescan volumes
#my $GRAPH="nohup sudo $APL/net/bin/conf_snmp_and_mrtg.pl >/dev/null 2>&1 &";
my %DEFCONFIG=(TEST=>'default',MOUNT=>'default',UMOUNT=>'default',LIMIT_WRITE=>26);

my $MOUNTPOINT="/vasm";
my $SMSTAT="$APL/var/sm/stat";                  # location for stat and status
my $GNAME    ='vol';                            # prefix for generic names
my $VER      = SM_VER;                          # va-skm version
# VARS ------------------------------------------------------------------------
my $declared;    # ex: declared->{superdisk}->{HWDEVICE}
my $unassigned;  # ex: $unassigned->{superTwo}->{HWDEVICE}
my $wheels;      # ex: $wheels->{superOne}->{HWDEVICE}
my %Ids;	 # all ids $Ids{superdisk}=56da123e51233123123, check uniq but do not enforce!
my %Names;       # all names $Names{56da123e51233123123}=superdisk
my @HwDevices;   # all HWDEVICES ! TBD lablel conversion
my $Task;     
my $TaskId;      # ex: 14307336-7824-4271-906d-fed13676422e
my $TaskLabel;   # ex: va-1234
my $TaskOption;  # ex: [force]
my $Prf;	 # prefix for logs;
# SUBS ------------------------------------------------------------------------

#-----------------------------------------------------------
# analize/validate arguments and determine THE TASK 
#-----------------------------------------------------------
sub print_usage {
 print "\n\nusage:\n"
 ."        $TOOL acquire             - acquire 'declared' volumes\n"
 ."        $TOOL scan [id]           - scan new resources for automatic declaration\n"
 ."        $TOOL scanall             - scan all resources for automatic declaration\n"
 ."        $TOOL assign id wheels    - assign volume to wheels\n"
 ."        $TOOL demote id           - return volume to unassigned\n"
 ."        $TOOL list                - list all volume in the system\n"
 ."        $TOOL add <label> [force] - do scan/acquire/assign for volume identified by label\n\n";
}

sub get_task {
 $Task=$ARGV[0];
 $TaskId=$ARGV[1];
 $Prf="[$Task] ";
 return $Task if $Task=~/^(acquire|scan|scanall|scanstore|list)$/;
 return $Task if $Task eq 'assign' and $TaskId eq 'all';
 if($Task=~/^(assign|demote|remove|restoremark)$/)   {
   if(not $TaskId=~/^(\w{8}-\w{4}-\w{4}-\w{4}-\w{12})$/) {      # check format
      print_usage;
      SM_LOG->logdie($Prf."ID=$TaskId is not recognized as valid");
   }   
   my $expectin=($Task=~/^(demote|restoremark)$/)?'wheels':'unassigned';
   if(! -f "$SMCONF/$expectin/$TaskId") { # check existance
      print_usage;
      SM_LOG->logdie($Prf."ID=$TaskId does not exist ($SMCONF/$expectin/$TaskId)");
   }
   return $Task;
 }elsif($Task eq 'add') {      # add use label instead id
   $TaskLabel=$TaskId;
   $TaskId='';
   $TaskOption=$ARGV[2] if $ARGV[2];
   return $Task;   
 }
 print_usage;
 SM_LOG->logdie("illegal call: $TOOL ". join(' ',@ARGV));
}

#-----------------------------------------------------------
# Load all configurations: declared, unassigned, wheels 
#-----------------------------------------------------------
sub load_one  {
 my $folder= shift ;
 my $path="$SMCONF/$folder";
 my $conf;
 die "ERR-CFG01: folder $path does not exist" if not -d "$path";
 opendir(DIR,$path) || die "ERR-CFG02: can't opendir $path: $!"; 
 my @files = grep { !/^\.\.?$/ and !/\.tmp$/ and !/\.stat$/ } readdir(DIR);
 closedir DIR;
 foreach my $file (@files) { # load each config into named hash
   # TBD checking name for illegal characters
   open(CONF,"$path/$file") || die "ERR-CFG03: Cannot read $file";
   my %cfg=map{/(^\w+)=(.+)/} grep {/^\w+=.+/} <CONF>;
   close CONF;
   $cfg{_filename}="$path/$file";
   $cfg{_folder}=$folder;
   $cfg{NAME}=$file if (not exists $cfg{NAME}) || $cfg{NAME} eq '';
   if($folder ne 'declared')       {       # unique name and ID check
     my ($name,$id)=($cfg{NAME},$cfg{ID});
     if(     exists $Ids{$name})   {
        SM_LOG->warn($Prf."Name=$name is not unique");
     }elsif (exists $Names{$id})       {
        SM_LOG->error($Prf."ID=$id is not unique. $path/$file is ignored");
        next;
     }
     $Ids{$name}=$id; $Names{$id}=$name;
   } else {                                # special case for declared folder
     if( defined $cfg{ID} and $cfg{ID} ) {
       my ($name,$id)=($cfg{NAME},$cfg{ID});
       $Names{$id}=$name if not exists $Names{$id};    # ID needs for unique check
     }
   }
   my $cst;                                       # target status. ONLINE|OFFLINE
   if(-f "$SMSTAT/$cfg{ID}.cst") {                # read cst from file if present
     open CST,"$SMSTAT/$cfg{ID}.cst";
     $cst=<CST>;chomp $cst;
     close CST;
   }
   $cst='OFFLINE' if $cst ne 'ONLINE';      
   $cfg{_cst}=$cst;                              # remember in conf
   push @HwDevices,$cfg{HWDEVICE} if defined $cfg{HWDEVICE}; #TBD lebel conversion
   #TBD warning if empty conf
   $conf->{$file}={%cfg}; 
 }
 return $conf;
}

sub load_conf {
 $declared  =load_one('declared'); 
 $unassigned=load_one('unassigned'); 
 $wheels    =load_one('wheels'); 
}

#-----------------------------------------------------------
# Move configuration to different folder
# transactional operation. Write all or nothing
#-----------------------------------------------------------
sub move_conf_file {
  my $conf=shift;
  my $dst=shift;              # destination: unassigned,wheels etc
 
  eval {
   my $oldname=$conf->{_filename};
   my $newname="$SMCONF/$dst/$conf->{ID}";
   my $tmpname="$newname.tmp";
   if($dst eq 'rejected')    {   # special case for rejected 
     $newname="$SMCONF/$dst/$conf->{NAME}";
     $tmpname="$newname.tmp";
     unlink $newname if -f $newname;
   }
   die("NAME conflict: $newname already exists") if -f $newname;
   open(CONF,">$tmpname") || die "Cannot open $tmpname for writing";
   foreach (sort keys %$conf) {
      next if /^_/;      # skeep internal attribute
      print(CONF "$_=$conf->{$_}\n")|| die "Cannot write to $tmpname";
   }
   close CONF;
   # ---------                                 commit (rename) phase 
   unlink $oldname if -f $oldname;           # error checking is not needed
   rename ($tmpname,$newname);
   $conf->{_filename}=$newname;
   $conf->{_folder}=$dst;
   # ---------                                 write (optional) stat
   if($conf->{_folder} ne 'declared') {
     my $stat=$conf->{_stat_space};
     my $fname="$SMSTAT/$conf->{ID}.stat";
     open(STAT,">$fname");   # no error handling, since optional
     foreach (sort keys %$stat) {
           print(STAT "$_=$stat->{$_}\n");
     }
     close STAT;
   }
  }; # end eval
  if ($@) {
     SM_LOG->error($Prf."cannot move '$conf->{NAME}' to '$dst': $@");
     return 0;
  }  
  return 1;
}

#-----------------------------------------------------------
# not used! generate MD5 base64 keys with excluding keys with '+/'
#-----------------------------------------------------------
my $last_key;

sub new_key65 {
 my $name=shift;
 for (my $i=0;;$i++) {
   my $init=sprintf "%d=$name=%d=$last_key",time,$i;
 #  print "key $init\n";
   $last_key = md5_base64($init);
   next if $last_key =~ /\/|\+/;
   return $last_key;
 }
}

#-----------------------------------------------------------
#  get free_space (MB) on mount point
#  uses 'df -P' for getting space results
#  retrun:  {SIZE,USED,FREE,RATE}
#-----------------------------------------------------------
sub space_info {
   my $mpoint=shift;
   my $bs=1024;
   my $info;
   open(DF, "$DF $mpoint 2>/dev/null|") || die ("Cannot get df -P $mpoint");
   my @rows=<DF>;
   close DF;
   foreach(@rows) {
     $info={SIZE=>int($1/1024),USED=>int($2/1024),FREE=>int($3/1024),RATE=>$4} 
                                        if /\s(\d+)\s+(\d+)\s+(\d+)\s+(\d)+%/;
   }
   #print Dumper($info); 
   return $info;
}

#------------------------------------------------------------------
#  check declared and move any usable new volumes to unassign
#------------------------------------------------------------------
sub acquire_declared {
 foreach my $name (sort keys %$declared) {
   my $cfg=$declared->{$name};
   next if defined  $cfg->{USAGE} and $cfg->{USAGE}=~/^(ignore|store)$/; 
   # ------------------ probe a new volume if fine then move to unassign
   eval {
     local $SIG{ALRM}= sub{ die "rejected since TIMEOUT $!" }; alarm 15;
     die "rejected '$name' since no ID" if (! exists $cfg->{ID}) ||  $cfg->{ID} eq '';
     my $id=$cfg->{ID};
     die "rejected '$name' ID=$id since wrong ID format" if ! $id=~/^(\w{8}-\w{4}-\w{4}-\w{4}-\w{12})$/;
     die "rejected '$name' ID=$id since ID in use by 'unassigned'" if exists $unassigned->{$id};
     die "rejected '$name' ID=$id since ID in use by 'wheels'"     if exists $wheels->{$id};
     my $mntout=`$MOUNT $cfg->{ID} '' '' probe 2>&1`;
     die("rejected '$name' ID=$id since mount error: $mntout")               if $?!=0;
     $cfg->{_stat_space}=space_info("$MOUNTPOINT/probe");
     system("$UMOUNT probe");
     die("rejected '$name' ID=$id since unexpected mount message: $mntout")  if ! $mntout=~/(ID|MSG)=(\w+)/;
     my $mntid=$2;
     # TBD check of correct respond from mount
     if(move_conf_file($cfg,'unassigned')) {   # moved successfully
       $unassigned->{$id}={%$cfg};             # copy to unassigned
       delete $declared->{$name};
       SM_LOG->info($Prf."SUCCESS: ID=$name is moved to unassigned/$id");
       SM_cinfo($id,$Prf."SUCCESS: ID=$name is UNUSED now");
     }
   };
   if ($@) { #------------------------ # error handling
      my $msg=$@; $msg=~s/\n/ /g;
      $cfg->{REJECTED}="$msg";
      SM_LOG->error($Prf."$msg");
      move_conf_file($cfg,'rejected');
   }
 }
}

#------------------------------------------------------------------
# generate unique name inside node (this is not ID22!)
#------------------------------------------------------------------

my @gen_names;				# the list of generated names;
sub generate_name {
    my $gname=shift;  
    # for testing my %ids=('vol',1,'vol123',2,'vol567',3,'volabc',1,'cda00',4);
    my $cur= (sort grep {/$gname\d\d\d$/} ("${gname}000",@gen_names,keys(%Ids),keys(%$declared)))[-1];
    $cur=~/(\d\d\d)/;
    $_=sprintf "%s%03d", $gname, $1+1;
    push @gen_names,$_;
    return $_;
}


#------------------------------------------------------------------
# scan & find new volumes. If found then declare a volume
# fdisk -l is used for scan
#   volume cansidered as a candidate if:
#     1. ID=83
#     2. size > 10GB
#     3. filesystem is present
#     4. device should not be mounted
#     5. device should not be present in /etc/fstab
# following format is assumed from LIST
#mnt  b05ba799-2801-4ca0-9ae8-4e459d46e696 <none>    3891 /dev/mapper/vg0-opt
#free 7767a069-34ac-452d-87cb-ff306f584758 va-1234   4864 /dev/mapper/vg0-wheel10
#mnt  4d059315-a671-429a-a24d-aa549ab2dcea <none>    1945 /dev/mapper/vg0-usr
#vasm ca98684e-6489-4dcd-910e-9f0f0befe6f2 va-3456   4864 /dev/mapper/vg0-wheel01
#------------------------------------------------------------------

sub scan_for_new {
 my $target=shift;   # new|all|store
 my $MINSIZE=3;
 my $label=($target eq 'store')?'va-store':'';
 my %newvols;
 eval {
   local $SIG{ALRM}= sub{ die "TIMEOUT $!" }; alarm 30;
   # -------------------------------      get a list resources from fdisk
   open(LIST, "$SMSCAN $label 2>/dev/null|") || die "cannot do $SMSCAN";
   foreach(<LIST>) {
     next if not /^(mnt|free|vasm)\s+(\w{8}-(\w{4}-){3}\w{12})\s+(\S+)\s+(\d+)\s+(\S+)/;
     my ($used,$uuid,$label,$size,$dev)=($1,$2,$4,int($5/1024),$6);
     #------------------------------  check if scan is limited ----------
    # print "$TaskId,$TaskLabel($used,$uuid,$label,$size,$dev)\n";
     next if $TaskId and $TaskId ne $uuid;
     next if $TaskLabel and $TaskLabel ne $label;
     #------------------------------      reject section   --------------
     if($used eq 'mnt')      {                # check in already mounted list
     SM_LOG->info($Prf."rejected ID=$uuid since already mounted");
     SM_cinfo ('',$Prf."rejected ID=$uuid since already mounted");
     next;
     }elsif($used eq 'fstab'){                # present in fstab
       SM_LOG->info($Prf."rejected ID=$uuid since present in fstab");
       SM_cinfo ('',$Prf."rejected ID=$uuid since present in fstab");
       next;
     }elsif($size<$MINSIZE)  {                # check a size condition
       SM_LOG->info($Prf."rejected ID=$uuid SIZE=${size}GB < ${MINSIZE}GB");
       SM_cinfo ('',$Prf."rejected ID=$uuid SIZE=${size}GB < ${MINSIZE}GB");
       next;
     }elsif(grep {/$uuid/} keys %Names) {     # check in existent IDs
       SM_LOG->info($Prf."rejected ID=$uuid since alredy in use");
       SM_cinfo ('',$Prf."rejected ID=$uuid since alredy in use");
       next;
     }
     #------------------------------      accept device-candidate -------
     SM_LOG->info($Prf."found    ID=$uuid SIZE=${size}GB\n");
     SM_cinfo ('',$Prf."found    ID=$uuid SIZE=${size}GB\n");
     $newvols{$uuid}=$label;                  # remember uuid and label
   }
   close LIST;
 };
 alarm 0;
 if ($@) { #------------------------ # error handling
   $_=$@;  #keep error code
   SM_LOG->error($Prf."Scan for new volumes fails: $_");
   SM_cerror ('',$Prf."Scan for new volumes fails: $_");
   return;
 }
# print 'newvols;' . Dumper (\%newvols);
 # --------------------------------- # MOUNT check [timeout 15]
 my %declare;
 foreach my $uuid (keys %newvols) {
  eval {
    local $SIG{ALRM}= sub{ die "rejected ID=$uuid TIMEOUT $!" }; alarm 30;
    my $mntout=`$MOUNT $uuid '' '' probe 2>&1`;
    die("rejected ID=$uuid since mount fails:$mntout") if $?;
    system("$UMOUNT probe");
    SM_LOG->info($Prf."mounted  ID=$uuid successfully");
    SM_cinfo ('',$Prf."mounted  ID=$uuid successfully");
    die("rejected ID=$uuid unexpected msg '$mntout'") if not $mntout=~/(ID|MSG)=([\w|-]+)/;
    my $val=$2;                                 # value from $mntout
    die("rejected ID=$uuid since already marked ID=$val") if $target eq 'new' and $val ne 'volume_unmarked';
    my $name=generate_name($GNAME);
    $name=$1 if $mntout=~/NAME=(\S+)/;          # use name if provided by mount
    my %vol=(NAME=>$name,ID=>$uuid,LABEL=>$newvols{$uuid},%DEFCONFIG,_filenamei=>'noName');
    $declared->{$uuid}={%vol};                  # add volume to declared pool
    move_conf_file($declared->{$uuid},'declared');
    SM_LOG->info($Prf."declared ID=$uuid NAME=$name succsessfully");
    SM_cinfo ('',$Prf."declared ID=$uuid NAME=$name succsessfully");
  };
  alarm 0;
  if($@) {
    $_=$@;
    SM_LOG->warn($Prf.$_);
    SM_cwarn ('',$Prf.$_);
  }
 }
}

#------------------------------------------------------------------
# assign volume into wheels 
# 
# conditions checks:
#     1. volume exists
#     2. volume mountable
# actions:
#     1. volume mounted into probe
#     2. [.vasm-info] is created in volume's root
#     3. ver (ex: va-2.6.0) subdir [owned by apl] is created in volumes's root
#     3. volume is unmounted
#     4. move volume's configuration to wheels
#     5. TBD: create cstatus
#------------------------------------------------------------------
sub assign_one_volume {
  my $id=shift;
  SM_LOG->logdie($Prf."ID=$id is not found in unassigned") if not exists $unassigned->{$id};
  my $cfg=$unassigned->{$id};
  my $name=$cfg->{NAME};
  eval {
    local $SIG{ALRM}= sub{ die "not assigned ID=$id [$name] since TIMEOUT $!" }; alarm 15;
    my $mntout=`$MOUNT $cfg->{ID} '' '' probe 2>&1`;
    die("not assigned ID=$id [$name] since mount error: $mntout")    if $?!=0;
#    print "$SMARK mark $VER $cfg->{_filename}\n";
    my $markout=`$SMARK mark $VER  $cfg->{_filename} 2>&1`;
    die("not assigned ID=$id [$name] since cannot mark: $markout")   if $?!=0;
    system("$UMOUNT probe");
    #---- creating config status
    open( CST,">$SMSTAT/$id.cst") || die ("cannot open >$SMSTAT/$id.cst");
    print CST "OFFLINE\n";
    close CST;
    #----
    move_conf_file($cfg,'wheels');
    SM_LOG->info($Prf."SUCCESS: ID=$id [$name] is assigned to wheels"); 
    SM_cinfo($id,$Prf."SUCCESS: ID=$id [$name] is assigned to wheels");
  };
  alarm 0;
  if ($@) { #------------------------ # error handling
     my $msg=$@; $msg=~s/\n/ /g;
     SM_LOG->error($Prf."$msg");
     SM_cerror($id,$Prf."$msg");
     system("$UMOUNT probe 1>/dev/null 2>&1"); # in case if mounted still
  }
}


#------------------------------------------------------------------
# restore mark is called when volume is restored from backup (sm_db)
#
#------------------------------------------------------------------
sub restore_mark {
  my $id=shift;
  SM_LOG->logdie($Prf."ID=$id is not found wheels") if not exists $wheels->{$id};
  my $cfg=$wheels->{$id};
  my $name=$cfg->{NAME};
  eval {
   system("$UMOUNT $cfg->{ID}");
   local $SIG{ALRM}= sub{ die "TIMEOUT $!\n" }; alarm 15;
   my $mntout=`$MOUNT $cfg->{ID} '' '' probe 2>&1`;
   die("cannot mount")         if $? != 0;   # mount fails
   my $markout=`$SMARK restore $VER  $cfg->{_filename} 2>&1`;
   die("cannot restore mark ID=$id [$name] since cannot mark: $markout")   if $?!=0;
   system("$UMOUNT probe");
  };
  alarm 0;
  if ($@) { #------------------------ # error handling
     my $msg=$@; $msg=~s/\n/ /g;
     SM_LOG->error($Prf."$msg");
     SM_cerror($id,$Prf."$msg");
     system("$UMOUNT probe 1>/dev/null 2>&1"); # in case if mounted still
  }
}


#------------------------------------------------------------------
# call assign_one_volume for each unassigned if arg==all
#------------------------------------------------------------------
sub assign_volume {
   my $arg=shift;
   if($arg ne 'all') {
     assign_one_volume($arg);
   }else {
      foreach my $id (keys %$unassigned) {
         assign_one_volume($id);
      }
   } 
}

#------------------------------------------------------------------
# demote volume from wheels into unassigned
#
# conditions checks:
#    1. volume exists in wheels
#    2. TBD: volume cstatus=OFFLINE ostatus=OFFLINE
# actions:
#    1. mount volume
#     if mounted then
#        2. DO NOT remove ver (ex: va-2.6.0) subdir
#        3. remove .vasm-info mark
#        4. umount volume
#     else (mount ERROR)
#        5. warning
#    6. move volume to unassigned
# TBD: detail review. probably should be moved to unassigned first 
#------------------------------------------------------------------

sub demote_volume {
  my $id=shift;
  SM_LOG->logdie($Prf."ID=$id is not found in wheels") if not exists $wheels->{$id};
  my $cfg=$wheels->{$id};
  my $name=$cfg->{NAME}; 
  SM_LOG->logdie($Prf."cannot demove ONLINE volume ID=$id") if $cfg->{_cst} eq 'ONLINE';
  SM_LOG->info($Prf." proceeds for ID=$id");
  eval {
   local $SIG{ALRM}= sub{ die "TIMEOUT $!\n" }; alarm 15;
   my $mntout=`$MOUNT $cfg->{ID} '' '' probe 2>&1`;
   die("cannot mount")         if $? != 0;   # mount fails
   my $markout=`$SMARK unmark 2>&1`;
   #TBD $markout analisys
  };
  alarm 0;
  SM_LOG->warn($Prf."$@; dirty ID=$id [$name] will be demoted") if $@; 
  system("$UMOUNT probe 1>/dev/null 2>&1");
  move_conf_file($cfg,'unassigned'); 
  # TBD: check error from move_conf_file
  SM_LOG->info($Prf."ID=$id [$name] is demoted");
  SM_cinfo($id,$Prf."ID=$id [$name] is demoted");
}


#------------------------------------------------------------------
sub remove_volume {
  my $id=shift;
  SM_LOG->logdie($Prf."ID=$id is not found in unassigned") if not exists $unassigned->{$id};
  my $name=$unassigned->{$id}->{NAME};
  my $conf=SM_CONF."/unassigned/$id";
  unlink $conf;
  if(-f $conf) {                     # file still exists. problems
     SM_error($id,$Prf."cannot remove volume $id [$name]");
     SM_LOG->logdie($Prf."cannot remove volume $id [$name]");
  }else {
     SM_LOG->info($Prf."volume $id [$name] is removed");
     SM_info('',$Prf."volume $id [$name] is removed");
  }
} 

#------------------------------------------------------------------
# show list of all volumes in system
# temporary implementation 

sub  list_volumes {
 $_=`cd $SMCONF && find * -type f`;
 s|/|:\t|g;
 s|wheels:|wheels:\t|g;
 print $_;
}
#------------------------------------------------------------------
# adding new volume (scan/acquire/assign - all togather)
sub add_volume {
  my $arg=($TaskOption eq 'force')?'all':'new';
  scan_for_new($arg);   
  acquire_declared;
  foreach my $id (keys %$unassigned) {
         assign_one_volume($id) if $unassigned->{$id}->{LABEL} eq $TaskLabel;
  }
   
}

# SIGS ------------------------------------------------------------------------


# MAIN ========================================================================

SM_LOG->info("$TOOL is started; arguments: (". join(' ',@ARGV).")");
get_task;
load_conf;

if($Task eq 'acquire')  { acquire_declared;                }
if($Task eq 'add')      { add_volume;                      }
if($Task eq 'scan')     { scan_for_new('new');             }
if($Task eq 'scanall')  { scan_for_new('all');             } # adopt if was marked
if($Task eq 'scanstore'){ scan_for_new('store');           } # scan for va-store adopt if was marked
if($Task eq 'assign')   { assign_volume $TaskId;  	   }
if($Task eq 'restoremark') { restore_mark $TaskId;  	   }
if($Task eq 'demote')   { demote_volume $TaskId;  	   }
if($Task eq 'remove')   { remove_volume $TaskId;           } 
if($Task eq 'list')     { list_volumes;                    }



#print 'declared '  .Dumper ($declared);
#print 'unassigned '.Dumper ($unassigned);
#print 'Names '     .Dumper \%Names;
#print 'Ids '       .Dumper \%Ids;
SM_LOG->info("$TOOL is finished");
