mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-31 19:32:31 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1001 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			1001 lines
		
	
	
		
			30 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;
 |