# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#-------------------------------------------------------

=head1
  xCAT plugin package to handle osdistro management

   Supported command:
         rmosdistro->rmosdistro

=cut

#-------------------------------------------------------
package xCAT_plugin::osdistro;
use Sys::Hostname;
use xCAT::Table;

use xCAT::Utils;

use xCAT::MsgUtils;
use Getopt::Long;
use Data::Dumper;
use xCAT::Yum;

#-------------------------------------------------------

=head3  handled_commands

Return list of commands handled by this plugin

=cut

#-------------------------------------------------------

sub handled_commands
{
    return {
	 	rmosdistro => "osdistro",
	   };
}


#-------------------------------------------------------

=head3  process_request

  Process the command

=cut

#-------------------------------------------------------
sub process_request
{

    my $request  = shift;
    my $callback = shift;

    my $command  = $request->{command}->[0];
    my $args     = $request->{arg};
    my $envs     = $request->{env};
    my %rsp;
    # do your processing here
    # return info

    if($command eq "rmosdistro")
    {
      &rmosdistro($request,$callback);  
    }

    return;

}



#-------------------------------------------------------

=head3  getOSdistroref

  check whether the specified osdistro is referenced 
  by any osimage. if yes, return the string of 
  osimage names, return undef otherwise 

=cut

#-------------------------------------------------------
sub getOSdistroref
{	
	my $osimagetab=shift;
	my $osdistroname=shift;

	my $ret=();
	

   	unless($osimagetab)
	{
		return undef;
	}
        # verified this does work on DB2

	my @clause=();
	
	push(@clause,"osdistroname==".$osdistroname);
	
	my @result=$osimagetab->getAllAttribsWhere(\@clause,'imagename');
	
	if(scalar @result)
	{
		foreach(@result)
		{
			$ret=$ret.$_->{'imagename'}.",";
		}
		$ret =~ s/,$//;
	}
	else
	{
		return undef;
	}
	
	return $ret;
}



#-------------------------------------------------------

=head3  rmosdistro

  remove osdistro,including remove osdistro directory 
  and entry in osdistro table

=cut

#-------------------------------------------------------

sub rmosdistro
{
    my $request  = shift;
    my $callback = shift;
        
    my $all=undef;
    my $force=undef;
    my $help=undef;
    
    my $osdistropath=undef;	
#an array of all the osdistronames to remove	
    my @OSdistroListToDel=();

    if ($request->{arg}) {
  	     	@ARGV = @{$request->{arg}};
    }


    GetOptions(
		'h|help'   => \$help,
    		'a|all'    => \$all,
		'f|force'  => \$force,  
     );


    if ($help) {
     		 $callback->({info=>"rmosdistro [{-a|--all}] [-f|--force] [osdistroname] ...",errorcode=>[0]});
     		 return;
    }

    unless($all)
    {
	unless(scalar @ARGV)
	{
     		$callback->({info=>"please specify osdistroname to remove, or specify \"-a|--all\" to remove all osdistros ",errorcode=>[1]});
     		return;
        }
        #if any osdistro has been specified,push it into array	
	push(@OSdistroListToDel,@ARGV);
    }

    my $osdistrotab = xCAT::Table->new('osdistro',-create=>1);
    unless($osdistrotab)
    {
       	$callback->({error=>"rmosdistro: failed to open table 'osdistro'!",errorcode=>[1]});
       	return;
    }


    #if -a or --all is specified,push all the osdistronames to the array to delete  
    if($all) 
    {
	my @result=$osdistrotab->getAllAttribs('osdistroname');
	if(@result and scalar @result >0)
	{
		foreach(@result)
		{
			push(@OSdistroListToDel,$_->{'osdistroname'});
		}
	}		
    }

    if(scalar @OSdistroListToDel)
    {
        #if -f|--force is not specified,need to open osimage table to check the reference of osdistro  
	my $osimagetab=undef;
	unless($force)
	{
		$osimagetab=xCAT::Table->new('osimage');
		unless($osimagetab)
		{
              	   $callback->({error=>"rmosdistro: failed to open table 'osimage'!",errorcode=>[1]});
		   $osdistrotab->close();	
        	   return;			
		}
	}

	foreach(@OSdistroListToDel)
	{

		#if -f|--force not specified,check the reference of osdistro,complain if the osdistro is referenced by some osimage
		unless($force)
		{
			my $result=&getOSdistroref($osimagetab,$_);
		        if($result)
			{
		            $callback->({error=>"rmosdistro: failed to remove $_, it is referenced by osimages:\n$result\nretry with -f option !",errorcode=>[1]});
                            next;   
			}	
		}
			
		#get "dirpaths" attribute of osdistro to remove the directory, complain if failed to lookup the osdistroname
                my %keyhash=('osdistroname' => $_,);
		my $result=$osdistrotab->getAttribs(\%keyhash,'dirpaths','basename','majorversion','minorversion','arch');
		unless($result)
		{
                         $callback->({error=>"rmosdistro: $keyhash{osdistroname}  not exist!",errorcode=>[1]});
                         next;				
		}
			
		#remove the osdistro directories
		if($result->{'dirpaths'})
		{
			   $result->{'dirpaths'} =~ s/,/\ /g;
			   #$callback->({error=>"rmosdistro: remove $result->{'dirpaths'}  directory!",errorcode=>[0]});
			   system("rm -rf $result->{'dirpaths'}");
			   if($? != 0)
				{
			           $callback->({error=>"rmosdistro: failed to remove $keyhash{osdistroname}  directory!",errorcode=>[1]});
                                   next;
				}
		}

		
		#remove the repo template
                my @ents = xCAT::TableUtils->get_site_attribute("installdir");
                my $site_ent = $ents[0];
		my $installroot;
                if( defined($site_ent) )
                {
                    $installroot = $site_ent;
                }
		xCAT::Yum->remove_yumrepo($installroot,$result->{basename}.$result->{majorversion}.(defined($result->{minorversion})?'.'.$result->{minorversion}:$result->{minorversion}),$result->{arch});	
	
		#remove the osdistro entry			
                $osdistrotab->delEntries(\%keyhash);
   		$osdistrotab->commit;
        	$callback->({info=>"rmosdistro: remove $_ success",errorcode=>[0]});
				
	}

	if($osimagetab)
	{
		$osimagetab->close;
	}
   }	


        $osdistrotab->close; 

        return;
}


1;