mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-11-04 13:22:36 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			966 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			966 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
# IBM(c) 2013 EPL license http://www.eclipse.org/legal/epl-v10.html
 | 
						|
package xCAT_plugin::openstack;
 | 
						|
BEGIN
 | 
						|
{
 | 
						|
    $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
 | 
						|
}
 | 
						|
use lib "$::XCATROOT/lib/perl";
 | 
						|
use xCAT::Utils;
 | 
						|
use xCAT::TableUtils;
 | 
						|
use xCAT::SvrUtils;
 | 
						|
use xCAT::NetworkUtils;
 | 
						|
use xCAT::Table;
 | 
						|
use Data::Dumper;
 | 
						|
use File::Path;
 | 
						|
use File::Copy;
 | 
						|
use Getopt::Long;
 | 
						|
Getopt::Long::Configure("bundling");
 | 
						|
Getopt::Long::Configure("pass_through");
 | 
						|
 | 
						|
 | 
						|
sub handled_commands {
 | 
						|
    return {
 | 
						|
		opsaddbmnode => "openstack",  #external command
 | 
						|
		opsaddimage => "openstack",   #external command
 | 
						|
		deploy_ops_bm_node => "openstack",   #internal command called from the baremetal driver
 | 
						|
		cleanup_ops_bm_node => "openstack",  #internal command called from the baremetal driver
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
sub process_request {
 | 
						|
	my $request = shift;
 | 
						|
	my $callback = shift;
 | 
						|
	my $doreq = shift;
 | 
						|
	my $command = $request->{command}->[0];
 | 
						|
	
 | 
						|
	if ($command eq "opsaddbmnode") {
 | 
						|
		return opsaddbmnode($request, $callback, $doreq);
 | 
						|
	} elsif ($command eq "opsaddimage") {
 | 
						|
		return opsaddimage($request, $callback, $doreq);
 | 
						|
	} elsif ($command eq "deploy_ops_bm_node") {
 | 
						|
		return deploy_ops_bm_node($request, $callback, $doreq);
 | 
						|
	} elsif ($command eq "cleanup_ops_bm_node") {
 | 
						|
		return cleanup_ops_bm_node($request, $callback, $doreq);
 | 
						|
	} else {
 | 
						|
		$callback->({error=>["Unsupported command: $command."],errorcode=>[1]});
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3  opsaddbmnode
 | 
						|
     This function takes the xCAT nodes and register them
 | 
						|
     as the OpenStack baremetal nodes
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
sub opsaddbmnode {
 | 
						|
	my $request = shift;
 | 
						|
	my $callback = shift;
 | 
						|
	my $doreq = shift;
 | 
						|
	
 | 
						|
	@ARGV = @{$request->{arg}};
 | 
						|
	Getopt::Long::Configure("bundling");
 | 
						|
	Getopt::Long::Configure("no_pass_through");
 | 
						|
	
 | 
						|
	my $help;
 | 
						|
	my $version;
 | 
						|
	my $verbose;
 | 
						|
	my $host;
 | 
						|
	
 | 
						|
    if(!GetOptions(
 | 
						|
            'h|help'      => \$help,
 | 
						|
            'v|version'   => \$version,
 | 
						|
            'V|verbose'   => \$verbose,
 | 
						|
            's=s'         => \$host,
 | 
						|
       ))
 | 
						|
    {
 | 
						|
        &opsaddbmnode_usage($callback);
 | 
						|
        return 1;
 | 
						|
    }
 | 
						|
    # display the usage if -h or --help is specified
 | 
						|
    if ($help) {
 | 
						|
        &opsaddbmnode_usage($callback);
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
    # display the version statement if -v or --verison is specified
 | 
						|
    if ($version)
 | 
						|
    {
 | 
						|
        my $rsp={};
 | 
						|
        $rsp->{data}->[0]= xCAT::Utils->Version();
 | 
						|
        $callback->($rsp);
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
	
 | 
						|
	if (!$request->{node}) {
 | 
						|
		$callback->({error=>["Please specify at least one node."],errorcode=>[1]});
 | 
						|
		return 1;  
 | 
						|
	}
 | 
						|
	if (!$host) {
 | 
						|
		$callback->({error=>["Please specify the OpenStack compute host name with -s flag."],errorcode=>[1]});
 | 
						|
		return 1;  
 | 
						|
	}
 | 
						|
    
 | 
						|
    my $nodes = $request->{node};
 | 
						|
 | 
						|
    #get node mgt
 | 
						|
    my $nodehmhash;
 | 
						|
    my $nodehmtab = xCAT::Table->new("nodehm");
 | 
						|
    if ($nodehmtab) {
 | 
						|
        $nodehmhash = $nodehmtab->getNodesAttribs($nodes,['power', 'mgt']);
 | 
						|
    }
 | 
						|
 | 
						|
    #get bmc info for the nodes
 | 
						|
	my $ipmitab = xCAT::Table->new("ipmi", -create => 0);
 | 
						|
	my $tmp_ipmi;
 | 
						|
	if ($ipmitab) {
 | 
						|
		$tmp_ipmi = $ipmitab->getNodesAttribs($nodes, ['bmc','username', 'password'], prefetchcache=>1);
 | 
						|
		#print Dumper($tmp_ipmi);
 | 
						|
	} else {
 | 
						|
		$callback->({error=>["Cannot open the ipmi table."],errorcode=>[1]});
 | 
						|
		return 1;		
 | 
						|
	}
 | 
						|
 | 
						|
    #get mac for the nodes
 | 
						|
	my $mactab = xCAT::Table->new("mac", -create => 0);
 | 
						|
	my $tmp_mac;
 | 
						|
	if ($mactab) {
 | 
						|
		$tmp_mac = $mactab->getNodesAttribs($nodes, ['mac'], prefetchcache=>1);
 | 
						|
		#print Dumper($tmp_mac);
 | 
						|
	} else {
 | 
						|
		$callback->({error=>["Cannot open the mac table."],errorcode=>[1]});
 | 
						|
		return 1;		
 | 
						|
	}
 | 
						|
 | 
						|
    #get cpu, memory and disk info for the nodes
 | 
						|
	my $hwinvtab = xCAT::Table->new("hwinv", -create => 0);
 | 
						|
	my $tmp_hwinv;
 | 
						|
	if ($hwinvtab) {
 | 
						|
		$tmp_hwinv = $hwinvtab->getNodesAttribs($nodes, ['cpucount', 'memory', 'disksize'], prefetchcache=>1);
 | 
						|
		#print Dumper($tmp_hwinv);
 | 
						|
	} else {
 | 
						|
		$callback->({error=>["Cannot open the hwinv table."],errorcode=>[1]});
 | 
						|
		return 1;		
 | 
						|
	}
 | 
						|
 | 
						|
    #get default username and password for bmc
 | 
						|
    my $d_bmcuser;
 | 
						|
    my $d_bmcpasswd;
 | 
						|
	my $passtab = xCAT::Table->new('passwd');
 | 
						|
	if ($passtab) {
 | 
						|
		($tmp_passwd)=$passtab->getAttribs({'key'=>'ipmi'},'username','password');
 | 
						|
		if (defined($tmp_passwd)) {
 | 
						|
			$d_bmcuser = $tmp_passwd->{username};
 | 
						|
			$d_bmcpasswd = $tmp_passwd->{password};
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	#print "d_bmcuser=$d_bmcuser, d_bmcpasswd=$d_bmcpasswd \n";
 | 
						|
	foreach my $node (@$nodes) {
 | 
						|
        #collect the node infomation needed for each node, some info
 | 
						|
		my $mgt;
 | 
						|
		my $ref_nodehm = $nodehmhash->{$node}->[0];
 | 
						|
		if ($ref_nodehm) {
 | 
						|
			if ($ref_nodehm->{'power'}) {
 | 
						|
				$mgt = $ref_nodehm->{'power'};
 | 
						|
			} elsif ($ref_nodehm->{'mgt'}) {
 | 
						|
				$mgt = $ref_nodehm->{'mgt'};
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		my ($bmc, $bmc_user, $bmc_password, $mac, $cpu, $memory, $disk);
 | 
						|
		if (($mgt) && ($mgt eq 'ipmi')) { 
 | 
						|
			my $ref_ipmi = $tmp_ipmi->{$node}->[0]; 
 | 
						|
			if ($ref_ipmi) {
 | 
						|
				if (exists($ref_ipmi->{bmc})) {
 | 
						|
					$bmc = $ref_ipmi->{bmc};
 | 
						|
				}
 | 
						|
				if (exists($ref_ipmi->{username})) {
 | 
						|
					$bmc_user = $ref_ipmi->{username};
 | 
						|
					if (exists($ref_ipmi->{password})) {
 | 
						|
						$bmc_password = $ref_ipmi->{password};
 | 
						|
					} 
 | 
						|
				} else { #take the default if they cannot be found on ipmi table
 | 
						|
					if ($d_bmcuser) { $bmc_user = $d_bmcuser; }
 | 
						|
					if ($d_bmcpasswd) { $bmc_password = $d_bmcpasswd; }
 | 
						|
				}
 | 
						|
			}
 | 
						|
		} # else { # for hardware control point other than ipmi, just fake it in OpenStack.
 | 
						|
			#$bmc = "0.0.0.0";
 | 
						|
			#$bmc_user = "xCAT";
 | 
						|
			#$bmc_password = "xCAT";
 | 
						|
		#}
 | 
						|
 | 
						|
		my $ref_mac = $tmp_mac->{$node}->[0]; 
 | 
						|
	    if ($ref_mac) {
 | 
						|
			if (exists($ref_mac->{mac})) {
 | 
						|
				$mac = $ref_mac->{mac};
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		$ref_hwinv = $tmp_hwinv->{$node}->[0]; 
 | 
						|
	    if ($ref_hwinv) {
 | 
						|
			if (exists($ref_hwinv->{cpucount})) {
 | 
						|
				$cpu = $ref_hwinv->{cpucount};
 | 
						|
			}
 | 
						|
			if (exists($ref_hwinv->{memory})) {
 | 
						|
				$memory = $ref_hwinv->{memory};
 | 
						|
                #TODO: what if the unit is not in MB? We need to convert it to MB
 | 
						|
				$memory =~ s/MB|mb//g;
 | 
						|
			}
 | 
						|
			if (exists($ref_hwinv->{disksize})) {
 | 
						|
				#The format of the the disk size is: sda:250GB,sdb:250GB or just 250GB
 | 
						|
                #We need to get the size of the first one
 | 
						|
				$disk = $ref_hwinv->{disksize};
 | 
						|
				my @a = split(',', $disk);
 | 
						|
				my @b = split(':', $a[0]);
 | 
						|
				if (@b > 1) {
 | 
						|
					$disk = $b[1];
 | 
						|
				} else {
 | 
						|
					$disk = $b[0];
 | 
						|
				}
 | 
						|
                #print "a=@a, b=@b\n";
 | 
						|
                #TODO: what if the unit is not in GB? We need to convert it to MB
 | 
						|
				$disk =~ s/GB|gb//g;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		#some info are mendatory
 | 
						|
        if (!$mac) {
 | 
						|
			$callback->({error=>["Mac address is not defined in the mac table for node $node."],errorcode=>[1]});
 | 
						|
			next;
 | 
						|
		}
 | 
						|
		if (!$cpu) {
 | 
						|
			#default cpu count is 1
 | 
						|
			$cpu = 1;
 | 
						|
		}
 | 
						|
		if (!$memory) {
 | 
						|
			#default memory size is 1024MB=1GB
 | 
						|
			$memory = 1024;
 | 
						|
		}
 | 
						|
		if (!$disk) {
 | 
						|
			#default disk size is 1GB
 | 
						|
			$disk = 1;
 | 
						|
		}				
 | 
						|
		
 | 
						|
		if ($verbose) {
 | 
						|
			my $rsp;
 | 
						|
			push @{$rsp->{data}}, "Attributes gathered from the xCAT database:";
 | 
						|
			push @{$rsp->{data}}, "  bmc=$bmc";
 | 
						|
			push @{$rsp->{data}}, "  bmc_user=$bmc_user";
 | 
						|
			push @{$rsp->{data}}, "  bmc_password=$bmc_password";
 | 
						|
			push @{$rsp->{data}}, "  mac=$mac";
 | 
						|
			push @{$rsp->{data}}, "  cpu=$cpu";
 | 
						|
			push @{$rsp->{data}}, "  memory=$memory";
 | 
						|
			push @{$rsp->{data}}, "  disk=$disk";
 | 
						|
			xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
		}
 | 
						|
 | 
						|
		#call OpenStack command to add the node into the OpenStack as
 | 
						|
        #a baremetal node.
 | 
						|
        my $cmd_tmp = "nova baremetal-node-create";
 | 
						|
		if ($bmc) {
 | 
						|
			#make sure it is an ip address
 | 
						|
			if (($bmc !~ /\d+\.\d+\.\d+\.\d+/) && ($bmc !~ /:/)) {
 | 
						|
				$bmc =  xCAT::NetworkUtils->getipaddr($bmc);
 | 
						|
			}
 | 
						|
			$cmd_tmp .= " --pm_address=$bmc";			
 | 
						|
		}
 | 
						|
		if ($bmc_user) {
 | 
						|
			$cmd_tmp .= " --pm_user=$bmc_user";
 | 
						|
		}
 | 
						|
		if ($bmc_password) {
 | 
						|
			$cmd_tmp .= " --pm_password=$bmc_password";
 | 
						|
		}
 | 
						|
		$cmd_tmp .= " $host $cpu $memory $disk $mac";
 | 
						|
 
 | 
						|
		my $cmd = qq~$cmd_tmp~;
 | 
						|
		if ($verbose) {
 | 
						|
			my $rsp;
 | 
						|
			push @{$rsp->{data}}, "The command to run on $host:";
 | 
						|
			push @{$rsp->{data}}, "  $cmd";
 | 
						|
			push @{$rsp->{data}}, "  ";
 | 
						|
			xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
		}
 | 
						|
		#print "cmd=$cmd\n";
 | 
						|
		my $output =
 | 
						|
			xCAT::InstUtils->xcmd($callback, $doreq, "xdsh", [$host], $cmd, 0);
 | 
						|
		if ($::RUNCMD_RC != 0) {
 | 
						|
			my $rsp;
 | 
						|
			push @{$rsp->{data}}, "OpenStack creating baremetal node $node:";
 | 
						|
			push @{$rsp->{data}}, "$output";
 | 
						|
			push @{$rsp->{data}}, "The command was: $cmd";
 | 
						|
			xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
		} else {
 | 
						|
			if (($verbose) && ($output)) {
 | 
						|
				my $rsp;
 | 
						|
				push @{$rsp->{data}}, "$output";
 | 
						|
				push @{$rsp->{data}}, "  ";
 | 
						|
				xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3  opsaddimage
 | 
						|
     This function takes the xCAT nodes and register them
 | 
						|
     as the OpenStack baremetal nodes
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
sub opsaddimage {
 | 
						|
	my $request = shift;
 | 
						|
	my $callback = shift;
 | 
						|
	my $doreq = shift;
 | 
						|
	
 | 
						|
	@ARGV = @{$request->{arg}};
 | 
						|
	Getopt::Long::Configure("bundling");
 | 
						|
	Getopt::Long::Configure("no_pass_through");
 | 
						|
	
 | 
						|
	my $help;
 | 
						|
	my $version;
 | 
						|
	my $verbose;
 | 
						|
	#my $cloud;
 | 
						|
	my $ops_img_names;
 | 
						|
    my $controller;
 | 
						|
	
 | 
						|
    if(!GetOptions(
 | 
						|
            'h|help'      => \$help,
 | 
						|
            'v|version'   => \$version,
 | 
						|
            'V|verbose'   => \$verbose,
 | 
						|
            'c=s'         => \$controller,
 | 
						|
			'n=s'         => \$ops_img_names,
 | 
						|
       ))
 | 
						|
    {
 | 
						|
        &opsaddimage_usage($callback);
 | 
						|
        return 1;
 | 
						|
    }
 | 
						|
    # display the usage if -h or --help is specified
 | 
						|
    if ($help) {
 | 
						|
        &opsaddimage_usage($callback);
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
    # display the version statement if -v or --verison is specified
 | 
						|
    if ($version)
 | 
						|
    {
 | 
						|
        my $rsp={};
 | 
						|
        $rsp->{data}->[0]= xCAT::Utils->Version();
 | 
						|
        $callback->($rsp);
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
	
 | 
						|
	if (@ARGV ==0) {
 | 
						|
		$callback->({error=>["Please specify an image name or a list of image names."],errorcode=>[1]});
 | 
						|
		return 1;  
 | 
						|
	}
 | 
						|
 | 
						|
	#make sure the input cloud name is valid.
 | 
						|
	#if (!$cloud) {
 | 
						|
	#	$callback->({error=>["Please specify the name of the cloud with -c flag."],errorcode=>[1]});
 | 
						|
	#	return 1;  
 | 
						|
	#} else {
 | 
						|
	#	my $cloudstab = xCAT::Table->new('clouds', -create => 0);
 | 
						|
	#	my @et = $cloudstab->getAllAttribs('name', 'controller');
 | 
						|
	#	if(@et) {
 | 
						|
	#		foreach my $tmp_et (@et) {
 | 
						|
	#			if ($tmp_et->{name} eq $cloud) {
 | 
						|
	#				if ($tmp_et->{controller}) {
 | 
						|
	#					$controller = $tmp_et->{controller};
 | 
						|
	#					last;
 | 
						|
	#				} else {
 | 
						|
	#					$callback->({error=>["Please specify the controller in the clouds table for the cloud: $cloud."],errorcode=>[1]});
 | 
						|
	#					return 1;  	
 | 
						|
	#				}
 | 
						|
	#			}
 | 
						|
	#		}
 | 
						|
	#	}
 | 
						|
	
 | 
						|
	if (!$controller) {
 | 
						|
		$callback->({error=>["Please specify the OpenStack controller node name with -c."],errorcode=>[1]});
 | 
						|
		return 1;  			
 | 
						|
	}
 | 
						|
	#}
 | 
						|
 | 
						|
	#make sure that the images from the command are valid image names
 | 
						|
    @images = split(',', $ARGV[0]);
 | 
						|
    @new_names = ();
 | 
						|
	if ($ops_img_names) {
 | 
						|
		@new_names = split(',', $ops_img_names);
 | 
						|
	}
 | 
						|
	#print "images=@images, new image names=@new_names, controller=$controller\n";
 | 
						|
 | 
						|
	my $image_hash = {};
 | 
						|
    my $osimgtab = xCAT::Table->new('osimage', -create => 0);
 | 
						|
    my @et = $osimgtab->getAllAttribs('imagename');
 | 
						|
	if(@et) {
 | 
						|
		foreach my $tmp_et (@et) {
 | 
						|
			$image_hash->{$tmp_et->{imagename}}{'xCAT'} = 1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	my @bad_images;
 | 
						|
	foreach my $image (@images) {
 | 
						|
		if (!exists($image_hash->{$image})) {
 | 
						|
			push @bad_images, $image;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (@bad_images > 0) {
 | 
						|
		$callback->({error=>["The following images cannot be found in xCAT osimage table:\n  " . join("\n  ", @bad_images) . "\n"],errorcode=>[1]});
 | 
						|
		return 1;  
 | 
						|
	}
 | 
						|
 | 
						|
	my $index=0;
 | 
						|
 	foreach my $image (@images) {
 | 
						|
		my $new_name = shift(@new_names);
 | 
						|
		if (!$new_name) {
 | 
						|
			$new_name = $image; #the default new name is xCAT image name
 | 
						|
		}
 | 
						|
        my $cmd_tmp = "glance image-create --name $new_name --public --disk-format qcow2 --container-format bare --property xcat_image_name=\'$image\' < /tmp/$image.qcow2";
 | 
						|
 | 
						|
		my $cmd = qq~touch /tmp/$image.qcow2;$cmd_tmp~;
 | 
						|
		if ($verbose) {
 | 
						|
			my $rsp;
 | 
						|
			push @{$rsp->{data}}, "The command to run on $controller:";
 | 
						|
			push @{$rsp->{data}}, "   $cmd";
 | 
						|
			push @{$rsp->{data}}, "  ";
 | 
						|
			xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
		}
 | 
						|
		my $output =
 | 
						|
			xCAT::InstUtils->xcmd($callback, $doreq, "xdsh", [$controller], $cmd, 0);
 | 
						|
		if ($::RUNCMD_RC != 0) {
 | 
						|
			my $rsp;
 | 
						|
			push @{$rsp->{data}}, "OpenStack creating image $new_name:";
 | 
						|
			push @{$rsp->{data}}, "$output";
 | 
						|
			push @{$rsp->{data}}, "The command was: $cmd";
 | 
						|
			xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
		} else {
 | 
						|
			if (($verbose) && ($output)) {
 | 
						|
				my $rsp;
 | 
						|
				push @{$rsp->{data}}, "$output";
 | 
						|
				push @{$rsp->{data}}, "  ";
 | 
						|
				xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
			}
 | 
						|
		}		 
 | 
						|
		my $cmd1 = qq~rm /tmp/$image.qcow2~;
 | 
						|
		if ($verbose) {
 | 
						|
			my $rsp;
 | 
						|
			push @{$rsp->{data}}, "The command to run on $controller:";
 | 
						|
			push @{$rsp->{data}}, "  $cmd1";
 | 
						|
			push @{$rsp->{data}}, "  ";
 | 
						|
			xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
		}
 | 
						|
		my $output1 =
 | 
						|
			xCAT::InstUtils->xcmd($callback, $doreq, "xdsh", [$controller], $cmd1, 0);
 | 
						|
		if (($verbose) && ($output1)) {
 | 
						|
			my $rsp;
 | 
						|
			push @{$rsp->{data}}, "$output1";
 | 
						|
			push @{$rsp->{data}}, "  ";
 | 
						|
			xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3  deploy_ops_bm_node
 | 
						|
	This is a internel command called by OpenStack xCAT-baremetal driver. 
 | 
						|
	It prepares the node by adding the config_ops_bm_node postbootscript 
 | 
						|
	to the postscript table for the node, then call nodeset and then boot 
 | 
						|
	the node up.
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
sub deploy_ops_bm_node {
 | 
						|
	my $request = shift;
 | 
						|
	my $callback = shift;
 | 
						|
	my $doreq = shift;
 | 
						|
	
 | 
						|
	@ARGV = @{$request->{arg}};
 | 
						|
	Getopt::Long::Configure("bundling");
 | 
						|
	Getopt::Long::Configure("no_pass_through");
 | 
						|
 | 
						|
	my $node = $request->{node}->[0];
 | 
						|
	
 | 
						|
	my $help;
 | 
						|
	my $version;
 | 
						|
	my $img_name;
 | 
						|
    my $hostname;
 | 
						|
	my $fixed_ip;
 | 
						|
	my $netmask;
 | 
						|
	
 | 
						|
    if(!GetOptions(
 | 
						|
            'h|help'      => \$help,
 | 
						|
            'v|version'   => \$version,
 | 
						|
            'image=s'     => \$img_name,
 | 
						|
			'host=s'      => \$hostname,
 | 
						|
			'ip=s'        => \$fixed_ip,
 | 
						|
			'mask=s'      => \$netmask,
 | 
						|
       ))
 | 
						|
    {
 | 
						|
        &deploy_ops_bm_node_usage($callback);
 | 
						|
        return 1;
 | 
						|
    }
 | 
						|
    # display the usage if -h or --help is specified
 | 
						|
    if ($help) {
 | 
						|
        &deploy_ops_bm_node_usage($callback);
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
    # display the version statement if -v or --verison is specified
 | 
						|
    if ($version)
 | 
						|
    {
 | 
						|
        my $rsp={};
 | 
						|
        $rsp->{data}->[0]= xCAT::Utils->Version();
 | 
						|
        $callback->($rsp);
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
	#print "node=$node, image=$img_name, host=$hostname, ip=$fixed_ip, mask=$netmask\n";
 | 
						|
 | 
						|
	#validate the image name
 | 
						|
    my $osimagetab = xCAT::Table->new('osimage', -create=>1);
 | 
						|
	my $ref = $osimagetab->getAttribs({imagename => $img_name}, 'imagename');
 | 
						|
	if (!$ref) {
 | 
						|
		$callback->({error=>["Invalid image name: $img_name."],errorcode=>[1]});
 | 
						|
		return 1;  
 | 
						|
	}
 | 
						|
 | 
						|
	#check if the fixed ip is within the xCAT management network.
 | 
						|
	#get the master ip address for the node then check if the master ip and 
 | 
						|
	#the OpenStack fixed_ip are on the same subnet.
 | 
						|
	#my $same_nw = 0;
 | 
						|
	#my $master = xCAT::TableUtils->GetMasterNodeName($node);
 | 
						|
	#my $master_ip = xCAT::NetworkUtils->toIP($master);
 | 
						|
	#if (xCAT::NetworkUtils::isInSameSubnet($master_ip, $fixed_ip, $netmask, 0)) {
 | 
						|
	#	$same_nw = 1;
 | 
						|
	#}
 | 
						|
	   
 | 
						|
	
 | 
						|
	#add config_ops_bm_node to the node's postbootscript
 | 
						|
	my $script = "config_ops_bm_node $hostname $fixed_ip $netmask";
 | 
						|
	add_postscript($callback, $node, $script);
 | 
						|
 | 
						|
    #run nodeset 
 | 
						|
	my $cmd = qq~osimage=$img_name~;
 | 
						|
	my $output = xCAT::Utils->runxcmd(
 | 
						|
		{command => ["nodeset"],
 | 
						|
		 node    => [$node], 
 | 
						|
		 arg     => [$cmd]},
 | 
						|
		$doreq, -1, 1);
 | 
						|
	if ($::RUNCMD_RC != 0) {
 | 
						|
		my $rsp;
 | 
						|
		push @{$rsp->{data}}, "nodeset:";
 | 
						|
		push @{$rsp->{data}}, "$output";
 | 
						|
		xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
		return 1;
 | 
						|
	}		
 | 
						|
 
 | 
						|
    #deploy the node now, supported nodehm.mgt values: ipmi, blade,fsp, hmc.
 | 
						|
    my $hmtab  = xCAT::Table->new('nodehm');
 | 
						|
	my $hment = $hmtab->getNodeAttribs($node,['mgt']);
 | 
						|
	if ($hment && $hment->{'mgt'}) {
 | 
						|
		my $mgt = $hment->{'mgt'};
 | 
						|
		if ($mgt eq 'ipmi') { 
 | 
						|
			deploy_bmc_node($callback, $doreq, $node);
 | 
						|
		} elsif (($mgt eq 'blade') || ($mgt eq 'fsp')) {
 | 
						|
			deploy_blade($callback, $doreq, $node);
 | 
						|
		} elsif ($mgt eq 'hmc') {
 | 
						|
			deploy_hmc_node($callback, $doreq, $node);
 | 
						|
		} else {
 | 
						|
			my $rsp;
 | 
						|
			push @{$rsp->{data}}, "Node $node: nodehm.mgt=$mgt is not supported in the OpenStack cloud.";
 | 
						|
			xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
			return 1;
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		#nodehm.mgt must setup for node 
 | 
						|
		my $rsp;
 | 
						|
		push @{$rsp->{data}}, "Node $node: nodehm.mgt cannot be empty in order to deploy.";
 | 
						|
		xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
# Deploy a rack-mounted node
 | 
						|
sub deploy_bmc_node {
 | 
						|
	my $callback = shift;
 | 
						|
	my $doreq = shift;
 | 
						|
	my $node = shift;
 | 
						|
 | 
						|
    #set boot order
 | 
						|
	my $cmd = qq~net~;
 | 
						|
	my $output = xCAT::Utils->runxcmd(
 | 
						|
		{command => ["rsetboot"],
 | 
						|
		 node    => [$node], 
 | 
						|
		 arg     => [$cmd]},
 | 
						|
		$doreq, -1, 1);
 | 
						|
	if ($::RUNCMD_RC != 0) {
 | 
						|
		my $rsp;
 | 
						|
		push @{$rsp->{data}}, "rsetboot:";
 | 
						|
		push @{$rsp->{data}}, "$output";
 | 
						|
		xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
	}		
 | 
						|
	
 | 
						|
    #reboot the node
 | 
						|
	my $cmd = qq~boot~;
 | 
						|
	my $output = xCAT::Utils->runxcmd(
 | 
						|
		{command => ["rpower"],
 | 
						|
		 node    => [$node], 
 | 
						|
		 arg     => [$cmd]},
 | 
						|
		$doreq, -1, 1);
 | 
						|
	if ($::RUNCMD_RC != 0) {
 | 
						|
		my $rsp;
 | 
						|
		push @{$rsp->{data}}, "rpower:";
 | 
						|
		push @{$rsp->{data}}, "$output";
 | 
						|
		xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
# Deploy a blade or fsp controlled node
 | 
						|
sub deploy_blade {
 | 
						|
	my $callback = shift;
 | 
						|
	my $doreq = shift;
 | 
						|
	my $node = shift;
 | 
						|
 | 
						|
    #set boot order
 | 
						|
	my $cmd = qq~net~;
 | 
						|
	my $output = xCAT::Utils->runxcmd(
 | 
						|
		{command => ["rbootseq"],
 | 
						|
		 node    => [$node], 
 | 
						|
		 arg     => [$cmd]},
 | 
						|
		$doreq, -1, 1);
 | 
						|
	if ($::RUNCMD_RC != 0) {
 | 
						|
		my $rsp;
 | 
						|
		push @{$rsp->{data}}, "rbootseq:";
 | 
						|
		push @{$rsp->{data}}, "$output";
 | 
						|
		xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
	}		
 | 
						|
	
 | 
						|
    #reboot the node
 | 
						|
	my $cmd = qq~boot~;
 | 
						|
	my $output = xCAT::Utils->runxcmd(
 | 
						|
		{command => ["rpower"],
 | 
						|
		 node    => [$node], 
 | 
						|
		 arg     => [$cmd]},
 | 
						|
		$doreq, -1, 1);
 | 
						|
	if ($::RUNCMD_RC != 0) {
 | 
						|
		my $rsp;
 | 
						|
		push @{$rsp->{data}}, "rpower:";
 | 
						|
		push @{$rsp->{data}}, "$output";
 | 
						|
		xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
		return 1;
 | 
						|
	}	
 | 
						|
}
 | 
						|
 | 
						|
# Deploy a node controlled by HMC
 | 
						|
sub deploy_hmc_node {
 | 
						|
	my $callback = shift;
 | 
						|
	my $doreq = shift;
 | 
						|
	my $node = shift;
 | 
						|
 | 
						|
	my $output = xCAT::Utils->runxcmd(
 | 
						|
		{command => ["rnetboot"],
 | 
						|
		 node    => [$node]},
 | 
						|
		$doreq, -1, 1);
 | 
						|
	if ($::RUNCMD_RC != 0) {
 | 
						|
		my $rsp;
 | 
						|
		push @{$rsp->{data}}, "rnetboot:";
 | 
						|
		push @{$rsp->{data}}, "$output";
 | 
						|
		xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
		return 1;
 | 
						|
	}	
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3  cleanup_ops_bm_node
 | 
						|
	This is a internel command called by OpenStack xCAT-baremetal driver.
 | 
						|
	It undoes all the changes made by deploy_ops_bm_node command. It removes
 | 
						|
	the config_ops_bmn_ode postbootscript from the postscript table for the 
 | 
						|
	node, removes the alias ip and then power off the node.
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
sub cleanup_ops_bm_node {
 | 
						|
	my $request = shift;
 | 
						|
	my $callback = shift;
 | 
						|
	my $doreq = shift;
 | 
						|
	
 | 
						|
	@ARGV = @{$request->{arg}};
 | 
						|
	Getopt::Long::Configure("bundling");
 | 
						|
	Getopt::Long::Configure("no_pass_through");
 | 
						|
 | 
						|
	my $node = $request->{node}->[0];
 | 
						|
	
 | 
						|
	my $help;
 | 
						|
	my $version;
 | 
						|
 	my $fixed_ip;
 | 
						|
	
 | 
						|
    if(!GetOptions(
 | 
						|
            'h|help'      => \$help,
 | 
						|
            'v|version'   => \$version,
 | 
						|
			'ip=s'        => \$fixed_ip,
 | 
						|
       ))
 | 
						|
    {
 | 
						|
        &cleanup_ops_bm_node_usage($callback);
 | 
						|
        return 1;
 | 
						|
    }
 | 
						|
    # display the usage if -h or --help is specified
 | 
						|
    if ($help) {
 | 
						|
        &cleanup_ops_bm_node_usage($callback);
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
    # display the version statement if -v or --verison is specified
 | 
						|
    if ($version)
 | 
						|
    {
 | 
						|
        my $rsp={};
 | 
						|
        $rsp->{data}->[0]= xCAT::Utils->Version();
 | 
						|
        $callback->($rsp);
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
	#print "node=$node, ip=$fixed_ip\n";   
 | 
						|
	
 | 
						|
	#removes the config_ops_bm_node postbootscript from the postscripts table
 | 
						|
	remove_postscript($callback, $node, "config_ops_bm_node");
 | 
						|
 | 
						|
 | 
						|
	#run updatenode to remove the ip alias 
 | 
						|
	my $cmd = qq~-P deconfig_ops_bm_node $fixed_ip~;
 | 
						|
	my $output = xCAT::Utils->runxcmd(
 | 
						|
		{command => ["updatenode"],
 | 
						|
		 node    => [$node], 
 | 
						|
		 arg     => [$cmd]},
 | 
						|
		$doreq, -1, 1);
 | 
						|
	if ($::RUNCMD_RC != 0) {
 | 
						|
		my $rsp;
 | 
						|
		push @{$rsp->{data}}, "updatenode:";
 | 
						|
		push @{$rsp->{data}}, "$output";
 | 
						|
		xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
	}
 | 
						|
		
 | 
						|
    #turn the node power off
 | 
						|
	$ssh_ok = 0;
 | 
						|
	my $cmd = qq~stat~;
 | 
						|
	my $output = xCAT::Utils->runxcmd(
 | 
						|
		{command => ["rpower"],
 | 
						|
		 node    => [$node], 
 | 
						|
		 arg     => [$cmd]},
 | 
						|
		$doreq, -1, 1);
 | 
						|
 | 
						|
	if ($::RUNCMD_RC != 0) {
 | 
						|
		my $rsp;
 | 
						|
		push @{$rsp->{data}}, "rpower:";
 | 
						|
		push @{$rsp->{data}}, "$output";
 | 
						|
		xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
		return 1;
 | 
						|
	}   else {
 | 
						|
		if ($output !~ /: off/) {
 | 
						|
			#power off the node
 | 
						|
			my $cmd = qq~off~;
 | 
						|
			my $output = xCAT::Utils->runxcmd(
 | 
						|
				{command => ["rpower"],
 | 
						|
				 node    => [$node], 
 | 
						|
				 arg     => [$cmd]},
 | 
						|
				$doreq, -1, 1);
 | 
						|
			if ($::RUNCMD_RC != 0) {
 | 
						|
				my $rsp;
 | 
						|
				push @{$rsp->{data}}, "rpower:";
 | 
						|
				push @{$rsp->{data}}, "$output";
 | 
						|
				xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
				return 1;
 | 
						|
			}		
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
=head3  add_postscript
 | 
						|
 | 
						|
	It adds the 'config_ops_bm_node' postbootscript to the 
 | 
						|
	postscript table for the given node.
 | 
						|
 | 
						|
=cut
 | 
						|
#-------------------------------------------------------
 | 
						|
sub  add_postscript {
 | 
						|
    my $callback=shift;
 | 
						|
    my $node=shift;
 | 
						|
	my $script=shift;
 | 
						|
	#print "script=$script\n";
 | 
						|
 | 
						|
    my $posttab=xCAT::Table->new("postscripts", -create =>1);
 | 
						|
	my %setup_hash;
 | 
						|
	my $ref = $posttab->getNodeAttribs($node,[qw(postscripts postbootscripts)]);
 | 
						|
	my $found=0;
 | 
						|
	if ($ref) {
 | 
						|
		if (exists($ref->{postscripts})) {
 | 
						|
		    my @a = split(/,/, $ref->{postscripts});
 | 
						|
		    if (grep(/^config_ops_bm_node/, @a)) {
 | 
						|
				$found = 1;
 | 
						|
				if (!grep(/^$script$/, @a)) {
 | 
						|
					#not exact match, must replace it with the new script
 | 
						|
					for (@a) {
 | 
						|
						s/^config_ops_bm_node.*$/$script/;
 | 
						|
					}
 | 
						|
					my $new_post = join(',', @a);
 | 
						|
					$setup_hash{$node}={postscripts=>"$new_post"};
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		
 | 
						|
 | 
						|
		if (exists($ref->{postbootscripts})) {
 | 
						|
		    my $post=$ref->{postbootscripts};
 | 
						|
		    my @old_a=split(',', $post);
 | 
						|
		    if (grep(/^config_ops_bm_node/, @old_a)) {
 | 
						|
				if (!grep(/^$script$/, @old_a)) {
 | 
						|
					#not exact match, will replace it with new script
 | 
						|
					for (@old_a) {
 | 
						|
						s/^config_ops_bm_node.*$/$script/;
 | 
						|
					}
 | 
						|
					my $new_postboot = join(',', @old_a);
 | 
						|
					$setup_hash{$node}={postbootscripts=>"$new_postboot"};
 | 
						|
				}
 | 
						|
		    } else {
 | 
						|
				if (! $found) {
 | 
						|
					$setup_hash{$node}={postbootscripts=>"$post,$script"};
 | 
						|
				}
 | 
						|
		    }
 | 
						|
		} else {
 | 
						|
            if (! $found) {
 | 
						|
				$setup_hash{$node}={postbootscripts=>"$script"};
 | 
						|
			}
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		$setup_hash{$node}={postbootscripts=>"$script"};
 | 
						|
	}
 | 
						|
 | 
						|
	if (keys(%setup_hash) > 0) {
 | 
						|
	    $posttab->setNodesAttribs(\%setup_hash);
 | 
						|
	}
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
=head3  remove_postscript
 | 
						|
 | 
						|
	It removes the 'config_ops_bm_node' postbootscript from 
 | 
						|
	the postscript table for the given node.
 | 
						|
 | 
						|
=cut
 | 
						|
#-------------------------------------------------------
 | 
						|
sub  remove_postscript {
 | 
						|
    my $callback=shift;
 | 
						|
    my $node=shift;
 | 
						|
	my $script=shift;
 | 
						|
 | 
						|
    my $posttab=xCAT::Table->new("postscripts", -create =>1);
 | 
						|
	my %setup_hash;
 | 
						|
	my $ref = $posttab->getNodeAttribs($node,[qw(postscripts postbootscripts)]);
 | 
						|
	my $found=0;
 | 
						|
	if ($ref) {
 | 
						|
		if (exists($ref->{postscripts})) {
 | 
						|
		    my @old_a = split(/,/, $ref->{postscripts});
 | 
						|
		    my @new_a = grep(!/^$script/, @old_a);
 | 
						|
			if (scalar(@new_a) != scalar(@old_a)) {
 | 
						|
				my $new_post = join(',', @new_a);
 | 
						|
				$setup_hash{$node}={postscripts=>"$new_post"};
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (exists($ref->{postbootscripts})) {
 | 
						|
		    my @old_b = split(/,/, $ref->{postbootscripts});
 | 
						|
		    my @new_b = grep(!/^$script/, @old_b);
 | 
						|
			if (scalar(@new_b) != scalar(@old_b)) {
 | 
						|
				my $new_post = join(',', @new_b);
 | 
						|
				$setup_hash{$node}={postbootscripts=>"$new_post"};
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
	}
 | 
						|
	
 | 
						|
	if (keys(%setup_hash) > 0) {
 | 
						|
	    $posttab->setNodesAttribs(\%setup_hash);
 | 
						|
	}
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3  opsaddbmnode_usage
 | 
						|
	The usage text for opsaddbmnode command.
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
sub opsaddbmnode_usage {
 | 
						|
    my $cb=shift;
 | 
						|
    my $rsp={};
 | 
						|
 | 
						|
    $rsp->{data}->[0]= "Usage: opsaddbmnode -h";
 | 
						|
    $rsp->{data}->[1]= "       opsaddbmnode -v";
 | 
						|
    $rsp->{data}->[2]= "       opsaddbmnode <noderange> -s <service_host> [-V]";
 | 
						|
    $cb->($rsp);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3  opsaddimage_usage
 | 
						|
	The usage text for opsaddimage command.
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
sub opsaddimage_usage {
 | 
						|
    my $cb=shift;
 | 
						|
    my $rsp={};
 | 
						|
 | 
						|
    $rsp->{data}->[0]= "Usage: opsaddimage -h";
 | 
						|
    $rsp->{data}->[1]= "       opsaddimage -v";
 | 
						|
    $rsp->{data}->[2]= "       opsaddimage <image1,image2...> [-n <new_name1,new_name2...> -c <controller> [-V]";
 | 
						|
    $cb->($rsp);
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3   deploy_ops_bm_node_usage
 | 
						|
	The usage text for deploy_ops_bm_node command.
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
sub deploy_ops_bm_node_usage {
 | 
						|
    my $cb=shift;
 | 
						|
    my $rsp={};
 | 
						|
 | 
						|
    $rsp->{data}->[0]= "Usage: deploy_ops_bm_node -h";
 | 
						|
    $rsp->{data}->[1]= "       deploy_ops_bm_node -v";
 | 
						|
    $rsp->{data}->[2]= "       deploy_ops_bm_node <node> --image <image_name> --host <ops_hostname> --ip <ops_fixed_ip> --mask <netmask>";
 | 
						|
    $cb->($rsp);
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3  cleanup_ops_bm_node_usage
 | 
						|
	The usage text cleanup_ops_bm_node command.
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
sub cleanup_ops_bm_node_usage {
 | 
						|
    my $cb=shift;
 | 
						|
    my $rsp={};
 | 
						|
 | 
						|
    $rsp->{data}->[0]= "Usage: cleanup_ops_bm_node -h";
 | 
						|
    $rsp->{data}->[1]= "       cleanup_ops_bm_node -v";
 | 
						|
    $rsp->{data}->[2]= "       cleanup_ops_bm_node <node> [--ip <ops_fixed_ip>]";
 | 
						|
    $cb->($rsp);
 | 
						|
}
 | 
						|
 | 
						|
1;
 |