# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# bos720 src/bos/usr/lpp/bosinst/samples/NIM/Deploy.pm 1.1 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 2008,2009 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 

# @(#)52        1.1  src/bos/usr/lpp/bosinst/samples/NIM/Deploy.pm, bosinst, bos720 3/29/09 15:20:44

package NIM::Deploy;		# Deployable object / image class 

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

=pod

=head1 NAME

NIM::Deploy

=over 2

=item

NIM::Deploy base class.

=back

=head1 VARIABLES

=head2 %Settings

=over 2

=item * project

=item * accept_license

=item * nim_res_dir

=item * work_dir

=item * verbose

=back

=head2 %Defaults

=over 2

=item * type

=item * name

=item * location

=item * ae_dir

=item * ae_xml

=item * ae_cmd

=back

=head1 FUNCTIONS

=cut

#-------------------------------------------------------------------------------
BEGIN
{
  # print "NIM::Deploy BEGIN\n";

  use Hash::Util;
  use File::Path;
  use File::Basename;
  use NIM::Util qw(:DEFAULT !log_print !log_printf);

  %Settings = ('project'		=> 'sysp',
	       'accept_licenses'	=> 0,
	       'nim_res_dir'		=> '/export/nim',
	       'work_dir'		=> '/var/ibm/systemp/nim',
	       'verbose'		=> 0);

  # may need to default some of these values from those of the nim master's
  %Defaults = ('type'			=> undef,
	       'name'			=> undef,
	       'location'		=> undef,
	       'ae_dir'			=> undef,
	       'ae_xml'			=> undef,
	       'ae_cmd'			=> undef);
}

