#!/usr/bin/env perl # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html # ##################################################### # cfm2xcat: # # This routine will read in cfmupdatenode distribution files # and build the files need to input to xdcp rsync function # in xCAT. # # cfm2xcat will run cfmupdatenode -a, it sets the environment # variable CSM_CFM_SAVE_DISTFILE to the file path input with the -i option # to save the built cfm distribution file(s). # These are normally deleted after cfm runs. # # cfm2xcat will then take the files that were created from calling # cfmupdatenode and create xCAT xdcp files synch files and store them in the # path input with the -o flag. # # Example: # cfm2xcat -i <...cfmsave> -o < path to output file> # cfm2xcat -i /tmp/cfmsave -o /tmp/xcat/xcatdistfile # # The routine will process all the /.../cfmsave* files and when finished, # you will have the new files xcatdistfile* and noderange* generated which # will be the correct format to input to the xdcp -F command in xCAT to run # the equivalent syncing of files that you were running on CSM. # # Take the files in the /tmp/xcat/* directory from the example above and # place on your xCAT Management Node. Then run for each file combination: # xdcp ^/tmp/xcat/noderange1 -F /tmp/xcat/xcatdistfile1 # More information is in the manpage for cfm2xcat and xdcp ##################################################### use strict; use warnings; use Getopt::Long; use Data::Dumper; my $help; my $input; my $output; my $rc = 0; if ( !GetOptions( 'h|help' => \$help, 'i|input=s' => \$input, 'o|output=s' => \$output, ) ) { &usage; exit 1; } if ($help) { &usage; exit 0; } if (!($input)) { print "Input file path must be supplied with the -i flag.\n"; exit 1; } if (!($output)) { print "Output file path and name must be supplied with the -o flag.\n"; exit 1; } # call cfmupdatenode and build cfm distribution files &buildcfmdistfiles($input); if (-e ($input)) # if anything built { # build the xcat sync files $rc = &buildxcatrsyncfiles($input, $output); if ($rc == 0) { print "Conversion finished, please carefully review $output files! Make sure that all the files list to sync to the nodes are relevant and available on the xCAT system in the directory indicated. \n"; } else { print " Error converting cfm file to xdcp files.\n"; } } else { print " Error building CFM dist files, or nothing to do.\n"; } exit 0; # end main # # # Builds the CFM distribution files from the cfmupdatenode -a call # sub buildcfmdistfiles { my ($cfmfile) = @_; my $cmd; my @output; # remove old files , if they exist my $tmpcfmfile = $cfmfile; if (-e ($tmpcfmfile)) { $tmpcfmfile .= "*"; $cmd = "rm $tmpcfmfile"; @output = runcmd($cmd); if ($::RUNCMD_RC != 0) { print " Error running $cmd.\n"; return 1; } } # export the CSM_CFM_SAVE_DISTFILE variable to the input (-i) # path, makes cfmupdatenode save the dist file(s) from the run in a # file by that name $cmd = "CSM_CFM_SAVE_DISTFILE=$cfmfile cfmupdatenode -a"; # run the cfmupdate command @output = runcmd($cmd); if ($::RUNCMD_RC != 0) { print " Error running $cmd.\n"; return 1; } else { return 0; } } # # # Builds the xdcp sync files from the CFM dist files # sub buildxcatrsyncfiles { my ($CFMfiles, $xcatfile) = @_; my $cmd; my @output; my %noderangequeue; # remove old files, if they exist my $tmpxcatfile = $xcatfile; if (-e ($tmpxcatfile)) { $tmpxcatfile .= "*"; $cmd = "rm $tmpxcatfile"; @output = runcmd($cmd); if ($::RUNCMD_RC != 0) { print " Error running $cmd.\n"; return 1; } } # get list of CFM files that were built $cmd = "ls $CFMfiles"; $cmd .= "*"; my @CFMfilelist = runcmd($cmd); if ($::RUNCMD_RC != 0) { print " Error running $cmd.\n"; return 1; } my $msg = "Building xCat rsync files $xcatfile from $CFMfiles\n"; print "$msg"; # For each CFM output file, open the CFM input file to read foreach my $cfmfile (@CFMfilelist) { open(CFM, "< $cfmfile") or die "Can't open $cfmfile for reading: $!"; # # convert the CFM rdist format to the xdcp format for rsync # build a hash of noderange -> to distribution files # while (my $line = ) { chomp $line; if ($line =~ /^#/) # skip commments { next; } if ($line =~ /.runclocal/) # skip sending runclocal { next; } my ($sourcefile, $rest) = split("->", $line); my ($tmpnodes, $destfile) = split("install", $rest); # get rid of parenthesis my ($paren, $tnodes) = split(/\(/, $tmpnodes); my ($nodes, $paren2) = split(/\)/, $tnodes); chomp $nodes; # strip off /cfmroot and /var/opt/csm/cfmlocal paths my ($root, $strippedsourcefile) = split("cfmroot", $sourcefile); chomp $strippedsourcefile; my ($root2, $strippeddestfile) = split("cfmlocal", $destfile); chomp $strippeddestfile; chop $strippeddestfile; $noderangequeue{$nodes}{'files'}{$strippedsourcefile} = $strippeddestfile; } close(CFM); } # # now take the hash and build the xdcp file(s), key is the noderange # (use short hostname) # one for each noderange and a matching noderange file # for example xdcpfile1 xdcpfile1.noderange # my $index; foreach (keys %noderangequeue) { my $noderange = $_; # open the xCAT output files to write my $newxcatfilenr = $xcatfile; $newxcatfilenr .= ".nr"; # file to hold the noderange if ($index) { # processing more than one noderange then building # more than one xdcp file $newxcatfilenr .= "$index"; } open(XCATNR, "> $newxcatfilenr") or die "Can't open $newxcatfilenr for writing: $!"; # create an appropriate noderange ( comma seperated) my @nodes = split(/ /, $noderange); my $goodnr = ""; foreach my $node (@nodes) { if ($node !~ /^\s*$/) { #skip blanks my @shorthost = split(/\./, $node); $goodnr .= $shorthost[0]; $goodnr .= ","; } } chop $goodnr; # write into the noderange file write_line_nr($goodnr); write_line_nr("\n"); # file to hold the rsync interface file to file list my $newxcatfile = $xcatfile; # file to hold the noderange if ($index) { # processing more than one noderange then building # more than one xdcp file $newxcatfile .= "$index"; } open(XCAT, "> $newxcatfile") or die "Can't open $newxcatfile for writing: $!"; my $srcfile; my $destfile; foreach my $sourcefile (keys %{$noderangequeue{$noderange}{'files'}}) { $srcfile = $sourcefile; $destfile = $noderangequeue{$noderange}{'files'}{$sourcefile}; write_line($srcfile); write_line("-> "); write_line($destfile); write_line("\n"); } close(XCAT); close(XCATNR); $index++; } return 0; } # # runs the input command and handles the errors. Returns the output # sub runcmd { my ($cmd) = @_; my $rc = 0; $::RUNCMD_RC = 0; my $outref = []; @$outref = `$cmd`; if ($?) { $rc = $?; $::RUNCMD_RC = $rc; if ($rc > 0) { my $msg = "$cmd returned rc=$rc @$outref\n"; print "$msg"; } } chomp(@$outref); return @$outref; } sub usage { print "CFM distribution file to xCAT xdcp rsync migration facility.\n"; print "Usage:\n"; print "\t-h - usage\n"; print "\t-i - Complete path to the CFM file(s) saved to be converted for xCAT."; print " Be sure directory exists.\n"; print "\t-o - Complete Path to the xCAT xdcp rsync input file(s) created from."; print " the CFM file. Be sure directory exists.\n"; print " Example: cfm2xcat -i /tmp/migration/cfmfiles -o /tmp/migration/xdcpfiles."; print "\n"; return; } # # write to xCAT rsync files # sub write_line { print XCAT @_; } # # write to xCAT rsync noderange files # sub write_line_nr { print XCATNR @_; }