#!/usr/bin/perl # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # bos720 src/bos/usr/lpp/bosinst/samples/nimae.pl 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 # @(#)64 1.1 src/bos/usr/lpp/bosinst/samples/nimae.pl, bosinst, bos720 3/29/09 15:21:01 #------------------------------------------------------------------------------- =head1 NAME nimae =over 2 =item * NIM script to perform higher level operations. =item * =begin html Various startup options are available. See description for NIM. =end html =back =head1 PARAMETERS =head4 -operation install_nimae =over 2 =item * -source_dir (OPTIONAL) =item * -nim_master (OPTIONAL) =item * -nimae_dir (OPTIONAL) =back =head4 -operation deploy_image =over 2 =item * -lpar (REQUIRED) Name of the LPAR to deploy the image. =item * -image (REQUIRED) Name of the image to deploy. =item * -config (OPTIONAL) Re-configuration data (name=value) used to modify the image during activation/boot. Can be specified multiple times. =item * -nim_master (OPTIONAL) =item * -nimae_dir (OPTIONAL) =item * -cp (OPTIONAL) Files to copy to remote system. Can be specified multiple times. =back =head1 RETURNS =cut #------------------------------------------------------------------------------- BEGIN { push @INC, '/usr/lpp/bosinst/samples' } use strict; use warnings; use Hash::Util; use Getopt::Long; use File::Basename; use File::Temp; use FileHandle; use Sys::Hostname; use XML::LibXML; use Cwd; use NIM; use NIM::Util; use NIM::Deploy; use threads; use threads::shared; # Getopt::Long::Configure('debug'); Getopt::Long::Configure('pass_through'); #------------------------------------------------------------------------------- my $cmd_args = join(' ', @ARGV); log_print("$0 $cmd_args\n"); #------------------------------------------------------------------------------- my @initial_ARGV = @ARGV; my %defaults = ('nimae_dir' => '/usr/lpp/bosinst/samples'); my %opts = ('operation' => undef, 'nim_master' => undef, 'nimae_dir' => undef); GetOptions("operation=s" => \$opts{'operation'}, "nim_master=s" => \$opts{'nim_master'}, "nimae_dir=s" => \$opts{'nimae_dir'}); $opts{'work_dir'} = $NIM::Deploy::Settings{'work_dir'}; my $exit_status = 0; my $ns_uri = 'http://schemas.dmtf.org/ovf/environment/1'; #------------------------------------------------------------------------------- if ($opts{'operation'}) { while (my ($k, $v) = each(%defaults)) { if ((defined $opts{$k}) && (! $opts{$k})) { $opts{$k} = $v; } } if (run_remote_cmd() == 0) { log_print("running $opts{'operation'} locally\n"); my %handler = ( 'install_nimae' => sub { # nimae -o install_nimae -nim_master ipv4-072 -source_dir . -nimae_dir /tmp/nimae log_print("install_nimae\n"); $opts{'source_dir'} = undef; GetOptions("source_dir=s" => \$opts{'source_dir'}); if (! $opts{'source_dir'}) { if ($opts{'nimae_dir'}) { $opts{'source_dir'} = $opts{'nimae_dir'}; } else { $opts{'source_dir'} = $defaults{'nimae_dir'}; } } if (! $opts{'nimae_dir'}) { $opts{'nimae_dir'} = $defaults{'nimae_dir'}; } if ($opts{'nim_master'} || die "-nim_master is a required option\n") { invoke("cd $opts{'source_dir'}; tar -chf - * | ssh root\@$opts{'nim_master'} \"export LIBPATH=.; mkdir -p $opts{'nimae_dir'}; cd $opts{'nimae_dir'}; cat | tar -xf -; export PERL5LIB=AE; AE/setup;\""); } }, 'deploy_image' => sub { # nimae -o deploy_image -nim_master ipv4-072 -image was7_5300-07master_sysb -lpar ipv4-073 -config .password$=mypw -nimae_dir /tmp/nimae log_print("deploy_image\n"); $exit_status = -1; # copies the ae dir and invokes the customize script with the key/value pairs # returns the fb_script resource name $opts{'image'} = undef; $opts{'lpar'} = undef; # -ae ae_dir -config key1=value1 -config key2=value2 -config 'regexp1'=value3 my %config = (); GetOptions("image=s" => \$opts{'image'}, "lpar=s" => \$opts{'lpar'}, # target machine "config=s" => \%config); # activation profile customization if (($opts{'image'} || die "-image is a required option\n") && ($opts{'lpar'} || die "-lpar is a required option\n")) { if (NIM::is_nim_master() != 0) { my $start_time = time(); my $lpar_name = $opts{'lpar'}; my $image_name = $opts{'image'}; my $lpar = $NIM::Config{'lpars'}->{$lpar_name}; my $image = $NIM::Config{'images'}->{$image_name}; if (! $image) { # eventually need to account for generic - i.e. non-mksysb - images if (NIM::object_type($image_name) eq 'mksysb') { $image = new NIM::Deploy::Mksysb('name' => $image_name); } if ($image) { $NIM::Config{'images'}->{$image_name} = $image; } } if (($lpar || die "Machine \'$lpar_name\' not found\n") && ($image || die "Image \'$image_name\' not found\n")) { log_print("\tDeploying $image_name to $lpar_name\n"); ########################################################## my @m = mutex_lock_nb("nimae::deploy_image::$lpar_name"); ########################################################## if ($#m >= 0) { ################################ push @m, mutex_lock($lpar_name); ################################ # delete any previously allocated resources from earlier deployment to the same lpar $lpar->delete_resources(); # parse template xml my $ae_xml = parse_ae_xml($image->{'ae_xml'}); # expand regexp properties while (my ($key, $value) = each(%config)) { my $properties = get_ae_properties($ae_xml, $key); delete $config{$key}; set_ae_config($properties, $value, \%config); } # create working copy of activation engine and customized xml file my ($work_ae_dir, $work_ae_xml_pn) = customize_ae($image->{'ae_dir'}, $ae_xml, $image->{'ae_cmd'}, \%config); # if ($image->{'type'} eq 'mksysb') { if (deploy_mksysb($lpar, $image, $work_ae_dir, $image->{'ae_cmd'}, \%config, $opts{'work_dir'}, $NIM::Deploy::Settings{'remote_work_dir'})) { $exit_status = 0; } } else { warn "Unsupported image type for deploy_image operation\n"; } } else { warn "$lpar_name is already locked for deploy_image"; } ################ mutex_unlock @m; ################ } } else { die "Not nim master"; } } }, 'remove_image' => sub { log_print("remove_image\n"); $opts{'image'} = undef; GetOptions("image=s" => \$opts{'image'}); if (($opts{'image'} || die "-image is a required option\n")) { if (NIM::is_nim_master() != 0) { my $image_name = $opts{'image'}; my $image = $NIM::Config{'images'}->{$image_name}; if (! $image) { # eventually need to account for generic - i.e. non-mksysb - images if (NIM::object_type($image_name) eq 'mksysb') { $image = new NIM::Deploy::Mksysb('name' => $image_name); } } if (($image || die "Image \'$image_name\' not found\n")) { $image->delete(); delete $NIM::Config{'images'}->{$image_name}; } } } }, 'reset_lpar' => sub { log_print("reset_lpar\n"); $opts{'lpar'} = undef; GetOptions("lpar=s" => \$opts{'lpar'}); # target machine if (($opts{'lpar'} || die "-lpar is a required option\n")) { if (NIM::is_nim_master() != 0) { my $lpar_name = $opts{'lpar'}; my $lpar = $NIM::Config{'lpars'}->{$lpar_name}; ############################### my @m = mutex_lock($lpar_name); ############################### if ($lpar) { $lpar->reset(); } else { NIM::LPAR::reset_by_name($lpar_name); } ################ mutex_unlock @m; ################ } } }, 'remove_lpar' => sub { # delete the NIM machine definition # lpar should have already been shutdown log_print("remove_lpar\n"); $opts{'lpar'} = undef; GetOptions("lpar=s" => \$opts{'lpar'}); # target machine if (($opts{'lpar'} || die "-lpar is a required option\n")) { if (NIM::is_nim_master() != 0) { my $lpar_name = $opts{'lpar'}; my $lpar = $NIM::Config{'lpars'}->{$lpar_name}; ############################### my @m = mutex_lock($lpar_name); ############################### if ($lpar) { $lpar->reset(); $lpar->delete(); delete $NIM::Config{'lpars'}->{$lpar_name}; } else { NIM::LPAR::reset_by_name($lpar_name); NIM::LPAR::delete_by_name($lpar_name); } ################ mutex_unlock @m; ################ } } }, 'noop' => sub { log_print("noop\n"); }, 'test' => sub { log_print("test\n"); my %config = (); GetOptions("config=s" => \%config); # activation profile customization my $ae_xml = parse_ae_xml("AE/AP/aix.ovf"); # expand regexp properties while (my ($key, $value) = each(%config)) { my $properties = get_ae_properties($ae_xml, $key); delete $config{$key}; set_ae_config($properties, $value, \%config); } # create working copy of activation engine and customized xml file my ($work_ae_dir, $work_ae_xml_pn) = customize_ae("./AE", $ae_xml, '.', \%config); print "$work_ae_dir\n"; `cp $work_ae_dir/AP/aix.ovf /tmp`; } ); my $code = $handler{$opts{'operation'}}; if ($code) { $code->(); } else { die "Invalid operation: $opts{'operation'}"; }; my $args = join(' ', @ARGV); if ($args) { warn "Invalid option(s) specified: $args\n"; } } else { log_print("done running remote command\n"); } } # print "exit rc = $exit_status\n"; exit $exit_status; #------------------------------------------------------------------------------- sub create_tar_cmd { my @rc = ('', ''); my $dir = getcwd(); my %copy_files = (); GetOptions("cp=s" => \%copy_files); if (scalar keys (%copy_files)) { $rc[0] = 'tar -chf -'; while (my ($pn, $src_pn) = each(%copy_files)) { my $src_fn = basename($src_pn); my $src_dn = dirname($src_pn); if ($src_dn) { $rc[0] = $rc[0] . " -C $src_dn $src_fn -C $dir"; } else { $rc[0] = $rc[0] . " $src_fn"; } my $fn = basename($pn); my $dn = dirname($pn); if (($dn || $fn) && ($src_fn ne $pn)) { $rc[1] = $rc[1] . "mv $src_fn $pn;"; } } } return @rc; } #------------------------------------------------------------------------------- # Used to pass command to a remote nim master #------------------------------------------------------------------------------- sub run_remote_cmd { my $rc = 0; if ($opts{'nim_master'} && ($opts{'operation'} ne 'install_nimae')) { my $host_name = hostname(); my ($host, $aliases, $addrtype, $length, @addr) = gethostbyname $host_name; my $nim; ($nim, $aliases, $addrtype, $length, @addr) = gethostbyname $opts{'nim_master'}; log_print("host = $host / nim_master = $opts{'nim_master'}\n"); log_print("nim master = $nim\n"); my @host_parts = split('.', $host); my @nim_parts = split('.', $nim); if (($#host_parts == $#nim_parts) && ($host ne $nim) || (($#host_parts == 0) || ($#nim_parts == 0)) && ($host_parts[0] ne $nim_parts[0])) { log_print("running remote command\n"); my $cmd = basename($0); if ($opts{'nimae_dir'}) { $cmd = $opts{'nimae_dir'} . '/' . $cmd; } @ARGV = @initial_ARGV; my @cmds = create_tar_cmd(); my $tar_cmd = $cmds[0]; my $args = join(' ', @ARGV); # pass along stdin my $input_str = NIM::Util::read_stdin(); if ($input_str) { # $input_str =~ s/\n//g; $input_str =~ s/'/\\'/g; $input_str =~ s/"/\\"/g; $input_str =~ s/\$/\\\$/g; $input_str = "echo \'$input_str\' |"; } # work dir needs to be requestor unique since this is a requestor driven request to put data and run command my $ssh_work_dir = "$opts{'work_dir'}/$host/$$"; log_print("running \'ssh root\@$opts{'nim_master'} \"$cmd $args\"\' in $ssh_work_dir\n"); if ($tar_cmd) { my $mv_cmd = $cmds[1]; # print "$tar_cmd\n"; # print "$mv_cmd\n"; invoke("$tar_cmd | ssh root\@$opts{'nim_master'} \"export LIBPATH=$opts{'nimae_dir'}; mkdir -p $ssh_work_dir; cd $ssh_work_dir; cat | tar -xf -; $mv_cmd export PERL5LIB=$opts{'nimae_dir'}; $input_str $cmd $args\""); } else { invoke("ssh root\@$opts{'nim_master'} \"export LIBPATH=$opts{'nimae_dir'}; mkdir -p $ssh_work_dir; cd $ssh_work_dir; export PERL5LIB=$opts{'nimae_dir'}; $input_str $cmd $args\""); } $rc = 1; } } return $rc; } #------------------------------------------------------------------------------- sub parse_ae_xml { my ($xml_file) = @_; my %rc = (); $rc{'xml_file'} = $xml_file; $rc{'parser'} = new XML::LibXML(); $rc{'doc'} = eval { $rc{'parser'}->parse_file($xml_file); }; $rc{'doc'} || die "can not open the file: $xml_file"; $rc{'fn'} = basename($xml_file); $rc{'dn'} = dirname($xml_file); $rc{'is_ovf'} = ($rc{'fn'} =~ /\.ovf$/); # debug - display info if (0) { while (my ($k, $v) = each(%rc)) { if ($k eq 'is_ovf') { $v = ($v ? '1' : '0'); } print "$k => $v\n"; } } return \%rc; } #------------------------------------------------------------------------------- sub get_ae_properties { my ($ae_xml, $query, $exact_match) = @_; my @rc = (); $exact_match = ($exact_match ? '1' : '0'); log_print("get_ae_properties($ae_xml->{'xml_file'}, $query, $exact_match)\n"); my $is_ovf = $ae_xml->{'is_ovf'}; my $doc = $ae_xml->{'doc'}; my $rootElement = $doc->getDocumentElement(); if ($is_ovf) { $rootElement->setNamespace($ns_uri, 'default_ns', 1); $rootElement->setNamespace($ns_uri, 'ovfenv_ns', 1); } log_printf("\troot element = %s, uri = %s\n", $rootElement->nodeName(), $rootElement->namespaceURI()); for (my $nextNode = $rootElement->firstChild(); $nextNode; $nextNode = $nextNode->nextSibling()) { log_printf("\tchild element = %s, uri =%s, type = %s, content = %s\n", $nextNode->nodeName(), $nextNode->namespaceURI(), $nextNode->nodeType(), $nextNode->textContent()); } if ($is_ovf) { log_print("\tprocessing ovf properties\n"); # xpath = //PropertySection/Property[@ovfenv:key='ConfigWAS.password'][@ovfenv:value] my $xpath_expression = "//default_ns:PropertySection/default_ns:Property[\@ovfenv_ns:key][\@ovfenv_ns:value]"; my @nodes = $rootElement->findnodes($xpath_expression); # log_printf("\tchecking %d nodes\n", $#nodes + 1); foreach my $node (@nodes) { # my $node_name = $node->nodeName(); # log_print("\tchecking node $node_name\n"); my $attr_node = $node->getAttributeNodeNS($ns_uri, 'key'); if ($attr_node) { my $attr_value = $attr_node->getValue(); my $match = 0; # log_print "ovfenv:key = $attr_value\n"; if ($exact_match) { if ($attr_value eq $query) { $match = 1; } } elsif ($attr_value =~ $query) { $match = 1; } if ($match) { # log_print "++ ovfenv:key = $attr_value\n"; push @rc, ($attr_value); } } } } else { # xpath = //configuration[@name='ConfigWAS']/parameter[@name='password'][@value] if ($exact_match) { my $last_dot = rindex($query, '.'); my $config_name = substr($query, 0, $last_dot); my $property_name = substr($query, $last_dot + 1); my $xpath_expression = "//configuration[\@name=\'$config_name\']/parameter[\@name=\'$property_name\'][\@value]"; my @nodes = $rootElement->findnodes($xpath_expression); if ($#nodes >= 0) { push @rc, ("${config_name}.${property_name}"); } } else { my $xpath_expression = "//configuration[\@name]/parameter[\@name][\@value]"; my @nodes = $rootElement->findnodes($xpath_expression); foreach my $node (@nodes) { my $parent = $node->parentNode; my $cname = $parent->getAttribute('name'); my $pname = $node->getAttribute('name'); my $name = "$cname.$pname"; # print "$name =~ $query\n"; if ($name =~ $query) { push @rc, ($name); } } } } foreach my $property (@rc) { log_print("\t$property\n"); } return \@rc; } #------------------------------------------------------------------------------- sub set_ae_config { my ($properties, $value, $rc) = @_; if (! defined $rc) { $rc = {}; } foreach my $property (@$properties) { $rc->{$property} = $value; } return $rc; } #------------------------------------------------------------------------------- sub customize_ae { my ($ae_dir, $ae_xml, $ae_cmd, $config) = @_; my @rc = ('', ''); log_print("customize_ae($ae_dir, $ae_xml->{'xml_file'}, $ae_cmd)\n"); if ($ae_dir) { if ($opts{'work_dir'}) { if (-e "$opts{'work_dir'}/$$/AE") { `rm -r $opts{'work_dir'}/$$/AE`; } else { `mkdir -p $opts{'work_dir'}/$$/AE`; } } log_print("\twork dir = $opts{'work_dir'}/$$/AE\n"); `cp -pr ${ae_dir}/* $opts{'work_dir'}/$$/AE`; if (-e "$opts{'work_dir'}/$$/AE/AP") { `rm $opts{'work_dir'}/$$/AE/AP/*`; } if (-e "$opts{'work_dir'}/$$/AE/AR") { `rm $opts{'work_dir'}/$$/AE/AR/*`; } else { `mkdir -p $opts{'work_dir'}/$$/AE/AR`; } my $is_ovf = $ae_xml->{'is_ovf'}; my $doc = $ae_xml->{'doc'}; my $fn = $ae_xml->{'fn'}; my $rootElement = $doc->getDocumentElement(); if ($is_ovf) { $rootElement->setNamespace($ns_uri, 'default_ns', 1); $rootElement->setNamespace($ns_uri, 'ovfenv_ns', 1); } while (my ($key, $value) = each(%$config)) { if ($key && $value) { # log_print("\t$key\n"); if ($is_ovf) { # need to modify ovf environment instead of ovf envelope xml file # xpath = //PropertySection/Property[@ovfenv:key='ConfigWAS.password'][@ovfenv:value] my $xpath_expression = "//default_ns:PropertySection/default_ns:Property[\@ovfenv_ns:key=\'$key\'][\@ovfenv_ns:value]"; my @nodes = $rootElement->findnodes($xpath_expression); foreach my $node (@nodes) { my $attr_val_node = $node->getAttributeNodeNS($ns_uri, 'value'); $attr_val_node->setValue($value); my $node_name = $node->nodeName(); log_print("\tsetting $node_name $key=$value\n"); } } else { # xpath = //configuration[@name='ConfigWAS']/parameter[@name='password'][@value] my $last_dot = rindex($key, '.'); my $config_name = substr($key, 0, $last_dot); my $property_name = substr($key, $last_dot + 1); log_print("\t$key\n"); if ($config_name && $property_name) { my $xpath_expression = "//configuration[\@name=\'$config_name\']/parameter[\@name=\'$property_name\'][\@value]"; my @nodes = $rootElement->findnodes($xpath_expression); foreach my $node (@nodes) { my $node_name = $node->nodeName(); log_print("\tsetting $node_name $key=$value\n"); $node->setAttribute('value', $value); } } } } } `mkdir -p $opts{'work_dir'}/$$/AE/AP`; if ($is_ovf) { $doc->toFile("$opts{'work_dir'}/$$/AE/AP/ovf-env.xml", 1); } else { $doc->toFile("$opts{'work_dir'}/$$/AE/AP/$fn", 1); } @rc = ("$opts{'work_dir'}/$$/AE", "$opts{'work_dir'}/$$/AE/AP/$fn"); } return @rc; } #------------------------------------------------------------------------------- sub rand_passwd { my $rc = ''; my $minimum = ord('a'); my $range = ord('z') - $minimum; for (my $i = 0; $i < 8; $i++) { my $random_number = int(rand($range)) + $minimum; $rc = $rc . chr($random_number); } # print $rc . "\n"; return $rc; } #------------------------------------------------------------------------------- sub deploy_mksysb { my ($lpar, $mksysb, $ae_dir, $ae_cmd, $config, $work_dir, $remote_work_dir) = @_; log_print("deploy_mksysb($lpar->{'nim_machine_name'}, $mksysb->{'name'}, $ae_dir, $ae_cmd, $work_dir, $remote_work_dir)\n"); my $rc = 0; my $start_time = time(); if ($mksysb->is_deployable() == 1) { my $dir = getcwd(); # set root password to random value to disable login with original password from the image # since the activation engine runs after tcpip starts up my $password = rand_passwd(); log_print("\ttemporary password: $password\n"); # need to create fb_script nim resource and return name as $rc chdir "$work_dir/$$/AE"; invoke("tar -chf ../AE.tar *"); chdir '..'; # NIM::Deploy::Mksysb::create_fb_script_resource() needs to be changed if perl commands used instead of ksh my $cmd_ary_ref = undef; if (0) { # perl commands $cmd_ary_ref = [ "mkpath(\'$remote_work_dir\')", "chdir \'$remote_work_dir\'", '`tar -xvf AE.tar`', '`rm AE.tar`', '$ENV{\'LIBPATH\'} = \'.\'', '`./setup`', "`echo \"root:$password\" | chpasswd`", # "`sh ${remote_work_dir}/ae -a ${remote_work_dir}/AL/wasv7.al`" "`$ae_cmd`" ]; } else { # ksh commands $cmd_ary_ref = [ "mkdir -p $remote_work_dir", "cd $remote_work_dir", 'tar -xvf AE.tar', 'rm AE.tar', 'export LIBPATH=.', './setup', "echo \"root:$password\" | chpasswd", "$ae_cmd" ]; } # use to switch between using fb_script or script resource my $use_fb_script = 1; my $fb_script_name = (($use_fb_script == 1) ? $mksysb->create_fb_script_resource($cmd_ary_ref, 'AE.tar', 1) : ''); my $script_name = (($use_fb_script == 0) ? $mksysb->create_script_resource($cmd_ary_ref, 'AE.tar', 1) : ''); if ($fb_script_name) { $lpar->add_to_res_group($fb_script_name, 'fb_script'); } if ($script_name) { $lpar->add_to_res_group($script_name, 'script'); } my $resolv_conf_name = $mksysb->create_resolv_conf_resource($lpar->{'domain'}, $lpar->get_nameservers()); $lpar->add_to_res_group($resolv_conf_name, 'resolv_conf'); # extract ./image.data file from the mksysb and size to disk my $image_data_name = $mksysb->create_image_data_resource($lpar->{'disk_size'}, $lpar->{'paging_space_size'}); $lpar->add_to_res_group($image_data_name, 'image_data'); my $thr = undef; if ($mksysb->resolve_machine_netboot_kernel($lpar->{'nim_machine_name'})) # if ($mksysb->machine_spot_check($lpar->{'nim_machine_name'})) { $mksysb->deploy_to_machine($lpar->{'nim_machine_name'}, $script_name, $fb_script_name, $resolv_conf_name, $image_data_name); # some hmc lpar_netboot have a bug which command blocks till the entire bosinst operation is complete # lpar_netboot should exit after the network bootp but before the install # use threads to account for blocking behavior if (0) { $lpar->netboot(); } else { log_print("Starting netboot thread\n"); $thr = threads->create(sub { my ($lpar) = @_; $lpar->netboot(); }, $lpar); } # print status $rc = $lpar->print_deploy_status(); } my $comment = q { # getting a SIGWARN "PmmREFCNT_dec: REFCNT decremented below 0!" if the following code # is enabled. if ($thr) { log_print("Waiting for netboot thread to complete\n"); $thr->join(); log_print("Netboot thread completed\n"); } }; if ($fb_script_name) { $mksysb->delete_fb_script_resource($fb_script_name); } if ($script_name) { $mksysb->delete_script_resource($script_name); } $mksysb->delete_resolv_conf_resource($resolv_conf_name); $mksysb->delete_image_data_resource($image_data_name); chdir $dir; } my $elapse_time = time() - $start_time; my $mins = $elapse_time /= 60; $mins =~ s/\..*//; my $secs = $elapse_time % 60; print "Elapsed time = $mins minutes + $secs seconds\n"; return $rc; } # __END__ =head1 AUTHOR IBM =head1 BUGS Please report any bugs to the L. =head1 SUPPORT =head1 ACKNOWLEDGEMENTS =head1 SEE ALSO =begin html =end html =cut #------------------------------------------------------------------------------- my $comment = q { nimae -o install_nimae -source_dir . -nim_master ipv4-072 -nimae_dir /tmp/nimae rm /var/ibm/systemp/logs/pAutomation.log; rm -r /var/ibm/systemp/nim/[1-9]*; export LIBPATH=.; ./nimae -o deploy_image -image db2-91_5300-07master_sysb -lpar ipv4-073 -config password=mypw };