#-------------------------------------------------------------------------------
END
{
  # print "NIM::Deploy END\n";

  my $rc = $?;

  # print "work_dir = $Settings{'work_dir'}/$$\n";
  if ($Settings{'work_dir'})
  {
    if (-e "$Settings{'work_dir'}/$$")
    {
      if ($NIM::Util::Settings{'log_file_name'})
      {
	my $fn = basename($NIM::Util::Settings{'log_file_name'});
	my $result = invoke("ls -1 $Settings{'work_dir'}/$$ | grep -v $fn | wc -l");
	if ($#$result >= 0)
	{
	  my $num_fns = $result->[0];
	  chomp($num_fns);
	  if ($num_fns > 0)
	  {
	    # print "cd $Settings{'work_dir'}/$$; ls -1 | grep -v $fn | xargs rm -r; cd -\n";
	    invoke("cd $Settings{'work_dir'}/$$; ls -1 | grep -v $fn | xargs rm -r; cd -");
	  }
	}
      }
      else
      {
	# print "rm -r $Settings{'work_dir'}/$$\n";
	`rm -r $Settings{'work_dir'}/$$`;
      }
    }
  }
  $? = $rc;
}

#-------------------------------------------------------------------------------
sub print_settings
{
  my $this = shift;
  my ($fh) = @_;

  if (! $fh)
  {
    $fh = STDOUT;
  }
   
  print $fh "NIM::Deploy::Settings:\n";
  while (my ($key, $value) = each(%Settings))
  {
    print $fh "\t$key = \'$value\'\n";
  }
}

#-------------------------------------------------------------------------------
sub log_print
{
  if ($Settings{'verbose'})
  {
    NIM::Util::log_print(@_);
  }
}

#-------------------------------------------------------------------------------
sub log_printf
{
  if ($Settings{'verbose'})
  {
    NIM::Util::log_printf(@_);
  }
}

#-------------------------------------------------------------------------------
sub get_resource_dir
{
  my $this = shift;
  my ($resource_type) = @_;

  my $rc = $Settings{'nim_res_dir'} . '/' . $resource_type;
  if (! -e $rc)
  {
    mkpath($rc);
  }
  return $rc
}

#-------------------------------------------------------------------------------
sub new
{
  my $type = shift;
  my %args = @_;

  log_print("NIM::Deploy::new()\n");

  my $this = {};
  bless $this, $type;

  $Settings{'work_dir'} = NIM::Util::create_work_dir($Settings{'work_dir'});
  if ($NIM::Deploy::Settings{'work_dir'})
  {
    if (-e "$Settings{'work_dir'}/$$")
    {
      # conflicts with work dir in Util.pm such that the log file is getting erased
      # `rm -r $Settings{'work_dir'}/$$/*`;
    }
    else
    {
      `mkdir -p $Settings{'work_dir'}/$$`;
    }
  }
  log_print "\twork_dir = \'$Settings{'work_dir'}\'\n";

  if ($Settings{'verbose'})
  {
    $this->print_settings($NIM::Util::Settings{'log_file_handle'});
  }

  my $nim_info = undef;
  if (defined $NIM::Config{'info'})
  {
    $nim_info = $NIM::Config{'info'};
    $nim_info->refresh();
  }
  else
  {
    $nim_info = new NIM::Info();
  }
  $this->{'info'} = $nim_info;

  $this->{'deploy_index'} = $this->set_deploy_index();
  $this->{'group_index'} = 0;
  log_printf("\tdeploy_index = %08x\n", $this->{'deploy_index'});

  my $nim_masters = $nim_info->locate_masters();

  $this->{'nim_master_name'} = $nim_masters->get_first_object_name();
  $this->{'nim_master_name'} || die "Unable to find nim master: $!";
  log_print "\tmaster = \'$this->{'nim_master_name'}\'\n";

  ###
  
  $this->{'type'}	= (defined $args{'type'}	? $args{'type'}		: $Defaults{'type'});
  $this->{'name'}	= (defined $args{'name'}	? $args{'name'}		: $Defaults{'name'});
  $this->{'location'}	= (defined $args{'location'}	? $args{'location'}	: $Defaults{'location'});

  $this->{'ae_dir'}	= (defined $args{'ae_dir'}	? $args{'ae_dir'}	: '');
  $this->{'ae_xml'}	= (defined $args{'ae_xml'}	? $args{'ae_xml'}	: '');
  $this->{'ae_cmd'}	= (defined $args{'ae_cmd'}	? $args{'ae_cmd'}	: '');

  return $this;
}

#-------------------------------------------------------------------------------
sub delete
{
  my $this = shift;

  log_print("NIM::Deploy::delete()\n");

  my $mac_group_name = $this->get_nim_name('mac_group');
  my $mac_groups = $this->{'info'}->locate_machine_group_by_name($mac_group_name);
  
  if (! $mac_groups->empty())
  {
    invoke("$Cmds{'nim'} -o remove $mac_group_name");
  }
}

#-------------------------------------------------------------------------------
sub is_available_deploy_index
{
  my $this = shift;
  my ($deploy_index) = @_;

  my $re = sprintf('%s-(?:res_group|spot|mksysb|mac_group)-%08x', $Settings{'project'}, $deploy_index);
  my $results = $this->{'info'}->select_with_regexp_key_values(('^name$' => "^$re\$"));
  if ($results->empty())
  {
    return 1;
  }
  return 0;
}

#-------------------------------------------------------------------------------
sub set_deploy_index
{
  my $this = shift;
  my ($num) = @_;

  my $path_name = "$Settings{'work_dir'}/$Settings{'project'}" . '.nim_deploy.index';

  use Fcntl;
  sysopen(FH, $path_name, O_RDWR|O_CREAT, 0644)	or die "Can't open $path_name file: $!";
  flock(FH, 2)					or die "Can't flock $path_name file: $!";
  if (! $num)
  {
    $num = <FH> || 1;
    seek(FH, 0, 0)				or die "Can't rewind $path_name file: $!";
  }

  for ( ; ! $this->is_available_deploy_index($num); $num++)
  {
  }

  truncate(FH, 0)				or die "Can't truncate $path_name file: $!";
  (print FH $num+1, "\n")			or die "Can't write $path_name file: $!";
  # do not unlock this until you close
  close FH;
  
  return $num;
}

#-------------------------------------------------------------------------------
sub get_nim_name
{
  my $this = shift;
  my ($type) = @_;
  
  if ($type eq 'res_group')
  {
  }
  elsif ($type eq 'mac_group')
  {
  }
  elsif ($type eq 'resolv_conf')
  { 
    return sprintf("%s\-%s\-%08x",
		   $Settings{'project'}, $type, $this->{'deploy_index'});
  }
  else
  {
    $type = '';
    warn "NIM::Deploy::get_nim_name() called with an invalid type: $type";
  }
  return ($type ? sprintf("%s\-%s\-%08x", $Settings{'project'}, $type, $this->{'group_index'}) : '');
}

#-------------------------------------------------------------------------------
sub rm_from_mac_group
{
  my $this = shift;
  my ($machine_name) = @_;

  log_print("NIM::Deploy::rm_from_mac_group(\'$machine_name\')\n");


  # yyy
}

#-------------------------------------------------------------------------------
sub add_to_mac_group
{
  my $this = shift;
  my ($machine_name) = @_;

  log_print("NIM::Deploy::add_to_mac_group(\'$machine_name\')\n");

  # No need to delete the machine from any other machine group to which
  # it is already a member - i.e. before we can add it to a new machine group -
  # because this machine group is used for tracking machines deployed to
  # and not machines with the image currently running.  Reasoning is that
  # we could be using a shared NIM master in which case, a deployment not done
  # via this program won't update these machine groups appropriately.

  my $mac_group_name = $this->get_nim_name('mac_group');
  my $mac_groups = $this->{'info'}->locate_machine_group_by_name($mac_group_name);
  
  if ($mac_groups->empty())
  {
    log_print "\tCreating machine group \'$mac_group_name\'\n";
    invoke("$Cmds{'nim'} -o define -t mac_group -a add_member=$machine_name $mac_group_name");
  }
  else
  {
    log_print "\tAdding machine group member \'$machine_name\'\n";
    invoke("$Cmds{'nim'} -o change -a add_member=$machine_name $mac_group_name");
  }
}

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

=head2 create_resolv_conf_resource

=over 2

=item

C<$deploy-E<gt>create_resolv_conf_resource($domain, @nameservers)>

=back

=head3 DESCRIPTION

=over 2

=item

Creates a NIM resolv_conf resource.

=back

=head3 PARAMETERS

=over 2

=item * $domain (REQUIRED)

=item * @nameservers (REQUIRED)

=back

=head3 RETURNS

=over 2

=item * The name of the NIM resolv_conf resource.

=item * empty string on failure

=back

=head3 EXCEPTIONS

=cut

#-------------------------------------------------------------------------------
sub create_resolv_conf_resource
{
  my $this = shift;
  my ($domain, @nameservers) = @_;

  my $rc = '';

  if ($domain || ($#nameservers >= 0))
  {
    my $resolv_conf_dir = "$NIM::Deploy::Settings{'nim_res_dir'}/resolv_conf";
    mkpath($resolv_conf_dir);
    
    my $resolv_conf_name = $this->get_nim_name('resolv_conf');
    my $resolv_conf_pn = "$resolv_conf_dir/$resolv_conf_name";
    
    if (! -e $resolv_conf_pn)
    {
      if (open(RESOLV_CONF, ">$resolv_conf_pn"))
      {
	if ($domain)
	{
	  print RESOLV_CONF "domain $domain\n";
	}
	foreach my $nameserver (@nameservers)
	{
	  print RESOLV_CONF "nameserver $nameserver\n";
	}
      }
    }
    if (-e $resolv_conf_pn)
    {
      invoke("$Cmds{'nim'} -o define -t resolv_conf -a server=$this->{'nim_master_name'} -a location=$resolv_conf_pn $resolv_conf_name");
      $rc = $resolv_conf_name;
    }
  }
  return $rc;
}

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

=head2 delete_resolv_conf_resource

=over 2

=item

C<$deploy-E<gt>delete_resolv_conf_resource($resolv_conf_name)>

=back

=head3 DESCRIPTION

=over 2

=item

Deletes a NIM resolv_conf resource.

=back

=head3 PARAMETERS

=over 2

=item * $resolv_conf_name (REQUIRED)

=back

=head3 RETURNS

=head3 EXCEPTIONS

=cut

#-------------------------------------------------------------------------------
sub delete_resolv_conf_resource
{
  my $this = shift;
  my ($resolv_conf_name) = @_;

  my $resolv_conf = $this->{'info'}->locate_resolv_conf_by_name($resolv_conf_name);
  if (! $resolv_conf->empty())
  {
    my $location = $resolv_conf->get_first_attr_value($resolv_conf_name, 'location');
    unlink($location);
    invoke("$Cmds{'nim'} -o remove $resolv_conf_name");
  }
}

1;

# __END__

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

=head1 AUTHOR

IBM

=head1 BUGS

Please report any bugs to the L</"AUTHOR">.

=head1 SUPPORT

=head1 ACKNOWLEDGEMENTS

=head1 SEE ALSO

=begin html

<ul>
<li><a href="Deploy/Mksysb.html">NIM::Deploy::Mksysb</a>
</ul>

=end html

=cut

