From 38c614f84ec789ea7da5ed259e6b0522cba9df17 Mon Sep 17 00:00:00 2001 From: zhanx Date: Thu, 2 Apr 2009 15:37:19 +0000 Subject: [PATCH] mkvm enhancement: 1. support cross hmc; 2. support hca guid automatic increase. This code change doesn't include man page/usage update. Will do them soon. git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@3069 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd --- perl-xCAT/xCAT/PPCvm.pm | 411 ++++++++++++++++++------------- xCAT-server/lib/perl/xCAT/PPC.pm | 61 +++++ 2 files changed, 295 insertions(+), 177 deletions(-) diff --git a/perl-xCAT/xCAT/PPCvm.pm b/perl-xCAT/xCAT/PPCvm.pm index 3bd6d78c6..34d8765f9 100644 --- a/perl-xCAT/xCAT/PPCvm.pm +++ b/perl-xCAT/xCAT/PPCvm.pm @@ -120,87 +120,155 @@ sub chvm_parse_args { sub mkvm_parse_args { my $request = shift; + +#return directly for PPC::process_request + if ( $request->{opt}) + { + $request->{method} = $request->{command}; + return $request->{opt}; + } + my %opt = (); - my $cmd = $request->{command}; + my $cmd = $request->{command}->[0]; my $args = $request->{arg}; - ############################################# - # Responds with usage statement - ############################################# +############################################# +# Responds with usage statement +############################################# local *usage = sub { my $usage_string = xCAT::Usage->getUsage($cmd); return( [ $_[0], $usage_string] ); }; - ############################################# - # Process command-line arguments - ############################################# +############################################# +# Process command-line arguments +############################################# if ( !defined( $args )) { return(usage( "No command specified" )); } - ############################################# - # Only 1 node allowed - ############################################# - if ( scalar( @{$request->{node}} ) > 1) { - return(usage( "multiple nodes specified" )); - } - ############################################# - # Checks case in GetOptions, allows opts - # to be grouped (e.g. -vx), and terminates - # at the first unrecognized option. - ############################################# +############################################# +# Checks case in GetOptions, allows opts +# to be grouped (e.g. -vx), and terminates +# at the first unrecognized option. +############################################# @ARGV = @$args; $Getopt::Long::ignorecase = 0; Getopt::Long::Configure( "bundling" ); - if ( !GetOptions( \%opt, qw(V|verbose i=s n=s c=s) )) { + if ( !GetOptions( \%opt, qw(V|verbose i=s l=s c=s p=s) )) { return( usage() ); } - #################################### - # Check for "-" with no option - #################################### +#################################### +# Check for "-" with no option +#################################### if ( grep(/^-$/, @ARGV )) { return(usage( "Missing option: -" )); } - #################################### - # Check for non-zero integer - #################################### +#################################### +# Check for non-zero integer +#################################### if ( exists( $opt{i} )) { if ( $opt{i} !~ /^([1-9]{1}|[1-9]{1}[0-9]+)$/ ) { return(usage( "Invalid entry: $opt{i}" )); } } - #################################### - # -i and -n not valid with -c - #################################### +#################################### +# -i and -l not valid with -c +#################################### if ( exists( $opt{c} ) ) { - if ( exists($opt{i}) or exists($opt{n})) { + if ( exists($opt{i}) or exists($opt{l})) { + return( usage() ); + } +#################################### +# -p is required for -c +#################################### + if ( !exists($opt{p})) { return( usage() ); } } - #################################### - # If -i and -n, both required - #################################### - elsif ( !exists($opt{n}) or !exists($opt{i})) { +#################################### +# If -i and -l, both required +#################################### + elsif ( !exists($opt{l}) or !exists($opt{i})) { return( usage() ); } - #################################### - # Check for an extra argument - #################################### +#################################### +# Check for an extra argument +#################################### if ( defined( $ARGV[0] )) { return(usage( "Invalid Argument: $ARGV[0]" )); } - #################################### - # Expand -n noderange - #################################### - if ( exists( $opt{n} )) { - my @noderange = xCAT::NodeRange::noderange( $opt{n},0 ); +#################################### +# Expand -l noderange +#################################### + if ( exists( $opt{l} )) { + my @noderange = xCAT::NodeRange::noderange( $opt{l},0 ); if ( !@noderange ) { - return(usage( "Invalid noderange: '$opt{n}'" )); + return(usage( "Invalid noderange: '$opt{l}'" )); } - $opt{n} = \@noderange; + $opt{lpar} = \@noderange; } - #################################### +#################################### +# Expand -c noderange +#################################### + if ( exists( $opt{c} )) { + my @noderange = xCAT::NodeRange::noderange( $opt{c},0 ); + if ( !@noderange ) { + return(usage( "Invalid noderange: '$opt{l}'" )); + } + $opt{cec} = \@noderange; + } + +################################################# +# Swap the targets to be processed in PPC.pm +################################################# + $opt{target} = [@{$request->{node}}]; + if ( $opt{l}) + { + $request->{node} = [@{$opt{lpar}}]; + $request->{noderange} = $opt{l}; + } + + if ( $opt{c}) + { + $request->{node} = [@{$opt{cec}}]; + $request->{noderange} = $opt{c}; + } + +############################################# +# Only 1 node allowed +############################################# + if ( scalar( @{$request->{node}} ) > 1) { + return(usage( "Multiple source specified" )); + } + +#################################### +# Read and check profile +#################################### + if ( exists( $opt{p})) { + $opt{p} = $request->{cwd}->[0] . $opt{p} if ( $opt{p} !~ /^\//); + return ( usage( "Profile $opt{p} cannot be found")) if ( ! -f $opt{p}); + open (PROFFILE, "<$opt{p}") or return ( usage( "Cannot open profile $opt{p}")); + my @cfgdata = (); + while( ) + { + chomp; + /\w+/ or next; + if ( /name=/ and /lpar_name/ and /lpar_id/ and /lpar_env/) + { + push @cfgdata, $_; + } + else + { + s/^[^,]*:\s*(name=.*)$/$1/; + return ( usage( "Invalid line in profile: $_")); + } + } + return ( usage( "No valid line was found in profile $opt{p}.")) if ( scalar( @cfgdata) < 1); + $opt{profile} = \@cfgdata; + } + +#################################### # No operands - add command name #################################### $request->{method} = $cmd; @@ -326,165 +394,95 @@ sub lsvm_parse_args { # Clones all the LPARs from one CEC to another (must be on same HMC) ########################################################################## sub clone { - + my $request = shift; my $exp = shift; - my $src = shift; - my $dest = shift; - my $srcd = shift; + my $targets = shift; + my $profile = shift; + my $destd = shift; + my $destname= shift; my $hwtype = @$exp[2]; my $server = @$exp[3]; my @values = (); - my @lpars = (); - my $srccec; + my @lpars = @$targets; my $destcec; - my @cfgdata; - - ##################################### - # Always one source CEC specified - ##################################### - my $lparid = @$srcd[0]; - my $mtms = @$srcd[2]; - my $type = @$srcd[4]; - ##################################### - # Not supported on IVM - ##################################### +##################################### +# Always one source CEC specified +##################################### + my $lparid = @$destd[0]; + my $mtms = @$destd[2]; + my $type = @$destd[4]; + +##################################### +# Not supported on IVM +##################################### if ( $hwtype eq "ivm" ) { return( [[RC_ERROR,"Not supported for IVM"]] ); } - ##################################### - # Source must be CEC - ##################################### +##################################### +# Source must be CEC +##################################### if ( $type ne "fsp" ) { return( [[RC_ERROR,"Node must be an FSP"]] ); } - ##################################### - # Find Destination CEC - ##################################### - my $tab = xCAT::Table->new( "vpd" ); - - ##################################### - # Error opening vpd database - ##################################### - if ( !defined( $tab )) { - return( [[RC_ERROR, "Error opening 'vpd' database"]] ); +##################################### +# Attributes not found +##################################### + if ( !$mtms) { + return( [[RC_ERROR,"Cannot found serial and mtm for $destname"]] ); } - my ($ent) = $tab->getNodeAttribs($dest, [qw(mtm serial)]); - ##################################### - # Node not found - ##################################### - if ( !defined( $ent )) { - return( [[RC_ERROR,"Destination '$dest' not in 'vpd' database"]] ); - } - ##################################### - # Attributes not found - ##################################### - if ( !exists( $ent->{mtm} ) or !exists( $ent->{serial} )) { - return( [[RC_ERROR,"Attributes not in 'vpd' database"]] ); - } - my $destmtms = "$ent->{mtm}*$ent->{serial}"; - - ##################################### - # Enumerate CECs - ##################################### +##################################### +# Enumerate CECs +##################################### my $filter = "type_model,serial_num"; my $cecs = xCAT::PPCcli::lssyscfg( $exp, "fsps", $filter ); my $Rc = shift(@$cecs); - ##################################### - # Return error - ##################################### +##################################### +# Return error +##################################### if ( $Rc != SUCCESS ) { return( [[$Rc, @$cecs[0]]] ); } - ##################################### - # Find source/dest CEC - ##################################### +##################################### +# Find source/dest CEC +##################################### foreach ( @$cecs ) { s/(.*),(.*)/$1*$2/; if ( $_ eq $mtms ) { - $srccec = $_; - } elsif ( $_ eq $destmtms ) { - $destcec = $destmtms; + $destcec = $_; } } - ##################################### - # Source CEC not found - ##################################### - if ( !defined( $srccec )) { - return( [[RC_ERROR,"Source CEC '$src' not found"]] ); - } - ##################################### - # Destination CEC not found - ##################################### +##################################### +# Destination CEC not found +##################################### if ( !defined( $destcec )) { - return([[RC_ERROR,"Destination CEC '$dest' not found on '$server'"]]); + return([[RC_ERROR,"Destination CEC '$destname' not found on '$server'"]]); } - ##################################### - # Get all LPARs on source CEC - ##################################### - $filter = "name,lpar_id"; - my $result = xCAT::PPCcli::lssyscfg( - $exp, - "lpar", - $srccec, - $filter ); - $Rc = shift(@$result); - - ##################################### - # Return error - ##################################### - if ( $Rc != SUCCESS ) { - return( [[$Rc, @$result[0]]] ); - } - ##################################### - # Get profile for each LPAR - ##################################### - foreach ( @$result ) { - my ($name,$id) = split /,/; - - ################################# - # Get source LPAR profile - ################################# - my $prof = xCAT::PPCcli::lssyscfg( - $exp, - "prof", - $srccec, - "lpar_ids=$id" ); - - $Rc = shift(@$prof); - - ################################# - # Return error - ################################# - if ( $Rc != SUCCESS ) { - return( [[$Rc, @$prof[0]]] ); - } - ################################# - # Save LPAR profile - ################################# - push @cfgdata, @$prof[0]; - } - ##################################### - # Modify read back profile - ##################################### - foreach my $cfg ( @cfgdata ) { +##################################### +# Modify read back profile +##################################### + my $min_lpar_num = scalar(@$profile) < scalar(@$targets) ? scalar(@$profile) : scalar(@$targets) ; + my $i; + for ($i = 0; $i < $min_lpar_num; $i++) + { + my $cfg = $profile->[$i]; + $cfg =~ s/^[^,]*:\s*(name=.*)$/$1/; $cfg =~ s/^name=([^,]+|$)/profile_name=$1/; my $profile = $1; - $cfg =~ s/\blpar_name=([^,]+|$)/name=$1/; - my $name = $1; + $cfg =~ s/\blpar_name=([^,]+|$)/name=$targets->[$i]/; $cfg = strip_profile( $cfg, $hwtype); $cfg =~ /lpar_id=([^,]+)/; $lparid = $1; - - ################################# - # Create new LPAR - ################################# - my @temp = @$srcd; + +################################# +# Create new LPAR +################################# + my @temp = @$destd; $temp[0] = $lparid; $temp[2] = $destcec; $temp[4] = 'lpar'; @@ -492,22 +490,21 @@ sub clone { my $result = xCAT::PPCcli::mksyscfg( $exp, "lpar", \@temp, $cfg ); $Rc = shift(@$result); - ################################# - # Success - add LPAR to database - ################################# +################################# +# Success - add LPAR to database +################################# if ( $Rc == SUCCESS ) { - my $newname = $dest."_".$name; my $err = xCATdB( - "mkvm", $newname, $profile, $lparid, $srcd, $hwtype, $name, $dest ); + "mkvm", $targets->[$i], $profile, $lparid, $destd, $hwtype, $targets->[$i], $destname ); if ( defined( $err )) { push @values, [$err, RC_ERROR]; } next; } - ################################# - # Error - Save error - ################################# +################################# +# Error - Save error +################################# push @values, [@$result[0], $Rc]; } if ( !scalar(@values) ) { @@ -1046,6 +1043,52 @@ sub list { return( \@values ); } +sub hca_adapter { + + my $cfgdata = shift; + +######################################### +# Increment HCA adapters if present +# "23001eff/2550010250300/2,23001eff/2550010250400/2" +# Increment the last 2 number of 2550010250300 and +# 2550010250400 in example above. +######################################### + if ( $cfgdata =~ /(\"*hca_adapters)/ ) { + +##################################### +# If double-quoted, has comma- +# seperated list of adapters +##################################### + my $delim = ( $1 =~ /^\"/ ) ? "\\\\\"" : ","; + $cfgdata =~ /hca_adapters=([^$delim]+)|$/; + my @hcas = split ",", $1; + my $adapters = "hca_adapters="; + for my $hca ( @hcas) + { + my @hcainfo = split /\//, $hca; + ###################################################### + # split it to 2 part, only increase the last 2 number + # otherwise it can overflow if change it to dec + ###################################################### + my $portlen = length( $hcainfo[1]); + my $portprefix = substr($hcainfo[1],0,$portlen-2); + my $portpostfix = substr($hcainfo[1],$portlen-2); + my $portnum = hex $portpostfix; + $portnum++; + $portpostfix = sprintf '%x', $portnum; + if ( length( $portpostfix) == 1) + { + $portpostfix = '0' . $portpostfix; + } + $hcainfo[1] = $portprefix . $portpostfix; + + $adapters = $adapters . join( "/", @hcainfo ) . ','; + } + $adapters =~ s/^(.*),$/$1/; + $cfgdata =~ s/hca_adapters=[^$delim]+/$adapters/; + } + return( $cfgdata ); +} ########################################################################## @@ -1161,7 +1204,13 @@ sub create { # Clone all the LPARs on CEC ##################################### if ( exists( $opt->{c} )) { - my $result = clone( $exp, $lpar, $opt->{c}, $d ); + my $result = clone( $request, + $exp, + $opt->{target}, + $opt->{profile}, + $d, + $request->{node}->[0] + ); foreach ( @$result ) { my $Rc = shift(@$_); push @values, [$opt->{c}, @$_[0], $Rc]; @@ -1211,7 +1260,7 @@ sub create { $cfgdata =~ s/lpar_name=/name=/; } - foreach my $name ( @{$opt->{n}} ) { + foreach my $name ( @{$opt->{target}} ) { ################################# # Modify read-back profile. @@ -1231,6 +1280,14 @@ sub create { } } ################################# + # Modify HCA adapters + ################################# + if ( $cfgdata =~ /hca_adapters=(\w+)/ ) { + if ( $1 !~ /^none$/i ) { + $cfgdata = hca_adapter( $cfgdata ); + } + } + ################################# # Modify SCSI adapters ################################# if ( $cfgdata =~ /virtual_scsi_adapters=(\w+)/ ) { diff --git a/xCAT-server/lib/perl/xCAT/PPC.pm b/xCAT-server/lib/perl/xCAT/PPC.pm index e2d192362..4085ab6ba 100644 --- a/xCAT-server/lib/perl/xCAT/PPC.pm +++ b/xCAT-server/lib/perl/xCAT/PPC.pm @@ -1012,6 +1012,19 @@ sub preprocess_request { my $callback = shift; my @requests; + ##################################### + # Special cases for mkvm + ##################################### + if ( $req->{command}->[0] eq 'mkvm') + { + $req = mkvm_prepare ( $req); + if ( ref($req) eq 'ARRAY')#Something wrong + { + $callback->({data=>$req}); + $req = {}; + return; + } + } #################################### # Get hwtype #################################### @@ -1116,6 +1129,51 @@ sub preprocess_request { return \@requests; } +#################################### +# Special case for mkvm +#################################### +sub mkvm_prepare +{ + my $req = shift; + + # Following code could be changed more flexibly, as we did in PPC::runcmd + # But since we only mkvm need to be handled in this specific way, keep the code simple + ###################################### + # Load specific module + ###################################### + eval "require xCAT::PPCvm"; + if ( $@ ) { + return( $@ ); + } + + my $opt = xCAT::PPCvm::mkvm_parse_args( $req); + if ( ref($opt) eq 'ARRAY') + { + return $opt; + } + $req->{opt} = $opt; + + ######################################################## + #Check lpar number in command line and profile + ######################################################## + if ( exists $opt->{c}) + { + my @profile = @{$opt->{profile}}; + my @lpars = @{$opt->{target}}; + my $min_lpar_num = scalar( @profile); + if ( scalar(@profile) > scalar( @lpars)) + { + xCAT::MsgUtils->message('W', "Warning: Lpar configuration number in profile is greater than lpars in command line. Only first " . scalar(@lpars) . " lpars will be created.\n"); + $min_lpar_num = scalar( @lpars); + } + elsif ( scalar(@profile) < scalar( @lpars)) + { + xCAT::MsgUtils->message('W', "Warning: Lpar number in command line is greater than lpar configuration number in profile. Only lpars " . join ",", @lpars[0..$min_lpar_num-1] . " will be created.\n"); + } + } + + return $req; +} sub preprocess_for_rflash { my $req = shift; my $callback = shift; @@ -1229,6 +1287,9 @@ sub process_request { $request{callback} = $callback; $request{method} = "parse_args"; + #For mkvm only so far + $request{opt} = $req->{opt} if (exists $req->{opt}); + #################################### # Process command-specific options ####################################