#!/usr/bin/perl
#
#  $Id$
# -----------------------------------------------------------------------------
#  SM_STATUS - manager var/sm/status
# -----------------------------------------------------------------------------
#  Author: Alex Titov
#  QA by:
#  Copyright: videoNEXT LLC
# -----------------------------------------------------------------------------
#  
#
# for REQ see: Rally TA2165: managing $APL/var/status (ARCHIVING or NO-ARCHIVE)
#              Rally DE2351 
#
# Archive status:
#    STOPPED | ARCHIVING | NO-ARCHIVE
#
# CIRRUS SM status:
#     ONLINE MISSING BROKEN FULL DEGRADED STOPPED STARTING
#
# Note: CIRRUS OSX only
#

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

# CONS ------------------------------------------------------------------------
my $SMST     =(split(/\//,$0))[-1];	        # the actual name of the prog
my $APL       =$ENV{APL};
my $INTERVAL  ="3";                             # 3 (secounds) is recommended
my $TOOL_NAME='sm_tool';
my $TOOL=dirname(__FILE__)."/$TOOL_NAME";       # name with path.
my $WHEELS_NAME='sm_wheels';
my $WHEELS=dirname(__FILE__)."/$WHEELS_NAME";   # name with path.
my $STATUS="$ENV{APL}/var/sm/status";           # archive status (STOPPED | ARCHIVING | NO-ARCHIVE)
my $SM_STATUS="$ENV{APL}/var/sm/sm_status";     # sm status(ONLINE MISSING BROKEN FULL DEGRADED STOPPED STARTING)
my $STATUSXML="$ENV{APL}/www/sm/status.xml";    # store the status here
my $LAYOUT_NAME='sm_layout';
my $LAYOUT=dirname(__FILE__)."/$LAYOUT_NAME";
my $DISKUTIL="/usr/sbin/diskutil info";         # for checking disk presents

# VARS ------------------------------------------------------------------------

# SIGS ------------------------------------------------------------------------
$SIG{INT} = \&terminate;
$SIG{TERM} = \&terminate;

# SUBS ------------------------------------------------------------------------
sub layout {
   if (-x $LAYOUT) {
     SM_LOG->info("run sm_layout");
     system($LAYOUT);
     sleep 15;        #time for twist a spindle
   } 
}

sub write_status {
   my ($status,$sm_status)=@_;
   #------------------------------- ARCHIVE STATUS
   open (ST,"$STATUS");                            # TBD: errors
   my $old=<ST>;
   close ST;
   chomp $old;
   if ($old ne $status) {
     SM_LOG->info("Archive Status is changed: $old -> $status");
     open (ST,">$STATUS"); 
     print ST "$status\n";
     close ST;
     open (STX,">$STATUSXML");
     print STX '<?xml version="1.0" encoding="us-ascii"?><data><status>' . $status . "</status></data>\n";
     close STX;
   }
   #------------------------------- SM STATUS
   open (ST,"$SM_STATUS");                            # TBD: errors
   $old=<ST>;
   close ST;
   chomp $old;
   if ($old ne $sm_status) {
     SM_LOG->info("Storage Status is changed: $old -> $sm_status");
     open (ST,">$SM_STATUS");
     print ST "$sm_status\n";
     close ST;
   }
}
#--------------------------------------------------------
# remove broken va-cirrus volumes
# (disk has been reformated, new USB attached etc)
#--------------------------------------------------------
sub rm_broken {
  my $vols=shift;
  foreach my $uuid (sort keys %$vols) {
     next if not ($vols->{$uuid}->{ost}=~/^(Broken|undef)$/ and $vols->{$uuid}->{NAME} eq 'va-cirrus');
     SM_LOG->info("Broken volume $uuid has to be removed");
     SM_LOG->info(`$WHEELS OFFLINE $uuid`);
     SM_LOG->info(`$TOOL   demote  $uuid`);
     SM_LOG->info(`$TOOL   remove  $uuid`);
  }
}

sub terminate {
    write_status('STOPPED','STOPPED');
    die;
}

# 1. get current wheels info
# 2. if any wheel online (or degraded) 
#       then  set ARCHIVING (var/sm/status)
#       else  set NO-ARCHIVE (var/sm/status)
# 3. set STOPED if killed

# MAIN =========================================================================
 SM_WritePid($SMST);                                # write pid for a first time
 SM_LOG->info("$SMST starts");
 my $last_time=0;
 my $last_time_rm=0;
 eval {
   for(;;) { 
     sleep 15;
     my $vols=SM_Wheels();                          # re-read volume configuration
     my $status='NO-ARCHIVE';
     my $sm_status='UNKNOWN';                       # we cannot predict status 
     my $broken=0;
     foreach my $uuid (sort keys %$vols) {
        $status='ARCHIVING'   if $vols->{$uuid}->{ost}=~/^(Online|Degraded)$/;
        $sm_status=uc($vols->{$uuid}->{ost}) if $vols->{$uuid}->{ost} ne 'Broken';
        $broken++             if $vols->{$uuid}->{ost}=~/^(Broken|undef)$/ and $vols->{$uuid}->{NAME} eq 'va-cirrus';
     }
     if($sm_status eq 'UNKNOWN' and $broken) {      # we have few broken volumes. Check them
       $sm_status='MISSING';                        # predict that all 'va-cirrus' disks are MISSING
       foreach my $uuid (sort keys %$vols) {
          if($vols->{$uuid}->{ost} eq 'Broken' and $vols->{$uuid}->{NAME} eq 'va-cirrus' ) {
             `$DISKUTIL $uuid`;
             if($?==0) {
                $sm_status='BROKEN';               # disk present so the status is BROKEN then
                last;
             }
          }
       }
     }
     write_status($status,$sm_status);
     if($status eq 'NO-ARCHIVE' and time-$last_time>50) { # every 50 seconds when NO-ARCHIVE
       layout;                                   
       $last_time=time;
     }elsif($status eq 'ARCHIVING' and $broken>0 and time-$last_time_rm >300) { # 5 minutes 
       rm_broken($vols);
     }
     SM_WritePid($SMST);
   }
 }; # end_eval
 SM_LOG->error("SMST problem: $@");
