fixup Zone.pm

This commit is contained in:
Lissa Valletta 2014-04-01 07:02:11 -04:00
commit ce87bdceac
121 changed files with 9680 additions and 607 deletions

View File

@ -194,7 +194,7 @@ then
if [ ! -d ../../$package_dir_name ];then
mkdir -p "../../$package_dir_name"
fi
packages="xCAT-client xCAT-genesis-scripts perl-xCAT xCAT-server xCAT-UI xCAT xCATsn xCAT-test xCAT-OpenStack"
packages="xCAT-client xCAT-genesis-scripts perl-xCAT xCAT-server xCAT-UI xCAT xCATsn xCAT-test xCAT-OpenStack xCAT-OpenStack-baremetal"
for file in `echo $packages`
do

View File

@ -41,7 +41,7 @@ UPLOADUSER=bp-sawyers
FRS=/home/frs/project/x/xc/xcat
# These are the rpms that should be built for each kind of xcat build
ALLBUILD="perl-xCAT xCAT-client xCAT-server xCAT-IBMhpc xCAT-rmc xCAT-UI xCAT-test xCAT-buildkit xCAT xCATsn xCAT-genesis-scripts xCAT-OpenStack"
ALLBUILD="perl-xCAT xCAT-client xCAT-server xCAT-IBMhpc xCAT-rmc xCAT-UI xCAT-test xCAT-buildkit xCAT xCATsn xCAT-genesis-scripts xCAT-OpenStack xCAT-SoftLayer xCAT-OpenStack-baremetal"
ZVMBUILD="perl-xCAT xCAT-server xCAT-UI"
ZVMLINK="xCAT-client xCAT xCATsn"
PCMBUILD="xCAT"
@ -237,7 +237,7 @@ if [ "$OSNAME" = "AIX" ]; then
fi
# Build the rest of the noarch rpms
for rpmname in xCAT-client xCAT-server xCAT-IBMhpc xCAT-rmc xCAT-UI xCAT-test xCAT-buildkit; do
for rpmname in xCAT-client xCAT-server xCAT-IBMhpc xCAT-rmc xCAT-UI xCAT-test xCAT-buildkit xCAT-SoftLayer; do
#if [ "$EMBED" = "zvm" -a "$rpmname" != "xCAT-server" -a "$rpmname" != "xCAT-UI" ]; then continue; fi # for zvm embedded env only need to build server and UI
if [[ " $EMBEDBUILD " != *\ $rpmname\ * ]]; then continue; fi
if [ "$OSNAME" = "AIX" -a "$rpmname" = "xCAT-buildkit" ]; then continue; fi # do not build xCAT-buildkit on aix
@ -272,19 +272,19 @@ if [ "$OSNAME" != "AIX" ]; then
fi
# Build the xCAT and xCATsn rpms for all platforms
for rpmname in xCAT xCATsn xCAT-OpenStack; do
for rpmname in xCAT xCATsn xCAT-OpenStack xCAT-OpenStack-baremetal; do
#if [ "$EMBED" = "zvm" ]; then break; fi
if [[ " $EMBEDBUILD " != *\ $rpmname\ * ]]; then continue; fi
if [ $SOMETHINGCHANGED == 1 -o "$BUILDALL" == 1 ]; then # used to be: if $GREP -E "^[UAD] +$rpmname/" $GITUP; then
UPLOAD=1
ORIGFAILEDRPMS="$FAILEDRPMS"
if [ "$OSNAME" = "AIX" ]; then
if [ "$rpmname" = "xCAT-OpenStack" ]; then continue; fi # do not bld openstack on aix
if [ "$rpmname" = "xCAT-OpenStack" ] || [ "$rpmname" = "xCAT-OpenStack-baremetal" ]; then continue; fi # do not bld openstack on aix
./makerpm $rpmname "$EMBED"
if [ $? -ne 0 ]; then FAILEDRPMS="$FAILEDRPMS $rpmname"; fi
else
for arch in x86_64 ppc64 s390x; do
if [ "$rpmname" = "xCAT-OpenStack" -a "$arch" != "x86_64" ]; then continue; fi # only bld openstack for x86_64 for now
if [ "$rpmname" = "xCAT-OpenStack" -a "$arch" != "x86_64" ] || [ "$rpmname" = "xCAT-OpenStack-baremetal" -a "$arch" != "x86_64" ] ; then continue; fi # only bld openstack for x86_64 for now
./makerpm $rpmname $arch "$EMBED"
if [ $? -ne 0 ]; then FAILEDRPMS="$FAILEDRPMS $rpmname-$arch"; fi
done
@ -496,6 +496,7 @@ if [ "$OSNAME" != "AIX" -a "$REL" = "devel" -a "$PROMOTE" != 1 -a -z "$EMBED" ];
rpm2cpio ../$XCATCORE/xCAT-test-*.$NOARCH.rpm | cpio -id '*.html'
rpm2cpio ../$XCATCORE/xCAT-buildkit-*.$NOARCH.rpm | cpio -id '*.html'
rpm2cpio ../$XCATCORE/xCAT-OpenStack-*.x86_64.rpm | cpio -id '*.html'
rpm2cpio ../$XCATCORE/xCAT-SoftLayer-*.$NOARCH.rpm | cpio -id '*.html'
i=0
while [ $((i+=1)) -le 5 ] && ! rsync $verboseflag -r opt/xcat/share/doc/man1 opt/xcat/share/doc/man3 opt/xcat/share/doc/man5 opt/xcat/share/doc/man7 opt/xcat/share/doc/man8 $UPLOADUSER,xcat@web.sourceforge.net:htdocs/
do : ; done

View File

@ -53,6 +53,7 @@ function makexcat {
tar -X /tmp/xcat-excludes -cf $RPMROOT/SOURCES/templates.tar templates
gzip -f $RPMROOT/SOURCES/templates.tar
cp xcat.conf $RPMROOT/SOURCES
cp xcat.conf.apach24 $RPMROOT/SOURCES
cp xCATMN $RPMROOT/SOURCES
else # xCATsn
tar -X /tmp/xcat-excludes -cf $RPMROOT/SOURCES/license.tar LICENSE.html
@ -77,6 +78,7 @@ function makexcat {
tar --exclude .svn -czf $RPMROOT/SOURCES/templates.tar.gz templates
tar --exclude .svn -czf $RPMROOT/SOURCES/winpostscripts.tar.gz winpostscripts
cp xcat.conf $RPMROOT/SOURCES
cp xcat.conf.apach24 $RPMROOT/SOURCES
cp xCATMN $RPMROOT/SOURCES
cd - >/dev/null
elif [ "$RPMNAME" = "xCATsn" ]; then

View File

@ -262,6 +262,12 @@ expression B<($1-1)%14+1> will evaluate to B<6>.
See http://www.perl.com/doc/manual/html/pod/perlre.html for information on perl regular expressions.
=head2 Easy Regular Expressions
As of xCAT 2.8.1, you can use a modified version of the regular expression support described in the previous section. You do not need to enter the node information (1st part of the expression), it will be derived from the input nodename. You only need to supply the 2nd part of the expression to determine the value to give the attribute. For examples, see
https://sourceforge.net/apps/mediawiki/xcat/index.php?title=Listing_and_Modifying_the_Database#Easy_Regular_expressions
=head1 OBJECT DEFINITIONS
Because it can get confusing what attributes need to go in what tables, the xCAT database can also

View File

@ -2747,7 +2747,7 @@ sub collapsenicsattr()
# e.g nicips.eth0
# do not need to handle nic attributes without the postfix .ethx,
# it will be overwritten by the attributes with the postfix .ethx,
if ($nodeattr =~ /^(nic\w+)\.(\w+)$/)
if ($nodeattr =~ /^(nic\w+)\.(.*)$/)
{
if ($1 && $2)
{

View File

@ -67,7 +67,7 @@ sub getHcpAttribs
}
}
my @ps = $tabs->{ppc}->getAllNodeAttribs(['node','parent','nodetype','hcp']);
my @ps = $tabs->{ppc}->getAllNodeAttribs(['node','parent','nodetype','hcp','id']);
for my $entry ( @ps ) {
my $tmp_parent = $entry->{parent};
my $tmp_node = $entry->{node};
@ -79,6 +79,9 @@ sub getHcpAttribs
if (defined($tmp_node) && defined($tmp_type) && ($tmp_type eq "blade") && defined($entry->{hcp})) {
push @{$ppchash{$tmp_node}{children}}, $entry->{hcp};
}
if (defined($tmp_node) && defined($entry->{id}) && defined($tmp_parent) && defined($tmp_type) && ($tmp_type eq "lpar")) {
$ppchash{$tmp_parent}{mapping}{$tmp_node} = $entry->{id};
}
#if(exists($ppchash{$tmp_node})) {
# if( defined($tmp_type) ) {

View File

@ -103,6 +103,53 @@ sub chvm_parse_extra_options {
return "'$value' is invalid, must be in form of 'Server_name:slotnum'";
}
}
} elsif ($cmd eq "vmcpus") {
if ($value =~ /^(\d+)\/(\d+)\/(\d+)$/) {
unless ($1 <= $2 and $2 <= $3) {
return "'$value' is invalid, must be in order";
}
} else {
return "'$value' is invalid, must be integer";
}
} elsif ($cmd eq "vmmemory") {
if ($value =~ /^([\d|.]+)([G|M]?)\/([\d|.]+)([G|M]?)\/([\d|.]+)([G|M]?)$/i) {
my ($mmin, $mcur, $mmax);
if ($2 == "G" or $2 == '') {
$mmin = $1 * 1024;
}
if ($4 == "G" or $4 == '') {
$mcur = $3 * 1024;
}
if ($6 == "G" or $6 == '') {
$mmax = $5 * 1024;
}
unless ($mmin <= $mcur and $mcur <= $mmax) {
return "'$value' is invalid, must be in order";
}
} else {
return "'$value' is invalid";
}
} elsif ($cmd eq "vmphyslots") {
my @tmp_array = split ",",$value;
foreach (@tmp_array) {
unless (/(0x\w{8})/) {
return "'$_' is invalid";
}
}
} elsif ($cmd eq "vmothersetting") {
my @tmp_array = split ",", $value;
foreach (@tmp_array) {
unless (/^(bsr|hugepage):\d+$/) {
return "'$_' is invalid";
}
}
} elsif ($cmd eq "vmnics") {
my @tmp_array = split ",", $value;
foreach (@tmp_array) {
unless (/^vlan\d+$/i) {
return "'$_' is invalid";
}
}
}
} else {
@ -1859,7 +1906,8 @@ sub deal_with_avail_mem {
}
#xCAT::MsgUtils->verbose_message($request, "====****====used:$used_regions,avail:$cur_avail,($min:$cur:$max).");
if ($cur_avail < $min) {
return([$name, "Parse reserverd regions failed, no enough memory, available:$lparhash->{hyp_avail_mem}.", 1]);
my $cur_mem_in_G = $lparhash->{hyp_avail_mem} * $lparhash->{mem_region_size} * 1.0 / 1024;
return([$name, "Parse reserverd regions failed, no enough memory, available:$cur_mem_in_G GB.", 1]);
}
if ($cur > $cur_avail) {
my $new_cur = $cur_avail;
@ -1999,6 +2047,7 @@ sub create_lpar {
}
return ([$name, "Done", 0]);
}
sub mkspeclpar {
my $request = shift;
my $hash = shift;
@ -2044,6 +2093,75 @@ sub mkspeclpar {
if (exists($opt->{vmnics})) {
$tmp_ent->{nics} = $opt->{vmnics};
}
if (!defined($tmp_ent) ) {
return ([[$name, "Not find params", 1]]);
#} elsif (!exists($tmp_ent->{cpus}) || !exists($tmp_ent->{memory}) || !exists($tmp_ent->{physlots})) {
} elsif (!exists($tmp_ent->{cpus}) || !exists($tmp_ent->{memory})) {
return ([[$name, "The attribute 'vmcpus', 'vmmemory' are needed to be specified.", 1]]);
}
# FIX bug 3873 [FVT]DFM illegal action could work
#
if ($tmp_ent->{cpus} =~ /^(\d+)\/(\d+)\/(\d+)$/) {
unless ($1 <= $2 and $2 <= $3) {
return([[$name, "Parameter for 'vmcpus' is invalid", 1]]);
}
} else {
return([[$name, "Parameter for 'vmcpus' is invalid", 1]]);
}
if ($tmp_ent->{memory} =~ /^([\d|.]+)([G|M]?)\/([\d|.]+)([G|M]?)\/([\d|.]+)([G|M]?)$/i) {
my ($mmin, $mcur, $mmax);
if ($2 == "G" or $2 == '') {
$mmin = $1 * 1024;
}
if ($4 == "G" or $4 == '') {
$mcur = $3 * 1024;
}
if ($6 == "G" or $6 == '') {
$mmax = $5 * 1024;
}
unless ($mmin <= $mcur and $mcur <= $mmax) {
return([[$name, "Parameter for 'vmmemory' is invalid", 1]]);
}
my $memsize = $memhash->{mem_region_size};
$mmin = ($mmin + $memsize) / $memsize;
$mcur = ($mcur + $memsize) / $memsize;
$mmax = ($mmax + $memsize) / $memsize;
$tmp_ent->{memory} = "$mmin/$mcur/$mmax";
$tmp_ent->{mem_region_size} = $memsize;
} else {
return([[$name, "Parameter for 'vmmemory' is invalid", 1]]);
}
if (exists($tmp_ent->{physlots})) {
my @tmp_array = split ",",$tmp_ent->{physlots};
foreach (@tmp_array) {
unless (/(0x\w{8})/i) {
return([[$name, "Parameter:$_ for 'vmphyslots' is invalid", 1]]);
}
}
}
if (exists($tmp_ent->{othersettings})) {
my @tmp_array = split ",",$tmp_ent->{othersettings};
foreach (@tmp_array) {
unless (/^(bsr|hugepage):\d+$/) {
return([[$name, "Parameter:$_ for 'vmothersetting' is invalid", 1]]);
}
}
}
if (exists($tmp_ent->{nics})) {
my @tmp_array = split ",",$tmp_ent->{nics};
foreach (@tmp_array) {
unless (/^vlan\d+$/i) {
return([[$name, "Parameter:$_ for 'vmnics' is invalid", 1]]);
}
}
}
if (exists($opt->{vios})) {
if (!exists($tmp_ent->{physlots})) {
my @phy_io_array = keys(%{$memhash->{bus}});
@ -2073,43 +2191,22 @@ sub mkspeclpar {
}
}
}
if (!defined($tmp_ent) ) {
return ([[$name, "Not find params", 1]]);
#} elsif (!exists($tmp_ent->{cpus}) || !exists($tmp_ent->{memory}) || !exists($tmp_ent->{physlots})) {
} elsif (!exists($tmp_ent->{cpus}) || !exists($tmp_ent->{memory})) {
return ([[$name, "The attribute 'vmcpus', 'vmmemory' are needed to be specified.", 1]]);
}
if ($tmp_ent->{memory} =~ /(\d+)([G|M]?)\/(\d+)([G|M]?)\/(\d+)([G|M]?)/i) {
my $memsize = $memhash->{mem_region_size};
my $min = $1;
if ($2 == "G" or $2 == '') {
$min = $min * 1024;
}
$min = $min/$memsize;
my $cur = $3;
if ($4 == "G" or $4 == '') {
$cur = $cur * 1024;
}
$cur = $cur/$memsize;
my $max = $5;
if ($6 == "G" or $6 == '') {
$max = $max * 1024;
}
$max = $max/$memsize;
$tmp_ent->{memory} = "$min/$cur/$max";
}
$tmp_ent->{hyp_config_mem} = $memhash->{hyp_config_mem};
$tmp_ent->{hyp_avail_mem} = $memhash->{hyp_avail_mem};
$tmp_ent->{huge_page} = "0/0/0";
$tmp_ent->{bsr_num} = "0";
if (exists($tmp_ent->{othersettings})) {
my $setting = $tmp_ent->{othersettings};
if ($setting =~ /hugepage:(\d+)/) {
my $tmp = $1;
$tmp_ent->{huge_page} = "1/".$tmp."/".$tmp;
if ($tmp >= 1) {
$tmp_ent->{huge_page} = "1/".$tmp."/".$tmp;
}
}
if ($setting =~ /bsr:(\d+)/) {
$tmp_ent->{bsr_num} = $1;
if ($1 >= 1) {
$tmp_ent->{bsr_num} = $1;
}
}
}
$tmp_ent->{phy_hea} = $memhash->{phy_drc_group_port};

View File

@ -35,7 +35,7 @@ package xCAT::RemoteShellExp;
node.
DSH_TO_USERID - The userid on the node where the ssh keys will be updated.
DSH_ENABLE_SSH - Node to node root passwordless ssh will be setup.
DSH_ZONE_SSHKEYS - directory containing the zones root .ssh keys
Usage: remoteshellexp
[-t node list] test ssh connection to the node
@ -144,7 +144,7 @@ sub remoteshellexp
} else {
$from_userid="root";
}
# set User on the node where we will send the keys
# set User on the node where we will send the keys
# this id can be a local id as well as root
if ($ENV{'DSH_TO_USERID'}) {
$to_userid=$ENV{'DSH_TO_USERID'};
@ -154,18 +154,19 @@ sub remoteshellexp
# set User home directory to find the ssh public key to send
# For non-root ids information may not be in /etc/passwd
# but elsewhere like LDAP
if ($ENV{'DSH_FROM_USERID_HOME'}) {
$home=$ENV{'DSH_FROM_USERID_HOME'};
$home=$ENV{'DSH_FROM_USERID_HOME'};
} else {
$home=xCAT::Utils->getHomeDir($from_userid);
$home=xCAT::Utils->getHomeDir($from_userid);
}
# This indicates we will generate new ssh keys for the user,
# if they are not already there
my $key="$home/.ssh/id_rsa";
my $key2="$home/.ssh/id_rsa.pub";
# Check to see if empty
if (-z $key) {
# unless using zones
my $key="$home/.ssh/id_rsa";
my $key2="$home/.ssh/id_rsa.pub";
# Check to see if empty
if (-z $key) {
my $rsp = {};
$rsp->{error}->[0] =
"The $key file is empty. Remove it and rerun the command.";
@ -183,8 +184,7 @@ sub remoteshellexp
}
if (($flag eq "k") && (!(-e $key)))
{
# if the file size of the id_rsa key is 0, tell them to remove it
# and run the command again
# updating keys and the key file does not exist
$rc=xCAT::RemoteShellExp->gensshkeys($expecttimeout);
}
# send ssh keys to the nodes/devices, to setup passwordless ssh
@ -200,6 +200,9 @@ sub remoteshellexp
if ($ssh_setup_cmd) { # setup ssh on devices
$rc=xCAT::RemoteShellExp->senddeviceskeys($remoteshell,$remotecopy,$to_userid,$to_user_password,$home,$ssh_setup_cmd,$nodes, $expecttimeout);
} else { #setup ssh on nodes
if ($ENV{'DSH_ZONE_SSHKEYS'}) { # if using zones the override the location of the keys
$home= $ENV{'DSH_ZONE_SSHKEYS'};
}
$rc=xCAT::RemoteShellExp->sendnodeskeys($remoteshell,$remotecopy,$to_userid,$to_user_password,$home,$nodes, $expecttimeout);
}
}
@ -495,11 +498,15 @@ sub sendnodeskeys
# in $HOME/.ssh/tmp/authorized_keys
# copy to the node to the temp directory
# scp $HOME/.ssh/tmp/authorized_keys to_userid@<node>:/tmp/$to_userid/.ssh
# scp $HOME/.ssh/id_rsa.pub to_userid@<node>:/tmp/$to_userid/.ssh
# Note if using zones, the keys do not come from ~/.ssh but from the
# zone table, sshkeydir attribute. For zones the userid is always root
# If you are going to enable ssh to ssh between nodes, then
# scp $HOME/.ssh/id_rsa to that temp directory on the node
# copy the script $HOME/.ssh/copy.sh to the node, it will do the
# the work of setting up the user's ssh keys and clean up
# ssh (run) copy.sh on the node
my @nodelist=split(/,/,$nodes);
foreach my $node (@nodelist) {
$sendkeys = new Expect;
@ -607,11 +614,11 @@ sub sendnodeskeys
my $spawncopyfiles;
if ($ENV{'DSH_ENABLE_SSH'}) { # we will enable node to node ssh
$spawncopyfiles=
"$remotecopy $home/.ssh/id_rsa $home/.ssh/copy.sh $home/.ssh/tmp/authorized_keys $to_userid\@$node:/tmp/$to_userid/.ssh ";
"$remotecopy $home/.ssh/id_rsa $home/.ssh/id_rsa.pub $home/.ssh/copy.sh $home/.ssh/tmp/authorized_keys $to_userid\@$node:/tmp/$to_userid/.ssh ";
} else { # no node to node ssh ( don't send private key)
$spawncopyfiles=
"$remotecopy $home/.ssh/copy.sh $home/.ssh/tmp/authorized_keys $to_userid\@$node:/tmp/$to_userid/.ssh ";
"$remotecopy $home/.ssh/id_rsa.pub $home/.ssh/copy.sh $home/.ssh/tmp/authorized_keys $to_userid\@$node:/tmp/$to_userid/.ssh ";
}
# send copy command
unless ($sendkeys->spawn($spawncopyfiles))

View File

@ -599,7 +599,7 @@ noderes => {
descriptions => {
node => 'The node name or group name.',
servicenode => 'A comma separated list of node names (as known by the management node) that provides most services for this node. The first service node on the list that is accessible will be used. The 2nd node on the list is generally considered to be the backup service node for this node when running commands like snmove.',
netboot => 'The type of network booting to use for this node. Valid values: pxe or xnba for x86* architecture, yaboot for POWER architecture.',
netboot => 'The type of network booting to use for this node. Valid values: pxe or xnba for x86* architecture, yaboot for POWER architecture, grub2 for RHEL7 on Power. Notice: yaboot is not supported from rhels7 on Power,use grub2 instead',
tftpserver => 'The TFTP server for this node (as known by this node). If not set, it defaults to networks.tftpserver.',
tftpdir => 'The directory that roots this nodes contents from a tftp and related perspective. Used for NAS offload by using different mountpoints.',
nfsserver => 'The NFS or HTTP server for this node (as known by this node).',
@ -1052,7 +1052,8 @@ site => {
" Set to NOGROUPS,if you do not wish to enabled any group of compute nodes.\n".
" Service Nodes are not affected by this attribute\n".
" they are always setup with\n".
" passwordless root access to nodes and other SN.\n\n".
" passwordless root access to nodes and other SN.\n".
" If using the zone table, this attribute in not used.\n\n".
" -----------------\n".
"SERVICES ATTRIBUTES\n".
" -----------------\n".
@ -1191,12 +1192,13 @@ performance => {
},
},
zone => {
cols => [qw(zonename sshkeydir defaultzone comments disable)],
cols => [qw(zonename sshkeydir sshbetweennodes defaultzone comments disable)],
keys => [qw(zonename)],
table_desc => 'Defines a cluster zone for nodes that share root ssh key access to each other.',
descriptions => {
zonename => 'The name of the zone.',
sshkeydir => 'Directory containing the shared root ssh RSA keys.',
sshbetweennodes => 'Indicates whether passwordless ssh will be setup between the nodes of this zone. Values are yes/1 or no/0. Default is yes. ',
defaultzone => 'If nodes are not assigned to any other zone, they will default to this zone. If value is set to yes or 1.',
comments => 'Any user-provided notes.',
disable => "Set to 'yes' or '1' to comment out this row.",
@ -1555,8 +1557,8 @@ hwinv => {
node => 'The node name or group name.',
cputype => 'The cpu model name for the node.',
cpucount => 'The number of cpus for the node.',
memory => 'The size of the memory for the node.',
disksize => 'The size of the disks for the node.',
memory => 'The size of the memory for the node in MB.',
disksize => 'The size of the disks for the node in GB.',
comments => 'Any user-provided notes.',
disable => "Set to 'yes' or '1' to comment out this row.",
},
@ -3083,6 +3085,10 @@ push(@{$defspec{node}->{'attrs'}}, @nodeattrs);
tabentry => 'zone.sshkeydir',
access_tabentry => 'zone.zonename=attr:zonename',
},
{attr_name => 'sshbetweennodes',
tabentry => 'zone.sshbetweennodes',
access_tabentry => 'zone.zonename=attr:zonename',
},
{attr_name => 'defaultzone',
tabentry => 'zone.defaultzone',
access_tabentry => 'zone.zonename=attr:zonename',

View File

@ -19,6 +19,7 @@ if ($^O =~ /^aix/i) {
use lib "$::XCATROOT/lib/perl";
use strict;
require xCAT::Table;
require xCAT::Zone;
use File::Path;
#-----------------------------------------------------------------------
@ -271,7 +272,7 @@ sub bldnonrootSSHFiles
Error:
0=good, 1=error
Example:
xCAT::TableUtils->setupSSH(@target_nodes);
xCAT::TableUtils->setupSSH(@target_nodes,$expecttimeout);
Comments:
Does not setup known_hosts. Assumes automatically
setup by SSH ( ssh config option StrictHostKeyChecking no should
@ -335,21 +336,21 @@ sub setupSSH
$::REMOTE_SHELL = "/usr/bin/ssh";
my $rsp = {};
# Get the home directory
my $home = xCAT::Utils->getHomeDir($from_userid);
$ENV{'DSH_FROM_USERID_HOME'} = $home;
if ($from_userid eq "root")
{
# make the directory to hold keys to transfer to the nodes
if (!-d $SSHdir)
{
mkpath("$SSHdir", { mode => 0755 });
}
# generates new keys for root, if they do not already exist
# generates new keys for root, if they do not already exist ~/.ssh
# nodes not used on this option but in there to preserve the interface
my $rc=
xCAT::RemoteShellExp->remoteshellexp("k",$::CALLBACK,$::REMOTE_SHELL,$n_str,$expecttimeout);
@ -374,7 +375,10 @@ else
fi
mkdir -p \$dest_dir
cat /tmp/$to_userid/.ssh/authorized_keys >> \$home/.ssh/authorized_keys 2>&1
cat /tmp/$to_userid/.ssh/id_rsa.pub >> \$home/.ssh/authorized_keys 2>&1
rm -f \$home/.ssh/id_rsa 2>&1
cp /tmp/$to_userid/.ssh/id_rsa \$home/.ssh/id_rsa 2>&1
cp /tmp/$to_userid/.ssh/id_rsa.pub \$home/.ssh/id_rsa.pub 2>&1
chmod 0600 \$home/.ssh/id_* 2>&1
rm -f /tmp/$to_userid/.ssh/* 2>&1
rmdir \"/tmp/$to_userid/.ssh\"
@ -386,6 +390,7 @@ rmdir \"/tmp/$to_userid\" \n";
my $auth_key2=0;
if ($from_userid eq "root")
{
# this will put the root/.ssh/id_rsa.pub key in the authorized keys file to put on the node
my $rc = xCAT::TableUtils->cpSSHFiles($SSHdir);
if ($rc != 0)
{ # error
@ -418,50 +423,47 @@ rmdir \"/tmp/$to_userid\" \n";
xCAT::TableUtils->bldnonrootSSHFiles($from_userid);
}
# send the keys to the nodes for root or some other id
#
# This environment variable determines whether to setup
# node to node ssh
# The nodes must be checked against the site.sshbetweennodes attribute
# send the keys
# For root user and not to devices only to nodes
if (($from_userid eq "root") && (!($ENV{'DEVICETYPE'}))) {
my $enablenodes;
my $disablenodes;
my @nodelist= split(",", $n_str);
foreach my $n (@nodelist)
# Need to check if nodes are in a zone.
my @zones;
my $tab = xCAT::Table->new("zone");
my @zones;
if ($tab)
{
my $enablessh=xCAT::TableUtils->enablessh($n);
if ($enablessh == 1) {
$enablenodes .= $n;
$enablenodes .= ",";
} else {
$disablenodes .= $n;
$disablenodes .= ",";
# if we have zones, need to send the zone keys to each node in the zone
my @attribs = ("zonename");
@zones = $tab->getAllAttribs(@attribs);
$tab->close();
} else {
$rsp->{data}->[0] = "Could not open zone table.\n";
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
return 1;
}
# check for zones, key send is different if zones defined or not
if (@zones) { # we have zones defined
my $rc = xCAT::TableUtils->sendkeysTOzones($ref_nodes,$expecttimeout);
if ($rc != 0)
{
$rsp->{data}->[0] = "Error sending ssh keys to the zones.\n";
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
exit 1;
}
}
my $cmd;
if ($enablenodes) { # node on list to setup nodetonodessh
chop $enablenodes; # remove last comma
$ENV{'DSH_ENABLE_SSH'} = "YES";
my $rc=xCAT::RemoteShellExp->remoteshellexp("s",$::CALLBACK,"/usr/bin/ssh",$enablenodes,$expecttimeout);
} else { # no zones
# if no zone table defined, do it the old way , keys are in ~/.ssh
my $rc = xCAT::TableUtils->sendkeysNOzones($ref_nodes,$expecttimeout);
if ($rc != 0)
{
$rsp->{data}->[0] = "remoteshellexp failed sending keys to enablenodes.";
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
}
}
if ($disablenodes) { # node on list to setup nodetonodessh
chop $disablenodes; # remove last comma
my $rc=xCAT::RemoteShellExp->remoteshellexp("s",$::CALLBACK,"/usr/bin/ssh",$disablenodes,$expecttimeout);
if ($rc != 0)
{
$rsp->{data}->[0] = "remoteshellexp failed sending keys to disablenodes.";
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
{
$rsp->{data}->[0] = "Error sending ssh keys to the nodes.\n";
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
}
}
} else { # from user is not root or it is a device , always send private key
$ENV{'DSH_ENABLE_SSH'} = "YES";
my $rc=xCAT::RemoteShellExp->remoteshellexp("s",$::CALLBACK,"/usr/bin/ssh",$n_str,$expecttimeout);
@ -503,6 +505,235 @@ rmdir \"/tmp/$to_userid\" \n";
#--------------------------------------------------------------------------------
=head3 sendkeysNOzones
Transfers the ssh keys
for the root id on the nodes no zones
key from ~/.ssh site.sshbetweennodes honored
Arguments:
Array of nodes
Timeout for expect call (optional)
Returns:
Env Variables: $DSH_FROM_USERID, $DSH_TO_USERID, $DSH_REMOTE_PASSWORD
the ssh keys are transferred from the $DSH_FROM_USERID to the $DSH_TO_USERID
on the node(s). The DSH_REMOTE_PASSWORD and the DSH_FROM_USERID
must be obtained by
the calling script or from the xdsh client
Globals:
$::XCATROOT , $::CALLBACK
Error:
0=good, 1=error
Example:
xCAT::TableUtils->sendkeysNOzones($ref_nodes,$expecttimeout);
Comments:
Does not setup known_hosts. Assumes automatically
setup by SSH ( ssh config option StrictHostKeyChecking no should
be set in the ssh config file).
=cut
#--------------------------------------------------------------------------------
sub sendkeysNOzones
{
my ($class, $ref_nodes,$expecttimeout) = @_;
my @nodes=$ref_nodes;
my $enablenodes;
my $disablenodes;
my $n_str = $nodes[0];
my @nodelist= split(",", $n_str);
my $rsp = ();
foreach my $n (@nodelist)
{
my $enablessh=xCAT::TableUtils->enablessh($n);
if ($enablessh == 1) {
$enablenodes .= $n;
$enablenodes .= ",";
} else {
$disablenodes .= $n;
$disablenodes .= ",";
}
}
if ($enablenodes) { # node on list to setup nodetonodessh
chop $enablenodes; # remove last comma
$ENV{'DSH_ENABLE_SSH'} = "YES";
# send the keys to the nodes
my $rc=xCAT::RemoteShellExp->remoteshellexp("s",$::CALLBACK,"/usr/bin/ssh",$enablenodes,$expecttimeout);
if ($rc != 0)
{
$rsp->{data}->[0] = "remoteshellexp failed sending keys to enablenodes.";
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
}
}
if ($disablenodes) { # node on list to disable nodetonodessh
chop $disablenodes; # remove last comma
# send the keys to the nodes
my $rc=xCAT::RemoteShellExp->remoteshellexp("s",$::CALLBACK,"/usr/bin/ssh",$disablenodes,$expecttimeout);
if ($rc != 0)
{
$rsp->{data}->[0] = "remoteshellexp failed sending keys to disablenodes.";
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
}
}
}
#--------------------------------------------------------------------------------
=head3 sendkeysTOzones
Transfers the ssh keys
for the root id on the nodes using the zone table.
If in a zone, then root ssh keys for the node will be taken from the zones ssh keys not ~/.ssh
zones are only supported on nodes that are not a service node.
Also for the call to RemoteShellExp, we must group the nodes that are in the same zone
Arguments:
Array of nodes
Timeout for expect call (optional)
Returns:
Env Variables: $DSH_FROM_USERID, $DSH_TO_USERID, $DSH_REMOTE_PASSWORD
the ssh keys are transferred from the $DSH_FROM_USERID to the $DSH_TO_USERID
on the node(s). The DSH_REMOTE_PASSWORD and the DSH_FROM_USERID
must be obtained by
the calling script or from the xdsh client
Globals:
$::XCATROOT , $::CALLBACK
Error:
0=good, 1=error
Example:
xCAT::TableUtils->sendkeysTOzones($ref_nodes,$expecttimeout);
Comments:
Does not setup known_hosts. Assumes automatically
setup by SSH ( ssh config option StrictHostKeyChecking no should
be set in the ssh config file).
=cut
#--------------------------------------------------------------------------------
sub sendkeysTOzones
{
my ($class, $ref_nodes,$expecttimeout) = @_;
my @nodes=$ref_nodes;
my $n_str = $nodes[0];
my @nodes= split(",", $n_str);
my $rsp = ();
my $cmd;
my $roothome = xCAT::Utils->getHomeDir("root");
my $zonehash =xCAT::Zone->getzoneinfo($::CALLBACK,\@nodes);
foreach my $zonename (keys %$zonehash) {
# build list of nodes
my $zonenodelist="";
foreach my $node (@{$zonehash->{$zonename}->{nodes}}) {
$zonenodelist .= $node;
$zonenodelist .= ",";
}
$zonenodelist =~ s/,$//; # remove last comma
# if any nodes defined for the zone
if ($zonenodelist) {
# check to see if we enable passwordless ssh between the nodes
if (!(defined($zonehash->{$zonename}->{sshbetweennodes}))||
(($zonehash->{$zonename}->{sshbetweennodes} =~ /^yes$/i )
|| ($zonehash->{$zonename}->{sshbetweennodes} eq "1"))) {
$ENV{'DSH_ENABLE_SSH'} = "YES";
} else {
delete $ENV{'DSH_ENABLE_SSH'}; # do not enable passwordless ssh
}
# point to the ssh keys to send for this zone
my $keydir = $zonehash->{$zonename}->{sshkeydir} ;
# check to see if the id_rsa and id_rsa.pub key is in the directory
my $key="$keydir/id_rsa";
my $key2="$keydir/id_rsa.pub";
# Check to see if empty
if (!(-e $key)) {
my $rsp = {};
$rsp->{error}->[0] =
"The $key file does not exist for $zonename. Need to use chzone to regenerate the keys.";
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK, 1);
return 1;
}
if (!(-e $key2)) {
my $rsp = {};
$rsp->{error}->[0] =
"The $key2 file does not exist for $zonename. Need to use chzone to regenerate the keys.";
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK, 1);
return 1;
}
# now put copy.sh in the zone directory from ~/.ssh
my $rootkeydir="$roothome/.ssh";
if ($rootkeydir ne $keydir) { # the zone keydir is not the same as ~/.ssh.
$cmd="cp $rootkeydir/copy.sh $keydir";
xCAT::Utils->runcmd($cmd, 0);
if ($::RUNCMD_RC != 0)
{
my $rsp = {};
$rsp->{error}->[0] =
"Could not copy copy.sh to the zone key dir";
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
return 1;
}
}
# Also create $keydir/tmp and put root's id_rsa.pub (in authorized_keys) for the transfer
$cmd="mkdir -p $keydir/tmp";
xCAT::Utils->runcmd($cmd, 0);
if ($::RUNCMD_RC != 0)
{
my $rsp = {};
$rsp->{error}->[0] =
"Could not mkdir the zone $keydir/tmp";
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
return 1;
}
# create authorized_keys file
if (xCAT::Utils->isMN()) { # if on Management Node
$cmd = " cp $roothome/.ssh/id_rsa.pub $keydir/tmp/authorized_keys";
} else { # SN
$cmd = " cp $roothome/.ssh/authorized_keys $keydir/tmp/authorized_keys";
}
xCAT::Utils->runcmd($cmd, 0);
if ($::RUNCMD_RC != 0)
{
$rsp->{data}->[0] = "$cmd failed.\n";
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
return (1);
}
else
{
chmod 0600, "$keydir/.ssh/tmp/authorized_keys";
}
# strip off .ssh
my ($newkeydir,$ssh) = (split(/\.ssh/, $keydir));
$ENV{'DSH_ZONE_SSHKEYS'} =$newkeydir ;
# send the keys to the nodes
my $rc=xCAT::RemoteShellExp->remoteshellexp("s",$::CALLBACK,"/usr/bin/ssh",
$zonenodelist,$expecttimeout);
if ($rc != 0)
{
$rsp = {};
$rsp->{data}->[0] = "remoteshellexp failed sending keys to $zonename.";
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
}
} # end nodes in the zone
} # end for each zone
return (0);
}
#--------------------------------------------------------------------------------
=head3 cpSSHFiles
Builds authorized_keyfiles for root
@ -1594,8 +1825,8 @@ sub enableSSH
} else {
# if not a service node we need to check, before enabling
if (defined($groups_hash)) {
if ($groups_hash->{ALLGROUPS} == 1)
if (keys %$groups_hash) { # not empty
if ($groups_hash->{ALLGROUPS} == 1)
{
$enablessh=1;
}
@ -1769,7 +2000,7 @@ sub updatenodegroups {
}
}
my ($ent) = $tabhd->getNodeAttribs($node, ['groups']);
my @list = qw(all);
my @list = ();
if (defined($ent) and $ent->{groups}) {
push @list, split(/,/,$ent->{groups});
}
@ -1783,5 +2014,54 @@ sub updatenodegroups {
@list = keys %saw;
$tabhd->setNodeAttribs($node, {groups=>join(",",@list)});
}
#-----------------------------------------------------------------------------
=head3 rmnodegroups
remove groups from the group attribute for the specified node
Arguments:
node
tabhd: the handler of 'nodelist' table,
groups: the groups that need to be removed.
Can be an array or string.
Globals:
none
Error:
Example:
xCAT::TableUtils->rmnodegroups($node, $tab, $groups);
=cut
#-----------------------------------------------------------------------------
sub rmnodegroups {
my ($class, $node, $tabhd, $groups) = @_;
my ($ent) = $tabhd->getNodeAttribs($node, ['groups']);
my @definedgroups;
my @removegroups;
my @newgroups;
if (defined($ent) and $ent->{groups}) {
push @definedgroups, split(/,/,$ent->{groups});
}
if (ref($groups) eq 'ARRAY') {
push @removegroups, @$groups;
} else {
push @removegroups, split(/,/,$groups);
}
# take out any groups that match the input list of groups to remove
foreach my $dgrp (@definedgroups){
if (grep(/^$dgrp$/, @removegroups)) { # is the group to be removed
next;
} else { # keep this group
push @newgroups,$dgrp;
}
}
my %saw;
@saw{@newgroups} = ();
@newgroups = keys %saw;
$tabhd->setNodeAttribs($node, {groups=>join(",",@newgroups)});
}
1;

View File

@ -3416,4 +3416,48 @@ sub version_cmp {
return ( $len_a <=> $len_b )
}
#--------------------------------------------------------------------------------
=head3 fullpathbin
returns the full path of a specified binary executable file
Arguments:
string of the bin file name
Returns:
string of the full path name of the binary executable file
Globals:
none
Error:
string of the bin file name in the argument
Example:
my $CHKCONFIG = xCAT::Utils->fullpathbin("chkconfig");
Comments:
none
=cut
#--------------------------------------------------------------------------------
sub fullpathbin
{
my $bin=shift;
if( $bin =~ /xCAT::Utils/)
{
$bin=shift;
}
my @paths= ("/bin","/usr/bin","/sbin","/usr/sbin");
my $fullpath=$bin;
foreach my $path (@paths)
{
if (-x $path.'/'.$bin)
{
$fullpath= $path.'/'.$bin;
last;
}
}
return $fullpath;
}
1;

View File

@ -49,7 +49,7 @@ This program module file, is a set of Zone utilities used by xCAT *zone commands
=cut
#--------------------------------------------------------------------------------
sub genSSHRootKeys
sub genSSHRootKeys
{
my ($class, $callback, $keydir,$zonename,$rsakey) = @_;
@ -71,22 +71,6 @@ sub genSSHRootKeys
}
}
#
# create /install/postscripts/_ssh/zonename if needed
#
my $installdir = xCAT::TableUtils->getInstallDir(); # get installdir
if (!-d "$installdir/postscripts/_ssh/$zonename")
{
my $cmd = "/bin/mkdir -m 755 -p $installdir/postscripts/_ssh/$zonename";
my $output = xCAT::Utils->runcmd("$cmd", 0);
if ($::RUNCMD_RC != 0)
{
my $rsp = {};
$rsp->{error}->[0] = "Could not create $installdir/postscripts/_ssh/$zonename directory.";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
}
#need to gen a new rsa key for root for the zone
my $pubfile = "$keydir/id_rsa.pub";
@ -152,29 +136,6 @@ sub genSSHRootKeys
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
# copy authorized_keys for install on node
if (-r $pubfile)
{
my $cmd =
"/bin/cp -p $pubfile $installdir/postscripts/_ssh/$zonename ";
my $output = xCAT::Utils->runcmd("$cmd", 0);
if ($::RUNCMD_RC != 0)
{
my $rsp = {};
$rsp->{error}->[0] =
"Could not copy $pubfile to $installdir/postscripts/_ssh/$zonename";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
}
else
{
my $rsp = {};
$rsp->{error}->[0] =
"Could not copy $pubfile to $installdir/postscripts/_ssh/$zonename, because $pubfile does not exist.";
xCAT::MsgUtils->message("E", $rsp, $callback);
}
}
#--------------------------------------------------------------------------------
@ -184,11 +145,11 @@ sub genSSHRootKeys
Returns:
Name of the current default zone from the zone table
Example:
my $defaultzone =xCAT::Zone->getdefaultzone();
my $defaultzone =xCAT::Zone->getdefaultzone($callback);
=cut
#--------------------------------------------------------------------------------
sub getdefaultzone
sub getdefaultzone
{
my ($class, $callback) = @_;
my $defaultzone;
@ -199,7 +160,8 @@ sub getdefaultzone
foreach my $zone (@zones) {
# Look for the defaultzone=yes/1 entry
if ((defined($zone->{defaultzone})) &&
(($zone->{defaultzone} =~ "yes") || ($zone->{defaultzone} = "1"))) {
(($zone->{defaultzone} =~ /^yes$/i )
|| ($zone->{defaultzone} eq "1"))) {
$defaultzone = $zone->{zonename};
}
$tab->close();
@ -230,9 +192,133 @@ sub iszonedefined
my ($class,$zonename) = @_;
# checks the zone table to see if input zonename already in the table
my $tab = xCAT::Table->new("zone");
my $zone = $tab->getAttribs({zonename => $zonename},'sshkeydir');
$tab->close();
if (defined($zone)) {
my $zonehash = $tab->getAttribs({zonename => $zonename},'sshkeydir');
if ( keys %$zonehash) {
return 1;
}else{
return 0;
}
}
#--------------------------------------------------------------------------------
=head3 getzonekeydir
Arguments:
zonename
Returns:
path to the root ssh keys for the zone /etc/xcat/sshkeys/<zonename>/.ssh
1 - zone not defined
Example:
xCAT::Zone->getzonekeydir($zonename);
=cut
#--------------------------------------------------------------------------------
sub getzonekeydir
{
my ($class,$zonename) = @_;
my $tab = xCAT::Table->new("zone");
$tab->close();
my $zonehash = $tab->getAttribs({zonename => $zonename},'sshkeydir');
if ( keys %$zonehash) {
my $zonesshkeydir=$zonehash->{sshkeydir};
return $zonesshkeydir;
}else{
return 1; # this is a bad error zone not defined
}
}
#--------------------------------------------------------------------------------
=head3 getmyzonename
Arguments:
$node -one nodename
Returns:
$zonename
Example:
my $zonename=xCAT::Zone->getmyzonename($node);
=cut
#--------------------------------------------------------------------------------
sub getmyzonename
{
my ($class,$node,$callback) = @_;
my @node;
push @node,$node;
my $zonename;
my $nodelisttab = xCAT::Table->new("nodelist");
my $nodehash = $nodelisttab->getNodesAttribs(\@node, ['zonename']);
$nodelisttab->close();
if ( defined ($nodehash->{$node}->[0]->{zonename})) { # it was defined in the nodelist table
$zonename=$nodehash->{$node}->[0]->{zonename};
} else { # get the default zone
$zonename =xCAT::Zone->getdefaultzone($callback);
}
return $zonename;
}
#--------------------------------------------------------------------------------
=head3 enableSSHbetweennodes
Arguments:
zonename
Returns:
1 if the sshbetweennodes attribute is yes/1 or undefined
0 if the sshbetweennodes attribute is no/0
Example:
xCAT::Zone->enableSSHbetweennodes($zonename);
=cut
#--------------------------------------------------------------------------------
sub enableSSHbetweennodes
{
my ($class,$node,$callback) = @_;
# finds the zone of the node
my $enablessh = 1; # default
my $zonename=xCAT::Zone->getmyzonename($node);
# reads the zone table
my $tab = xCAT::Table->new("zone");
$tab->close();
# read both keys, want to know zone is in the zone table. If sshkeydir is not there
# it is either missing or invalid anyway
my $zonehash = $tab->getAttribs({zonename => $zonename},'sshbetweennodes','sshkeydir');
if (! ( keys %$zonehash)) {
my $rsp = {};
$rsp->{error}->[0] =
"$node has a zonename: $zonename that is not define in the zone table. Remove the zonename from the node, or create the zone using mkzone. The generated mypostscript may not reflect the correct setting for ENABLESSHBETWEENNODES";
xCAT::MsgUtils->message("E", $rsp, $callback);
return $enablessh;
}
my $sshbetweennodes=$zonehash->{sshbetweennodes};
if (defined ($sshbetweennodes)) {
if (($sshbetweennodes =~ /^no$/i) || ($sshbetweennodes eq "0")) {
$enablessh = 0;
} else {
$enablessh = 1;
}
} else { # not defined default yes
$enablessh = 1 ; # default
}
return $enablessh;
}
#--------------------------------------------------------------------------------
=head3 usingzones
Arguments:
none
Returns:
1 if the zone table is not empty
0 if empty
Example:
xCAT::Zone->usingzones;
=cut
#--------------------------------------------------------------------------------
sub usingzones
{
my ($class) = @_;
# reads the zonetable
my $tab = xCAT::Table->new("zone");
my @zone = $tab->getAllAttribs('zonename');
$tab->close();
if (@zone) {
return 1;
}else{
return 0;
@ -242,44 +328,48 @@ sub iszonedefined
=head3 getzoneinfo
Arguments:
callback
An array of nodes
Returns:
Hash array by zonename point to the nodes in that zonename and sshkeydir
zonename1 -> {nodelist} -> array of nodes in the zone
<zonename1> -> {nodelist} -> array of nodes in the zone
-> {sshkeydir} -> directory containing ssh RSA keys
-> {defaultzone} -> is it the default zone
Example:
my %zonehash =xCAT::Zone->getNodeZones($nodelist);
my %zonehash =xCAT::Zone->getzoneinfo($callback,@nodearray);
Rules:
If the nodes nodelist.zonename attribute is a zonename, it is assigned to that zone
If the nodes nodelist.zonename attribute is undefined:
If there is a defaultzone in the zone table, the node is assigned to that zone
If there is no defaultzone in the zone table, the node is assigned to the ~.ssh keydir
$::GETZONEINFO_RC
0 = good return
1 = error occured
=cut
#--------------------------------------------------------------------------------
sub getzoneinfo
sub getzoneinfo
{
my ($class, $callback,$nodes) = @_;
# make the list into an array
# $nodelist=~ s/\s*//g; # remove blanks
# my @nodes = split ',', $nodelist;
$::GETZONEINFO_RC=0;
my $zonehash;
my $defaultzone;
# read all the zone table
my $zonetab = xCAT::Table->new("zone");
my @zones;
if ($zonetab){
my @zones = $zonetab->getAllAttribs('zonename','sshkeydir','defaultzone');
@zones = $zonetab->getAllAttribs('zonename','sshkeydir','sshbetweennodes','defaultzone');
$zonetab->close();
if (@zones) {
foreach my $zone (@zones) {
my $zonename=$zone->{zonename};
$zonehash->{$zonename}->{sshkeydir}= $zone->{sshkeydir};
$zonehash->{$zonename}->{defaultzone}= $zone->{defaultzone};
$zonehash->{$zonename}->{sshbetweennodes}= $zone->{sshbetweennodes};
# find the defaultzone
if ((defined($zone->{defaultzone})) &&
(($zone->{defaultzone} =~ /yes/i) or ($zone->{defaultzone} eq "1"))) {
if ((defined($zone->{defaultzone})) &&
(($zone->{defaultzone} =~ /^yes$/i )
|| ($zone->{defaultzone} eq "1"))) {
$defaultzone = $zone->{zonename};
}
}
@ -289,41 +379,74 @@ sub getzoneinfo
$rsp->{error}->[0] =
"Error reading the zone table. ";
xCAT::MsgUtils->message("E", $rsp, $callback);
$::GETZONEINFO_RC =1;
return;
}
my $nodelisttab = xCAT::Table->new("nodelist");
my $nodehash = $nodelisttab->getNodesAttribs(\@$nodes, ['zonename']);
# for each of the nodes, look up it's zone name and assign to the zonehash
# if the node is a service node, it is assigned to the __xcatzone which gets its keys from
# the ~/.ssh dir no matter what in the database for the zonename.
# If the nodes nodelist.zonename attribute is a zonename, it is assigned to that zone
# If the nodes nodelist.zonename attribute is undefined:
# If there is a defaultzone in the zone table, the node is assigned to that zone
# If there is no defaultzone in the zone table, the node is assigned to the ~.ssh keydir
# If there is no defaultzone error out
my @allSN=xCAT::ServiceNodeUtils->getAllSN("ALL"); # read all the servicenodes define
my $xcatzone = "__xcatzone"; # if node is in no zones or a service node, use this one
$zonehash->{$xcatzone}->{sshkeydir}= "~/.ssh";
foreach my $node (@$nodes) {
my $zonename;
if (grep(/^$node$/, @allSN)) { # this is a servicenode, treat special
$zonename=$xcatzone; # always use ~/.ssh directory
} else { # use the nodelist.zonename attribute
$zonename=$nodehash->{$node}->[0]->{zonename};
}
$zonename=$nodehash->{$node}->[0]->{zonename};
if (defined($zonename)) { # zonename explicitly defined in nodelist.zonename
push @{$zonehash->{$zonename}->{nodes}},$node;
# check to see if defined in the zone table
unless ( xCAT::Zone->iszonedefined($zonename)) {
my $rsp = {};
$rsp->{error}->[0] =
"$node has a zonename: $zonename that is not define in the zone table. Remove the zonename from the node, or create the zone using mkzone.";
xCAT::MsgUtils->message("E", $rsp, $callback);
$::GETZONEINFO_RC =1;
return;
}
push @{$zonehash->{$zonename}->{nodes}},$node;
} else { # no explict zonename
if (defined ($defaultzone)) { # there is a default zone in the zone table, use it
push @{$zonehash->{$defaultzone}->{nodes}},$node;
} else { # if no default then use the ~/.ssh keys as the default, put them in the __xcatzone
push @{$zonehash->{$xcatzone}->{nodes}},$node;
} else { # if no default, this is an error
my $rsp = {};
$rsp->{error}->[0] =
"There is no default zone defined in the zone table. There must be exactly one default zone. ";
xCAT::MsgUtils->message("E", $rsp, $callback);
$::GETZONEINFO_RC =1;
return;
}
}
}
return $zonehash;
}
#--------------------------------------------------------------------------------
=head3 getnodesinzone
Arguments:
callback
zonename
Returns:
Array of nodes
Example:
my @nodes =xCAT::Zone->getnodesinzone($callback,$zonename);
=cut
#--------------------------------------------------------------------------------
sub getnodesinzone
{
my ($class, $callback,$zonename) = @_;
my @nodes;
my $nodelisttab = xCAT::Table->new("nodelist");
my @nodelist=$nodelisttab->getAllAttribs('node','zonename');
# build the array of nodes in this zone
foreach my $nodename (@nodelist) {
if ((defined($nodename->{'zonename'})) && ($nodename->{'zonename'} eq $zonename)) {
push @nodes,$nodename->{'node'};
}
}
return @nodes;
}
1;

View File

@ -14,9 +14,10 @@ require Exporter;
%distnames = (
"1310229985.226287" => "centos6",
"1323560292.885204" => "centos6.2",
"1341569670.539525" => "centos6.3",#x86
"1362445555.957609" => "centos6.4",#x86_64
"1323560292.885204" => "centos6.2",
"1341569670.539525" => "centos6.3",#x86
"1362445555.957609" => "centos6.4",#x86_64
"1385726732.061157" => "centos6.5",#x86_64
"1176234647.982657" => "centos5",
"1156364963.862322" => "centos4.4",
"1178480581.024704" => "centos4.5",

View File

@ -0,0 +1,6 @@
xcat-openstack-baremetal for Debian
-----------------------------------
<possible notes regarding this package - if none, delete this file>
-- root <root@unknown> Wed, 12 Mar 2014 01:47:54 -0700

View File

@ -0,0 +1,9 @@
xcat-openstack-baremetal for Debian
-----------------------------------
<this file describes information about the source package, see Debian policy
manual section 4.14. You WILL either need to modify or delete this file>

View File

@ -0,0 +1,5 @@
xcat-openstack-baremetal (2.8.4-1) unstable; urgency=low
* Initial release (Closes: #nnnn) <nnnn is the bug number of your ITP>
-- root <root@unknown> Wed, 12 Mar 2014 01:47:54 -0700

View File

@ -0,0 +1 @@
8

View File

@ -0,0 +1,14 @@
Source: xcat-openstack-baremetal
Section: admin
Priority: extra
Maintainer: xCAT <xcat-user@lists.sourceforge.net>
Build-Depends: debhelper (>= 8.0.0)
Standards-Version: 3.9.4
Homepage: http://xcat.sourceforge.net/
#Vcs-Git: git://git.debian.org/collab-maint/xcat-openstack-baremetal.git
#Vcs-Browser: http://git.debian.org/?p=collab-maint/xcat-openstack-baremetal.git;a=summary
Package: xcat-openstack-baremetal
Architecture: all
Depends: xCAT-client
Description: Executables and data of the xCAT baremetal driver for OpenStack

View File

@ -0,0 +1,38 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: xcat-openstack-baremetal
Source: <url://example.com>
Files: *
Copyright: <years> <put author's name and email here>
<years> <likewise for another author>
License: <special license>
<Put the license of the package here indented by 1 space>
<This follows the format of Description: lines in control file>
.
<Including paragraphs>
# If you want to use GPL v2 or later for the /debian/* files use
# the following clauses, or change it to suit. Delete these two lines
Files: debian/*
Copyright: 2014 root <root@unknown>
License: GPL-2+
This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
.
This package is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
.
On Debian systems, the complete text of the GNU General
Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
# Please also look if there are files or directories which have a
# different copyright/license attached and list them here.
# Please avoid to pick license terms that are more restrictive than the
# packaged work, as it may make Debian's contributions unacceptable upstream.

View File

@ -0,0 +1,7 @@
opt/xcat/bin
opt/xcat/sbin
opt/xcat/lib/perl/xCAT_plugin
opt/xcat/lib/python/xcat/openstack/baremetal
opt/xcat/share/xcat/openstack/postscripts
opt/xcat/share/man/man1
opt/xcat/share/doc/man1

View File

View File

@ -0,0 +1,2 @@
xcat-openstack-baremetal_2.8.4-1_all.deb admin extra
xcat-openstack-baremetal_2.8.4-1_all.deb admin extra

View File

@ -0,0 +1,6 @@
lib/* opt/xcat/lib/
share/xcat/openstack/postscripts/* opt/xcat/share/xcat/openstack/postscripts/
share/man/man1/* opt/xcat/share/man/man1/
share/doc/man1/* opt/xcat/share/doc/man1/

View File

@ -0,0 +1,43 @@
#!/bin/sh
# postinst script for xcat-openstack-baremetal
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postinst> `configure' <most-recently-configured-version>
# * <old-postinst> `abort-upgrade' <new version>
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
# <new-version>
# * <postinst> `abort-remove'
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
# <failed-install-package> <version> `removing'
# <conflicting-package> <version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
configure)
#copy the postscripts under /installl/postscripts directory on MN only
if [ -f "/etc/xCATMN" ]; then
cp /opt/xcat/share/xcat/openstack/postscripts/* /install/postscripts/
fi
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

View File

@ -0,0 +1,46 @@
#!/bin/sh
# prerm script for xcat-openstack-baremetal
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <prerm> `remove'
# * <old-prerm> `upgrade' <new-version>
# * <new-prerm> `failed-upgrade' <old-version>
# * <conflictor's-prerm> `remove' `in-favour' <package> <new-version>
# * <deconfigured's-prerm> `deconfigure' `in-favour'
# <package-being-installed> <version> `removing'
# <conflicting-package> <version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
remove|upgrade|deconfigure)
#remove postscripts under /installl/postscripts directory on MN only
if [ -f "/etc/xCATMN" ]; then
for fn in /opt/xcat/share/xcat/openstack/postscripts/*
do
bn=`basename $fn`
rm /install/postscripts/$bn
done
fi
;;
failed-upgrade)
;;
*)
echo "prerm called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

View File

@ -0,0 +1,44 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
build:
pwd
`pwd`/xpod2man
clean:
dh_testdir
dh_testroot
dh_clean -d
install:
pwd
dh_testdir
dh_testroot
dh_installdirs
dh_install -X".svn"
chmod 444 `pwd`/debian/xcat-openstack-baremetal/opt/xcat/share/man/man1/*
chmod 644 `pwd`/debian/xcat-openstack-baremetal/opt/xcat/share/doc/man1/*
dh_link
binary-indep: build install
pwd
export
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
binary-arch:
pwd
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install configure

View File

@ -0,0 +1 @@
1.0

View File

@ -0,0 +1,201 @@
dh_installdirs
dh_installdirs
dh_install
dh_link
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb
dh_installdirs
dh_install
dh_link
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb
dh_installdirs
dh_install
dh_link
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb
dh_installdirs
dh_install
dh_link
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb
dh_installdirs
dh_install
dh_link
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb
dh_installdirs
dh_install
dh_link
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb
dh_installdirs
dh_install
dh_link
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb
dh_installdirs
dh_install
dh_link
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb
dh_installdirs
dh_install
dh_link
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb
dh_installdirs
dh_install
dh_link
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb
dh_installdirs
dh_install
dh_link
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb
dh_installdirs
dh_install
dh_link
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb
dh_installdirs
dh_install
dh_link
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb
dh_installdirs
dh_install
dh_link
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb
dh_installdirs
dh_install
dh_link
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb
dh_installdirs
dh_install
dh_link
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb
dh_installdirs
dh_install
dh_link
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb
dh_installdirs
dh_install
dh_link
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb
dh_installdirs
dh_install
dh_link
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb
dh_installdirs
dh_install
dh_link
dh_installman
dh_compress
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
dh_builddeb

View File

@ -0,0 +1,4 @@
opt/xcat/bin/xcatclient opt/xcat/sbin/deploy_ops_bm_node
opt/xcat/bin/xcatclient opt/xcat/sbin/cleanup_ops_bm_node
opt/xcat/bin/xcatclient opt/xcat/bin/opsaddbmnode
opt/xcat/bin/xcatclientnnr opt/xcat/bin/opsaddimage

View File

@ -0,0 +1 @@
misc:Depends=

View File

@ -0,0 +1,904 @@
# 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 $host;
if(!GetOptions(
'h|help' => \$help,
'v|version' => \$version,
'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;
}
#print "$bmc, $bmc_user, $bmc_password, $mac, $cpu, $memory, $disk\n";
#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~source \~/openrc;$cmd_tmp~;
#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";
xCAT::MsgUtils->message("E", $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 $cloud;
my $ops_img_names;
my $controller;
if(!GetOptions(
'h|help' => \$help,
'v|version' => \$version,
'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;source \~/openrc;$cmd_tmp;rm /tmp/$image.qcow2~;
#print "cmd=$cmd\ncontroller=$controller\n";
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";
xCAT::MsgUtils->message("E", $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>";
$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>";
$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;

View File

@ -0,0 +1,17 @@
# Copyright (c) 2012 NTT DOCOMO, INC.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from xcat.openstack.baremetal import driver
BareMetalDriver = driver.xCATBareMetalDriver

View File

@ -0,0 +1,256 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# coding=utf-8
"""
A driver for Bare-metal platform.
"""
from oslo.config import cfg
from nova.compute import power_state
from nova import context as nova_context
from nova import exception
from nova.openstack.common import excutils
from nova.openstack.common.gettextutils import _
from nova.openstack.common import importutils
from nova.openstack.common import jsonutils
from nova.openstack.common import log as logging
from nova.virt.baremetal import baremetal_states
from nova.virt.baremetal import db
from nova.virt.baremetal import driver as bm_driver
from nova.virt.baremetal import utils as bm_utils
from nova.virt import driver
from nova.virt import firewall
from nova.virt.libvirt import imagecache
from xcat.openstack.baremetal import xcat_driver
from xcat.openstack.baremetal import exception as xcat_exception
from xcat.openstack.baremetal import power_states
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
CONF.import_opt('use_ipv6', 'nova.netconf')
class xCATBareMetalDriver(bm_driver.BareMetalDriver):
"""BareMetal hypervisor driver."""
def __init__(self, virtapi, read_only=False):
super(xCATBareMetalDriver, self).__init__(virtapi)
self.xcat = xcat_driver.xCAT()
def _get_xCAT_image_name(self, image_meta):
prop = image_meta.get('properties')
xcat_image_name = prop.get('xcat_image_name')
if xcat_image_name:
return xcat_image_name
else:
raise xcat_exception.xCATInvalidImageError(image=image_meta.get('name'))
def spawn(self, context, instance, image_meta, injected_files,
admin_password, network_info=None, block_device_info=None):
"""
Create a new instance/VM/domain on the virtualization platform.
Once this successfully completes, the instance should be
running (power_state.RUNNING).
If this fails, any partial instance should be completely
cleaned up, and the virtualization platform should be in the state
that it was before this call began.
:param context: security context
:param instance: Instance object as returned by DB layer.
This function should use the data there to guide
the creation of the new instance.
:param image_meta: image object returned by nova.image.glance that
defines the image from which to boot this instance
:param injected_files: User files to inject into instance.
:param admin_password: Administrator password to set in instance.
:param network_info:
:py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
:param block_device_info: Information about block devices to be
attached to the instance.
"""
#import pdb
#pdb.set_trace()
node_uuid = self._require_node(instance)
node = db.bm_node_associate_and_update(context, node_uuid,
{'instance_uuid': instance['uuid'],
'instance_name': instance['hostname'],
'task_state': baremetal_states.BUILDING})
try:
self._plug_vifs(instance, network_info, context=context)
self._attach_block_devices(instance, block_device_info)
self._start_firewall(instance, network_info)
macs = self.macs_for_instance(instance)
nodename = self.xcat.get_xcat_node_name(macs)
imagename = self._get_xCAT_image_name(image_meta)
hostname = instance.get('hostname')
#get the network information for the new node
interfaces = bm_utils.map_network_interfaces(network_info, CONF.use_ipv6)
if CONF.use_ipv6:
fixed_ip = interfaces[0].get('address_v6')
netmask = interfaces[0].get('netmask_v6')
gateway = interfaces[0].get('gateway_v6')
else:
fixed_ip = interfaces[0].get('address')
netmask = interfaces[0].get('netmask')
gateway = interfaces[0].get('gateway')
#convert netmask from IPAddress to unicode string
if netmask:
netmask = unicode(netmask)
#let xCAT install it
bm_driver._update_state(context, node, instance, baremetal_states.DEPLOYING)
self.xcat.deploy_node(nodename, imagename, hostname, fixed_ip, netmask, gateway)
bm_driver._update_state(context, node, instance, baremetal_states.ACTIVE)
except Exception as e:
with excutils.save_and_reraise_exception():
LOG.error(_("Error occured while deploying instance %(instance)s "
"on baremetal node %(node)s: %(error)s") %
{'instance': instance['uuid'],
'node': node['uuid'],
'error':str(e)})
bm_driver._update_state(context, node, instance, baremetal_states.ERROR)
def reboot(self, context, instance, network_info, reboot_type,
block_device_info=None, bad_volumes_callback=None):
"""Reboot the specified instance.
After this is called successfully, the instance's state
goes back to power_state.RUNNING. The virtualization
platform should ensure that the reboot action has completed
successfully even in cases in which the underlying domain/vm
is paused or halted/stopped.
:param instance: Instance object as returned by DB layer.
:param network_info:
:py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
:param reboot_type: Either a HARD or SOFT reboot
:param block_device_info: Info pertaining to attached volumes
:param bad_volumes_callback: Function to handle any bad volumes
encountered
"""
try:
node = bm_driver._get_baremetal_node_by_instance_uuid(instance['uuid'])
macs = self.macs_for_instance(instance)
nodename = self.xcat.get_xcat_node_name(macs)
self.xcat.reboot_node(nodename)
bm_driver._update_state(context, node, instance, baremetal_states.RUNNING)
except xcat_exception.xCATCommandError as e:
with excutils.save_and_reraise_exception():
LOG.error(_("Error occured while rebooting instance %(instance)s "
"on baremetal node %(node)s: %(error)s") %
{'instance': instance['uuid'],
'node': node['uuid'],
'error':str(e)})
bm_driver._update_state(context, node, instance, baremetal_states.ERROR)
def destroy(self, instance, network_info, block_device_info=None,
context=None):
"""Destroy (shutdown and delete) the specified instance.
If the instance is not found (for example if networking failed), this
function should still succeed. It's probably a good idea to log a
warning in that case.
:param context: security context
:param instance: Instance object as returned by DB layer.
:param network_info:
:py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
:param block_device_info: Information about block devices that should
be detached from the instance.
:param destroy_disks: Indicates if disks should be destroyed
"""
#import pdb
#pdb.set_trace()
context = nova_context.get_admin_context()
try:
node = bm_driver._get_baremetal_node_by_instance_uuid(instance['uuid'])
except exception.InstanceNotFound:
LOG.warning(_("Destroy function called on a non-existing instance %s")
% instance['uuid'])
return
try:
macs = self.macs_for_instance(instance)
nodename = self.xcat.get_xcat_node_name(macs)
interfaces = bm_utils.map_network_interfaces(network_info, CONF.use_ipv6)
fixed_ip=None
if interfaces and interfaces[0]:
if CONF.use_ipv6:
fixed_ip = interfaces[0].get('address_v6')
else:
fixed_ip = interfaces[0].get('address')
if fixed_ip:
self.xcat.cleanup_node(nodename, fixed_ip)
else:
self.xcat.cleanup_node(nodename)
except Exception as e:
#just log it and move on
LOG.warning(_("Destroy called with xCAT error:" + str(e)))
try:
self._detach_block_devices(instance, block_device_info)
self._stop_firewall(instance, network_info)
self._unplug_vifs(instance, network_info)
bm_driver._update_state(context, node, None, baremetal_states.DELETED)
except Exception as e:
with excutils.save_and_reraise_exception():
LOG.error(_("Error occurred while destroying instance %s: %s")
% (instance['uuid'], str(e)))
bm_driver._update_state(context, node, instance,
baremetal_states.ERROR)
def power_off(self, instance, node=None):
"""Power off the specified instance."""
macs = self.macs_for_instance(instance)
nodename = self.xcat.get_xcat_node_name(macs)
self.xcat.power_off_node(nodename)
def power_on(self, context, instance, network_info, block_device_info=None,
node=None):
"""Power on the specified instance."""
macs = self.macs_for_instance(instance)
nodename = self.xcat.get_xcat_node_name(macs)
self.xcat.power_on_node(nodename)
def get_console_output(self, instance):
pass
def get_info(self, instance):
"""Get the current status of an instance, by name (not ID!)
Returns a dict containing:
:state: the running state, one of the power_state codes
:max_mem: (int) the maximum memory in KBytes allowed
:mem: (int) the memory in KBytes used by the domain
:num_cpu: (int) the number of virtual CPUs for the domain
:cpu_time: (int) the CPU time used in nanoseconds
"""
node = bm_driver._get_baremetal_node_by_instance_uuid(instance['uuid'])
macs = self.macs_for_instance(instance)
nodename = self.xcat.get_xcat_node_name(macs)
ps = self.xcat.get_node_power_state(nodename)
if ps == power_states.ON:
pstate = power_state.RUNNING
elif ps == power_states.OFF:
pstate = power_state.SHUTDOWN
else:
pstate = power_state.NOSTATE
return {'state': pstate,
'max_mem': node['memory_mb'],
'mem': node['memory_mb'],
'num_cpu': node['cpus'],
'cpu_time': 0}

View File

@ -0,0 +1,41 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
"""xCAT baremtal exceptions.
"""
import functools
import sys
from oslo.config import cfg
import webob.exc
from nova.openstack.common import excutils
from nova.openstack.common.gettextutils import _
from nova.openstack.common import log as logging
from nova import safe_utils
from nova import exception as nova_exception
LOG = logging.getLogger(__name__)
class xCATException(Exception):
errmsg = _("xCAT general exception")
def __init__(self, errmsg=None, **kwargs):
if not errmsg:
errmsg = self.errmsg
errmsg = errmsg % kwargs
super(xCATException, self).__init__(errmsg)
class xCATCommandError(xCATException):
errmsg = _("Error returned when calling xCAT command %(cmd)s"
" for node %(node)s:%(error)s")
class xCATInvalidImageError(xCATException):
errmsg = _("The image %(image)s is not an xCAT image")
class xCATDeploymentFailure(xCATException):
errmsg = _("xCAT node deployment failed for node %(node)s:%(error)s")
class xCATRebootFailure(xCATException):
errmsg = _("xCAT node rebooting failed for node %(node)s:%(error)s")

View File

@ -0,0 +1,9 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
"""
Possible xCAT node power states.
"""
OFF = 'off'
ON = 'on'
ERROR = 'error'

View File

@ -0,0 +1,260 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# coding=utf-8
"""
Baremetal xCAT power manager.
"""
import os
import sys
import stat
from oslo.config import cfg
import datetime
from nova import context as nova_context
from nova.virt.baremetal import baremetal_states
from nova.openstack.common.gettextutils import _
from nova.openstack.common import log as logging
from nova.openstack.common import loopingcall
from nova.openstack.common import timeutils
from nova import paths
from nova import utils
from xcat.openstack.baremetal import exception
from xcat.openstack.baremetal import power_states
LOG = logging.getLogger(__name__)
# register configuration options
xcat_opts = [
cfg.IntOpt('deploy_timeout',
help='Timeout for node deployment. Default: 0 second (unlimited)',
default=0),
cfg.IntOpt('reboot_timeout',
help='Timeout for rebooting a node. Default: 0 second (unlimited)',
default=0),
cfg.IntOpt('deploy_checking_interval',
help='Checking interval for node deployment. Default: 10 seconds',
default=10),
cfg.IntOpt('reboot_checking_interval',
help='Checking interval for rebooting a node. Default: 5 seconds',
default=5),
]
xcat_group = cfg.OptGroup(name='xcat',
title='xCAT Options')
CONF = cfg.CONF
CONF.register_group(xcat_group)
CONF.register_opts(xcat_opts, xcat_group)
class xCAT(object):
"""A driver that calls xCAT funcions"""
def __init__(self):
#setup the path for xCAT commands
#xcatroot = os.getenv('XCATROOT', '/opt/xcat/')
#sys.path.append("%s/bin" % xcatroot)
#sys.path.append("%s/sbin" % xcatroot)
pass
def _exec_xcat_command(self, command):
"""Calls xCAT command."""
args = command.split(" ")
out, err = utils.execute(*args, run_as_root=True)
LOG.debug(_("xCAT command stdout: '%(out)s', stderr: '%(err)s'"),
{'out': out, 'err': err})
return out, err
def get_xcat_node_name(self, macs):
"""Get the xcat node name given mac addressed.
It uses the mac address to search for the node name in xCAT.
"""
for mac in macs:
out, err = self._exec_xcat_command("lsdef -w mac=%s" % mac)
if out:
return out.split(" ")[0]
errstr='No node found in xCAT with the following mac address: ' \
+ ','.join(macs)
LOG.warning(errstr)
raise exception.xCATCommandError(errstr)
def deploy_node(self, nodename, imagename, hostname, fixed_ip, netmask, gateway):
"""
Install the node.
It calls xCAT command deploy_ops_bmnode which 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.
"""
out, err = self._exec_xcat_command(
"deploy_ops_bm_node %(node)s --image %(image)s"
" --host %(host)s --ip %(ip)s --mask %(mask)s"
% {'node': nodename,
'image': imagename,
'host': hostname,
'ip': fixed_ip,
'mask': netmask,
})
if err:
errstr = _("Error returned when calling xCAT deploy_ops_bm_node"
" command for node %s:%s") % (nodename, err)
LOG.warning(errstr)
raise exception.xCATCommandError(errstr)
self._wait_for_node_deploy(nodename)
def cleanup_node(self, nodename, fixed_ip=None):
"""
Undo all the changes made to the node by deploy_node function.
It calls xCAT command cleanup_ops_bm_node which removes the
config_ops_bm_node postbootscript from the postscript table
for the node, removes the alias ip and then power the node off.
"""
cmd = "cleanup_ops_bm_node %s" % nodename
if fixed_ip:
cmd += " --ip %s" % fixed_ip
out, err = self._exec_xcat_command(cmd)
if err:
errstr = _("Error returned when calling xCAT cleanup_ops_bm_node"
" command for node %s:%s") % (nodename, err)
LOG.warning(errstr)
raise exception.xCATCommandError(errstr)
def power_on_node(self, nodename):
"""Power on the node."""
state = self.get_node_power_state(nodename)
if state == power_states.ON:
LOG.warning(_("Powring on node called, but the node %s "
"is already on") % nodename)
out, err = self._exec_xcat_command("rpower %s on" % nodename)
if err:
errstr = _("Error returned when calling xCAT rpower on"
" for node %s:%s") % (nodename, err)
LOG.warning(errstr)
raise exception.xCATCommandError(errstr)
else:
self._wait_for_node_reboot(nodename)
return power_states.ON
def power_off_node(self, nodename):
"""Power off the node."""
state = self.get_node_power_state(nodename)
if state == power_states.OFF:
LOG.warning(_("Powring off node called, but the node %s "
"is already off") % nodename)
out, err = self._exec_xcat_command("rpower %s off" % nodename)
if err:
errstr = _("Error returned when calling xCAT rpower off"
" for node %s:%s") % (nodename, err)
LOG.warning(errstr)
raise exception.xCATCommandError(errstr)
else:
return power_states.OFF
def reboot_node(self, nodename):
"""Reboot the node."""
out, err = self._exec_xcat_command("rpower %s boot" % nodename)
if err:
errstr = _("Error returned when calling xCAT rpower boot"
" for node %s:%s") % (nodename, err)
LOG.warning(errstr)
raise exception.xCATCommandError(errstr)
self._wait_for_node_reboot(nodename)
return power_states.ON
def get_node_power_state(self, nodename):
out, err = self._exec_xcat_command("rpower %s stat" % nodename)
if err:
errstr = _("Error returned when calling xCAT rpower stat"
" for node %s:%s") % (nodename, err)
LOG.warning(errstr)
raise exception.xCATCommandError(errstr)
else:
state = out.split(":")[1]
if state:
state = state.strip()
if state == 'on':
return power_states.ON
elif state == 'off':
return power_states.OFF
return power_states.ERROR
def _wait_for_node_deploy(self, nodename):
"""Wait for xCAT node deployment to complete."""
locals = {'errstr':''}
def _wait_for_deploy():
out,err = self._exec_xcat_command("nodels %s nodelist.status" % nodename)
if err:
locals['errstr'] = _("Error returned when quering node status"
" for node %s:%s") % (nodename, err)
LOG.warning(locals['errstr'])
raise loopingcall.LoopingCallDone()
if out:
node,status = out.split(": ")
status = status.strip()
if status == "booted":
LOG.info(_("Deployment for node %s completed.")
% nodename)
raise loopingcall.LoopingCallDone()
if (CONF.xcat.deploy_timeout and
timeutils.utcnow() > expiration):
locals['errstr'] = _("Timeout while waiting for"
" deployment of node %s.") % nodename
LOG.warning(locals['errstr'])
raise loopingcall.LoopingCallDone()
expiration = timeutils.utcnow() + datetime.timedelta(
seconds=CONF.xcat.deploy_timeout)
timer = loopingcall.FixedIntervalLoopingCall(_wait_for_deploy)
# default check every 10 seconds
timer.start(interval=CONF.xcat.deploy_checking_interval).wait()
if locals['errstr']:
raise exception.xCATDeploymentFailure(locals['errstr'])
def _wait_for_node_reboot(self, nodename):
"""Wait for xCAT node boot to complete."""
locals = {'errstr':''}
def _wait_for_reboot():
out,err = self._exec_xcat_command("nodestat %s" % nodename)
if err:
locals['errstr'] = _("Error returned when quering node status"
" for node %s:%s") % (nodename, err)
LOG.warning(locals['errstr'])
raise loopingcall.LoopingCallDone()
if out:
node,status = out.split(": ")
status = status.strip()
if status == "sshd":
LOG.info(_("Rebooting node %s completed.")
% nodename)
raise loopingcall.LoopingCallDone()
if (CONF.xcat.reboot_timeout and
timeutils.utcnow() > expiration):
locals['errstr'] = _("Timeout while waiting for"
" rebooting node %s.") % nodename
LOG.warning(locals['errstr'])
raise loopingcall.LoopingCallDone()
expiration = timeutils.utcnow() + datetime.timedelta(
seconds=CONF.xcat.reboot_timeout)
timer = loopingcall.FixedIntervalLoopingCall(_wait_for_reboot)
# default check every 5 seconds
timer.start(interval=CONF.xcat.reboot_checking_interval).wait()
if locals['errstr']:
raise exception.xCATRebootFailure(locals['errstr'])

View File

@ -0,0 +1,90 @@
=head1 NAME
B<opsaddbmnode> - It adds xCAT baremetal nodes to an OpenStack cloud.
=head1 SYNOPSIS
B<opsaddbmnode> I<noderange> B<-s> I<service_host>
B<opsaddbmnode> [B<-h>|B<--help>]
B<opsaddbmnode> [B<-v>|B<--version>]
=head1 DESCRIPTION
The B<opsaddbmnode> command registers xCAT nodes to an OpenStack cloud. An OpenStack nova baremetal node registration command takes several node attributes:
=over
=item BMC ip addresss, user id and password
=item Name of nova compute host which will control this baremetal node
=item Number of CPUs in the node
=item Memory in the node (MB)
=item Local hard disk in the node (GB)
=item MAC address to provision the node
=back
The opsaddbmnode command pulls the above baremetal node information from xCAT tables and calls "nova baremetal-node-create" to register the baremetal node with the OpenStack cloud.
Please make sure the following xCAT tables are filled with correct information for the given nodes before calling this command.
=over
=item ipmi (for BMC ip addresss, user id and password)
=item mac (for MAC address)
=item hwinv (for CPU, memory and disk info.)
=back
=head1 Parameters
I<noderage> is a comma separated node or node group names.
=head1 OPTIONS
=over 10
=item B<-s> The node name of the OpenStack compute host that hosts the baremetal nodes.
=item B<-h|--help> Display usage message.
=item B<-v|--version> The Command Version.
=back
=head1 RETURN VALUE
0 The command completed successfully.
1 An error has occurred.
=head1 EXAMPLES
=over 3
=item 1
To register node1, node2 and node3 to OpenStack, sv1 is the compute host.
opsassbmnode node1,node2,node3 -s sv1
=back
=head1 FILES
/opt/xcat/bin/opadddbmnode
=head1 SEE ALSO
L<opsaddimage(1)|opsaddimage.1>

View File

@ -0,0 +1,65 @@
=head1 NAME
B<opsaddimage> - It adds or removes nodes for the vlan.
=head1 SYNOPSIS
B<opsaddimage> I<image1,image2,...> B<-n> I<new_name1,new_name2,...> [B<-c> I<controller>]
B<opsaddimage> [B<-h>|B<--help>]
B<opsaddimage> [B<-v>|B<--version>]
=head1 DESCRIPTION
The B<opsaddimage> command adds a list of xCAT images into the OpenStack cloud.
Under the cover, it creates a fake image and registers the fake image into OpenStack with command B<glance image-create>. It sets the property in the image to indicate that this is an xCAT image and also stores the original xCAT image name in the property for further reference.
The xCAT image names can be listed using B<lsdef -t osimage> command.
=head1 Parameters
I<image1,image1...> a comma separated xCAT images names.
=head1 OPTIONS
=over 10
=item B<-n> a comma separated new image names in the OpenStack. If omitted, the default is the original xCAT image nanme.
=item B<-c> the node name of the OpenStack controller. This node must be an xCAT managed node.
=item B<-h|--help> Display usage message.
=item B<-v|--version> The Command Version.
=back
=head1 RETURN VALUE
0 The command completed successfully.
1 An error has occurred.
=head1 EXAMPLES
=over 3
=item 1.
To register xCAT image rhels6.3-x86_64-install-compute into OpenStack.
opsaddimage rhels6.3-x86_64-install-compute -c sv2
=back
=head1 FILES
/opt/xcat/bin/opsaddimage
=head1 SEE ALSO
L<opsaddbmnode(1)|opsaddbmnode.1>

View File

@ -0,0 +1,215 @@
#!/bin/sh
# IBM(c) 2014 EPL license http://www.eclipse.org/legal/epl-v10.html
# xCAT post script for configuring the openstack baremetal node.
# The format is:
# config_ops_bm_node ops_hostname ops_ip ops_netmask
get_os_type()
{
#get os type
str_os_type=`uname | tr 'A-Z' 'a-z'`
str_temp=''
if [ "$str_os_type" = "linux" ];then
str_temp=`echo $OSVER | grep -E '(sles|suse)'`
if [ -f "/etc/debian_version" ];then
str_os_type="debian"
elif [ -f "/etc/SuSE-release" -o -n "$str_temp" ];then
str_os_type="sles"
else
str_os_type="redhat"
fi
else
str_os_type="aix"
fi
echo "$str_os_type"
}
setup_ip()
{
str_os_type=$1
str_if_name=$2
str_v4ip=$3
str_v4mask=$4
ret=`ifconfig $str_if_name |grep "inet addr" 2>&1`
if [ $? -eq 0 ]; then
old_ip=`echo $ret|cut -d':' -f2 |cut -d' ' -f1`
old_mask=`echo $ret|cut -d':' -f4`
#echo "old ip = $old_ip, old mask=$old_mask"
if [ "$old_ip" == "$str_v4ip" -a "$old_mask" == "$str_v4mask" ]; then
#if nic is up and the address is the same, then donothing
#echo "do nothing"
exit 0
else
#bring down the nic and reconstruct it.
#echo "bring down the old nic"
ifconfig $str_if_name del $old_ip
fi
fi
if [ "$str_os_type" = "sles" ];then
str_conf_file="/etc/sysconfig/network/ifcfg-${str_if_name}"
if [ -f $str_conf_file ]; then
rm $str_conf_file
fi
echo "DEVICE=${str_if_name}" > $str_conf_file
echo "BOOTPROTO=static" >> $str_conf_file
echo "IPADDR=${str_v4ip}" >> $str_conf_file
echo "NETMASK=${str_v4mask}" >> $str_conf_file
echo "NETWORK=''" >> $str_conf_file
echo "STARTMODE=onboot" >> $str_conf_file
echo "USERCONTROL=no" >> $str_conf_file
ifup $str_if_name
#debian ubuntu
elif [ "$str_os_type" = "debian" ];then
str_conf_file="/etc/network/interfaces.d/${str_if_name}"
if [ -f $str_conf_file ]; then
rm $str_conf_file
fi
echo "auto ${str_if_name}" > $str_conf_file
echo "iface ${str_if_name} inet static" >> $str_conf_file
echo " address ${str_v4ip}" >> $str_conf_file
echo " netmask ${str_v4mask}" >> $str_conf_file
ifconfig $str_if_name up
else
# Write the info to the ifcfg file for redhat
str_conf_file="/etc/sysconfig/network-scripts/ifcfg-${str_if_name}"
if [ -f $str_conf_file ]; then
rm $str_conf_file
fi
echo "DEVICE=${str_if_name}" > $str_conf_file
echo "BOOTPROTO=static" >> $str_conf_file
echo "NM_CONTROLLED=no" >> $str_conf_file
echo "IPADDR=${str_v4ip}" >> $str_conf_file
echo "NETMASK=${str_v4mask}" >> $str_conf_file
echo "ONBOOT=yes" >> $str_conf_file
ifup $str_if_name
fi
}
#change hostname permanently
change_host_name()
{
str_os_type=$1
str_hostname=$2
hostname $str_hostname
if [ "$str_os_type" = "sles" ];then
echo "Persistently changing the hostname not implemented yet."
#debian ubuntu
elif [ "$str_os_type" = "debian" ];then
conf_file="/etc/hostname"
echo "$str_hostname" > $conf_file
else
conf_file="/etc/sysconfig/network"
if [ ! -f $conf_file ]; then
touch $conf_file
fi
grep 'HOSTNAME' $conf_file 2>&1 > /dev/null
if [ $? -eq 0 ]; then
sed -i "s/HOSTNAME=.*/HOSTNAME=$str_hostname/" $conf_file
else
echo "HOSTNAME=$str_hostname" >> $conf_file
fi
fi
}
str_os_type=$(get_os_type)
echo "os_type=$str_os_type"
if [ "$str_os_type" = "aix" ]; then
logger -t xcat "config_ops_bm_node dose not support AIX."
echo "config_ops_bm_node dose not support AIX."
exit 0
fi
#change the hostname
if [[ -n "$1" ]]; then
change_host_name $str_os_type $1
fi
#Add the openstack ip to the node
if [[ -n $2 ]]; then
ops_ip=$2
if [[ -z $3 ]]; then
logger -t xcat "config_ops_bm_node: Please specify the netmask."
echo "config_ops_bm_node: Please specify the netmask."
exit 1
else
ops_mask=$3
fi
#figure out the install nic
if [[ -n $MACADDRESS ]]; then
pos=0
#mac has the following format: 01:02:03:04:05:0E!node5|01:02:03:05:0F!node6-eth1
for x in `echo "$MACADDRESS" | tr "|" "\n"`
do
node=""
mac=""
pos=$((pos+1))
i=`expr index $x !`
if [[ $i -gt 0 ]]; then
node=`echo ${x##*!}`
mac_tmp=`echo ${x%%!*}`
else
mac_tmp=$x
fi
if [[ $pos -eq 1 ]]; then
mac1=$mac_tmp
fi
if [[ "$PRIMARYNIC" = "$mac_tmp" ]]; then
mac=$mac_tmp
break
fi
if [[ -z "$PRIMARYNIC" ]] || [[ "$PRIMARYNIC" = "mac" ]]; then
if [[ -z $node ]] || [[ "$node" = "$NODE" ]]; then
mac=$mac_tmp
break
fi
fi
done
if [[ -z $mac ]]; then
if [[ -z "$PRIMARYNIC" ]] || [[ "$PRIMARYNIC" = "mac" ]]; then
mac=$mac1 #if nothing mathes, take the first mac
else
nic=$PRIMARYNIC #or the primary nic itself is the nic
fi
fi
else
logger -t xcat "config_ops_bm_node: no mac addresses are defined in the mac table for the node $NODE"
echo "config_ops_bm_node: no mac addresses are defined in the mac table for the node $NODE"
index=$((index+1))
continue
fi
echo "mac=$mac"
#find the nic that has the mac
if [[ -z $nic ]]; then
#go to each nic to match the mac address
ret=`ifconfig |grep -i $mac 2>&1`;
if [ $? -eq 0 ]; then
nic=`echo $ret |head -n1|cut -d' ' -f 1`
else
logger -t xcat "config_ops_bm_node: The mac address for the network for $NODE is not defined."
echo "config_ops_bm_node: The mac address for the network for $NODE is not defined."
fi
fi
echo "nic=$nic"
#now setup the ip alias
setup_ip $str_os_type $nic:0 $ops_ip $ops_mask
fi

View File

@ -0,0 +1,94 @@
#!/bin/sh
# IBM(c) 2014 EPL license http://www.eclipse.org/legal/epl-v10.html
# xCAT post script for deconfiguring the openstack baremetal node.
# The format is:
# deconfig_ops_bm_node ops_ip
get_os_type()
{
#get os type
str_os_type=`uname | tr 'A-Z' 'a-z'`
str_temp=''
if [ "$str_os_type" = "linux" ];then
str_temp=`echo $OSVER | grep -E '(sles|suse)'`
if [ -f "/etc/debian_version" ];then
str_os_type="debian"
elif [ -f "/etc/SuSE-release" -o -n "$str_temp" ];then
str_os_type="sles"
else
str_os_type="redhat"
fi
else
str_os_type="aix"
fi
echo "$str_os_type"
}
#change hostname permanently
change_host_name()
{
str_os_type=$1
str_hostname=$2
hostname $str_hostname
if [ "$str_os_type" = "sles" ];then
echo "Persistently changing the hostname not implemented yet."
#debian ubuntu
elif [ "$str_os_type" = "debian" ];then
conf_file="/etc/hostname"
echo "$str_hostname" > $conf_file
else
conf_file="/etc/sysconfig/network"
if [ ! -f $conf_file ]; then
touch $conf_file
fi
grep 'HOSTNAME' $conf_file 2>&1 > /dev/null
if [ $? -eq 0 ]; then
sed -i "s/HOSTNAME=.*/HOSTNAME=$str_hostname/" $conf_file
else
echo "HOSTNAME=$str_hostname" >> $conf_file
fi
fi
}
str_os_type=$(get_os_type)
echo "os_type=$str_os_type"
if [ $str_os_type == "aix" ]; then
logger -t xcat "deconfig_ops_bm_node dose not support AIX."
echo "deconfig_ops_bm_node dose not support AIX."
exit 0
fi
#change the hostname
#hostname $NODE
change_host_name $str_os_type $NODE
#remove the openstack ip from the node
if [[ -n $1 ]]; then
ops_ip=$1
nic=$(ip addr | grep $ops_ip | awk '{print $NF}')
echo "nic=$nic, ops_ip=$ops_ip"
ifconfig $nic del $ops_ip
#delete the configuration file
if [ "$str_os_type" = "sles" ]; then
str_conf_file="/etc/sysconfig/network/ifcfg-$nic"
elif [ "$str_os_type" = "debian" ]; then #debian ubuntu
str_conf_file="/etc/network/interfaces.d/$nic"
else #redhat
str_conf_file="/etc/sysconfig/network-scripts/ifcfg-$nic"
fi
if [ -f $str_conf_file ]; then
rm $str_conf_file
fi
fi

View File

@ -0,0 +1,102 @@
Summary: Executables and data of the xCAT baremetal driver for OpenStack
Name: xCAT-OpenStack-baremetal
Version: %(cat Version)
Release: snap%(date +"%Y%m%d%H%M")
Epoch: 4
License: IBM
Group: Applications/System
Source: xCAT-OpenStack-baremetal-%{version}.tar.gz
Packager: IBM Corp.
Vendor: IBM Corp.
Distribution: %{?_distribution:%{_distribution}}%{!?_distribution:%{_vendor}}
Prefix: /opt/xcat
BuildRoot: /var/tmp/%{name}-%{version}-%{release}-root
%ifos linux
BuildArch: noarch
%endif
Provides: xCAT-OpenStack-baremetal = %{epoch}:%{version}
Requires: xCAT-client
%description
xCAT-OpenStack-baremetal provides the baremetal driver for OpenStack.
%prep
%setup -q -n xCAT-OpenStack-baremetal
%build
# Convert pods to man pages and html pages
./xpod2man
%install
# The install phase puts all of the files in the paths they should be in when the rpm is
# installed on a system. The RPM_BUILD_ROOT is a simulated root file system and usually
# has a value like: /var/tmp/xCAT-OpenStack-baremetal-2.0-snap200802270932-root
rm -rf $RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT/%{prefix}/bin
mkdir -p $RPM_BUILD_ROOT/%{prefix}/sbin
mkdir -p $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT_plugin
mkdir -p $RPM_BUILD_ROOT/%{prefix}/lib/python/xcat/openstack/baremetal
mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/xcat/openstack/postscripts
mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/man/man1
mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/doc/man1
set +x
cp -R lib/* $RPM_BUILD_ROOT/%{prefix}/lib
cp share/xcat/openstack/postscripts/* $RPM_BUILD_ROOT/%{prefix}/share/xcat/openstack/postscripts
# These were built dynamically in the build phase
cp share/man/man1/* $RPM_BUILD_ROOT/%{prefix}/share/man/man1
chmod 444 $RPM_BUILD_ROOT/%{prefix}/share/man/man1/*
# These were built dynamically during the build phase
cp share/doc/man1/* $RPM_BUILD_ROOT/%{prefix}/share/doc/man1
chmod 644 $RPM_BUILD_ROOT/%{prefix}/share/doc/man1/*
# These links get made in the RPM_BUILD_ROOT/prefix area
ln -sf ../bin/xcatclient $RPM_BUILD_ROOT/%{prefix}/sbin/deploy_ops_bm_node
ln -sf ../bin/xcatclient $RPM_BUILD_ROOT/%{prefix}/sbin/cleanup_ops_bm_node
ln -sf ../bin/xcatclient $RPM_BUILD_ROOT/%{prefix}/bin/opsaddbmnode
ln -sf ../bin/xcatclientnnr $RPM_BUILD_ROOT/%{prefix}/bin/opsaddimage
set -x
%clean
# This step does not happen until *after* the %files packaging below
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
#%doc LICENSE.html
# Just package everything that has been copied into RPM_BUILD_ROOT
%{prefix}
%changelog
%post
#copy the postscripts under /installl/postscripts directory on MN only
if [ -f "/etc/xCATMN" ]; then
cp $RPM_INSTALL_PREFIX0/share/xcat/openstack/postscripts/* /install/postscripts/
fi
%preun
#remove postscripts under /installl/postscripts directory on MN only
if [ -f "/etc/xCATMN" ]; then
for fn in $RPM_INSTALL_PREFIX0/share/xcat/openstack/postscripts/*
do
bn=`basename $fn`
rm /install/postscripts/$bn
done
fi
exit 0

214
xCAT-OpenStack-baremetal/xpod2man Executable file
View File

@ -0,0 +1,214 @@
#!/usr/bin/perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
# First builds the xCAT summary man page from Synopsis of each man page.
# Then converts all of the pod man pages into html (including links to each other)
# We assume that this script is run in the xCAT-vlan-2.0 dir, so everything is
# done relative to that.
use strict;
#use lib '.';
use Pod::Man;
use Pod::Html;
my $poddir = 'pods';
my $mandir = 'share/man';
my $htmldir = 'share/doc';
my $cachedir = '/tmp';
my @pods = getPodList($poddir);
#foreach (@pods) { print "$_\n"; } exit;
# Build the cmd overview page.
#writesummarypage("$poddir/man1/xcat.1.pod", @pods);
# Build the man page for each pod.
#mkdir($mandir) or die "Error: could not create $mandir.\n";
print "Converting PODs to man pages...\n";
foreach my $podfile (@pods) {
my $manfile = $podfile;
$manfile =~ s/^$poddir/$mandir/; # change the beginning of the path
$manfile =~ s/\.pod$//; # change the ending
my $mdir = $manfile;
$mdir =~ s|/[^/]*$||; # get rid of the basename part
if (system("mkdir -p $mdir")) { die "Error: could not create $mdir.\n"; }
my ($section) = $podfile =~ /\.(\d+)\.pod$/;
convertpod2man($podfile, $manfile, $section);
}
my @dummyPods = createDummyPods($poddir, \@pods);
# Build the html page for each pod.
#mkdir($htmldir) or die "Error: could not create $htmldir.\n";
print "Converting PODs to HTML pages...\n";
# have to clear the cache, because old entries can cause a problem
unlink("$cachedir/pod2htmd.tmp", "$cachedir/pod2htmi.tmp");
foreach my $podfile (@pods) {
my $htmlfile = $podfile;
$htmlfile =~ s/^$poddir/$htmldir/; # change the beginning of the path
$htmlfile =~ s/\.pod$/\.html/; # change the ending
my $hdir = $htmlfile;
$hdir =~ s|/[^/]*$||; # get rid of the basename part
if (system("mkdir -p $hdir")) { die "Error: could not create $hdir.\n"; }
#print "$podfile, $htmlfile, $poddir, $htmldir\n";
convertpod2html($podfile, $htmlfile, $poddir, $htmldir);
}
# Remove the dummy pods
unlink @dummyPods;
rmdir "$poddir/man7";
exit;
# To enable linking between the cmd man pages and the db man pages, need to:
# grep thru the cmd pods searching for references (L<>) to any section 5 man page
# if that pod does not exist, create an empty one that will satisfy pod2html
# keep track of all dummy pods created, so they can be removed later
sub createDummyPods {
my ($poddir, $pods) = @_;
my $cmd = "grep -r -E 'L<.+\\([57]\\)\\|.+\\.[57]>' " . $poddir;
#print "Running cmd: ", $cmd, "\n";
my @lines = `$cmd`;
if ($?) { print "Error running: $cmd\n"; print join('', @lines); }
#my @lines;
#system($cmd);
my @dummyPods;
foreach my $l (@lines) {
#print "$l\n";
my @matches = $l =~ /L<([^\(]+)\(([57])\)\|\1\.[57]>/g; # get all the matches in the line
# The above line should create the array with every other entry being the man page name
# and every other entry is the section # (5 or 7)
my $cmd;
while ($cmd=shift @matches) {
#foreach my $m (@matches) {
my $section = shift @matches;
my $filename = "$poddir/man$section/$cmd.$section.pod";
#print "$filename\n";
if (!(grep /^$filename$/, @$pods) && !(grep /^$filename$/, @dummyPods)) { push @dummyPods, $filename; }
}
}
# Create these empty files
print "Creating empty linked-to files: ", join(', ', @dummyPods), "\n";
mkdir "$poddir/man7";
foreach my $d (@dummyPods) {
if (!open(TMP, ">>$d")) { warn "Could not create dummy pod file $d ($!)\n"; }
else { close TMP; }
}
return @dummyPods;
}
# Recursively get the list of pod man page files.
sub getPodList {
my $poddir = shift;
my @files;
# 1st get toplevel dir listing
opendir(DIR, $poddir) or die "Error: could not read $poddir.\n";
my @topdir = grep !/^\./, readdir(DIR); # /
close(DIR);
# Now go thru each subdir (these are man1, man3, etc.)
foreach my $mandir (@topdir) {
opendir(DIR, "$poddir/$mandir") or die "Error: could not read $poddir/$mandir.\n";
my @dir = grep !/^\./, readdir(DIR); # /
close(DIR);
foreach my $file (@dir) {
push @files, "$poddir/$mandir/$file";
}
}
return sort @files;
}
# Create the xcat man page that gives a summary description of each xcat cmd.
# Not used.
sub writesummarypage {
my $file = shift; # relative path file name of the man page
# the rest of @_ contains the pod files that describe each cmd
open(FILE, ">$file") or die "Error: could not open $file for writing.\n";
print FILE <<'EOS1';
=head1 NAME
B<xcat> - extreme Cluster Administration Tool.
=head1 DESCRIPTION
Extreme Cluster Administration Toolkit (xCAT). xCAT is a scalable distributed computing management
and provisioning tool that provides a unified interface for hardware control, discovery, and
OS diskful/diskfree deployment.
=head1 XCAT DATABASE
All of the cluster configuration information is in the xCAT database. See L<xcatdb(5)|xcatdb.5> for
descriptions of every table in the database.
=head1 XCAT COMMANDS
What follows is a short description of each xCAT command. To get more information about a particular
command, see its man page. Note that the commands are listed in alphabetical order B<within each section>,
i.e. all the commands in section 1, then the commands in section 3, etc.
=over 12
EOS1
# extract the summary for each cmd from its man page
foreach my $manpage (@_) {
my ($sectionnum) = $manpage =~ /\.(\d+)\.pod$/;
# Suck in the whole file, then we will parse it.
open(MANPAGE, "$manpage") or die "Error: could not open $manpage for reading.\n";
my @contents = <MANPAGE>;
my $wholemanpage = join('', @contents);
close(MANPAGE);
# This regex matches: optional space, =head1, space, title, space, cmd, space, description, newline
my ($cmd, $description) = $wholemanpage =~ /^\s*=head1\s+\S+\s+(\S+)\s+(.+?)\n/si;
if (!defined($cmd)) { print "Warning: $manpage is not in a recognized structure. It will be ignored.\n"; next; }
if (!defined($description)) { print "Warning: $manpage does not have a description for $cmd. It will be ignored.\n"; next; }
$cmd =~ s/^.<(.+)>$/$1/; # if the cmd name has pod formatting around it, strip it off
$description =~ s/^-\s*//; # if the description has a leading hypen, strip it off
print FILE "\n=item L<$cmd($sectionnum)|$cmd.$sectionnum>\n\n".$description."\n";
}
# Artificially add the xcattest cmd, because the xCAT-test rpm will add this
print FILE "\n=item L<xcattest(1)|xcattest.1>\n\nRun automated xCAT test cases.\n";
print FILE <<"EOS3";
=back
EOS3
close FILE;
}
# Create the html page for one pod.
sub convertpod2html {
my ($podfile, $htmlfile, $poddir, $htmldir) = @_;
#TODO: use --css=<stylesheet> and --title=<pagetitle> to make the pages look better
pod2html($podfile,
"--outfile=$htmlfile",
"--podpath=man1",
"--podroot=$poddir",
"--htmldir=$htmldir",
"--recurse",
"--cachedir=$cachedir",
);
}
# Create the man page for one pod.
sub convertpod2man {
my ($podfile, $manfile, $section) = @_;
my $parser = Pod::Man->new(section => $section);
$parser->parse_from_file($podfile, $manfile);
}

326
xCAT-SoftLayer/LICENSE.html Normal file
View File

@ -0,0 +1,326 @@
<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:w="urn:schemas-microsoft-com:office:word"
xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
<meta name=ProgId content=Word.Document>
<meta name=Generator content="Microsoft Word 9">
<meta name=Originator content="Microsoft Word 9">
<title>Eclipse Public License - Version 1.0</title>
<!--[if gte mso 9]><xml>
<o:DocumentProperties>
<o:Revision>2</o:Revision>
<o:TotalTime>3</o:TotalTime>
<o:Created>2004-03-05T23:03:00Z</o:Created>
<o:LastSaved>2004-03-05T23:03:00Z</o:LastSaved>
<o:Pages>4</o:Pages>
<o:Words>1626</o:Words>
<o:Characters>9270</o:Characters>
<o:Lines>77</o:Lines>
<o:Paragraphs>18</o:Paragraphs>
<o:CharactersWithSpaces>11384</o:CharactersWithSpaces>
<o:Version>9.4402</o:Version>
</o:DocumentProperties>
</xml><![endif]--><!--[if gte mso 9]><xml>
<w:WordDocument>
<w:TrackRevisions/>
</w:WordDocument>
</xml><![endif]-->
<style>
<!--
/* Font Definitions */
@font-face
{font-family:Tahoma;
panose-1:2 11 6 4 3 5 4 4 2 4;
mso-font-charset:0;
mso-generic-font-family:swiss;
mso-font-pitch:variable;
mso-font-signature:553679495 -2147483648 8 0 66047 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-parent:"";
margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";}
p
{margin-right:0in;
mso-margin-top-alt:auto;
mso-margin-bottom-alt:auto;
margin-left:0in;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";}
p.BalloonText, li.BalloonText, div.BalloonText
{mso-style-name:"Balloon Text";
margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:8.0pt;
font-family:Tahoma;
mso-fareast-font-family:"Times New Roman";}
@page Section1
{size:8.5in 11.0in;
margin:1.0in 1.25in 1.0in 1.25in;
mso-header-margin:.5in;
mso-footer-margin:.5in;
mso-paper-source:0;}
div.Section1
{page:Section1;}
-->
</style>
</head>
<body lang=EN-US style='tab-interval:.5in'>
<div class=Section1>
<p align=center style='text-align:center'><b>Eclipse Public License - v 1.0</b>
</p>
<p><span style='font-size:10.0pt'>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER
THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (&quot;AGREEMENT&quot;). ANY USE,
REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE
OF THIS AGREEMENT.</span> </p>
<p><b><span style='font-size:10.0pt'>1. DEFINITIONS</span></b> </p>
<p><span style='font-size:10.0pt'>&quot;Contribution&quot; means:</span> </p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
in the case of the initial Contributor, the initial code and documentation
distributed under this Agreement, and<br clear=left>
b) in the case of each subsequent Contributor:</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>i)
changes to the Program, and</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>ii)
additions to the Program;</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>where
such changes and/or additions to the Program originate from and are distributed
by that particular Contributor. A Contribution 'originates' from a Contributor
if it was added to the Program by such Contributor itself or anyone acting on
such Contributor's behalf. Contributions do not include additions to the
Program which: (i) are separate modules of software distributed in conjunction
with the Program under their own license agreement, and (ii) are not derivative
works of the Program. </span></p>
<p><span style='font-size:10.0pt'>&quot;Contributor&quot; means any person or
entity that distributes the Program.</span> </p>
<p><span style='font-size:10.0pt'>&quot;Licensed Patents &quot; mean patent
claims licensable by a Contributor which are necessarily infringed by the use
or sale of its Contribution alone or when combined with the Program. </span></p>
<p><span style='font-size:10.0pt'>&quot;Program&quot; means the Contributions
distributed in accordance with this Agreement.</span> </p>
<p><span style='font-size:10.0pt'>&quot;Recipient&quot; means anyone who
receives the Program under this Agreement, including all Contributors.</span> </p>
<p><b><span style='font-size:10.0pt'>2. GRANT OF RIGHTS</span></b> </p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
Subject to the terms of this Agreement, each Contributor hereby grants Recipient
a non-exclusive, worldwide, royalty-free copyright license to<span
style='color:red'> </span>reproduce, prepare derivative works of, publicly
display, publicly perform, distribute and sublicense the Contribution of such
Contributor, if any, and such derivative works, in source code and object code
form.</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b)
Subject to the terms of this Agreement, each Contributor hereby grants
Recipient a non-exclusive, worldwide,<span style='color:green'> </span>royalty-free
patent license under Licensed Patents to make, use, sell, offer to sell, import
and otherwise transfer the Contribution of such Contributor, if any, in source
code and object code form. This patent license shall apply to the combination
of the Contribution and the Program if, at the time the Contribution is added
by the Contributor, such addition of the Contribution causes such combination
to be covered by the Licensed Patents. The patent license shall not apply to
any other combinations which include the Contribution. No hardware per se is
licensed hereunder. </span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>c)
Recipient understands that although each Contributor grants the licenses to its
Contributions set forth herein, no assurances are provided by any Contributor
that the Program does not infringe the patent or other intellectual property
rights of any other entity. Each Contributor disclaims any liability to Recipient
for claims brought by any other entity based on infringement of intellectual
property rights or otherwise. As a condition to exercising the rights and
licenses granted hereunder, each Recipient hereby assumes sole responsibility
to secure any other intellectual property rights needed, if any. For example,
if a third party patent license is required to allow Recipient to distribute
the Program, it is Recipient's responsibility to acquire that license before
distributing the Program.</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>d)
Each Contributor represents that to its knowledge it has sufficient copyright
rights in its Contribution, if any, to grant the copyright license set forth in
this Agreement. </span></p>
<p><b><span style='font-size:10.0pt'>3. REQUIREMENTS</span></b> </p>
<p><span style='font-size:10.0pt'>A Contributor may choose to distribute the
Program in object code form under its own license agreement, provided that:</span>
</p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
it complies with the terms and conditions of this Agreement; and</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b)
its license agreement:</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>i)
effectively disclaims on behalf of all Contributors all warranties and
conditions, express and implied, including warranties or conditions of title
and non-infringement, and implied warranties or conditions of merchantability
and fitness for a particular purpose; </span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>ii)
effectively excludes on behalf of all Contributors all liability for damages,
including direct, indirect, special, incidental and consequential damages, such
as lost profits; </span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>iii)
states that any provisions which differ from this Agreement are offered by that
Contributor alone and not by any other party; and</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>iv)
states that source code for the Program is available from such Contributor, and
informs licensees how to obtain it in a reasonable manner on or through a
medium customarily used for software exchange.<span style='color:blue'> </span></span></p>
<p><span style='font-size:10.0pt'>When the Program is made available in source
code form:</span> </p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
it must be made available under this Agreement; and </span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b) a
copy of this Agreement must be included with each copy of the Program. </span></p>
<p><span style='font-size:10.0pt'>Contributors may not remove or alter any
copyright notices contained within the Program. </span></p>
<p><span style='font-size:10.0pt'>Each Contributor must identify itself as the
originator of its Contribution, if any, in a manner that reasonably allows
subsequent Recipients to identify the originator of the Contribution. </span></p>
<p><b><span style='font-size:10.0pt'>4. COMMERCIAL DISTRIBUTION</span></b> </p>
<p><span style='font-size:10.0pt'>Commercial distributors of software may
accept certain responsibilities with respect to end users, business partners
and the like. While this license is intended to facilitate the commercial use
of the Program, the Contributor who includes the Program in a commercial
product offering should do so in a manner which does not create potential
liability for other Contributors. Therefore, if a Contributor includes the
Program in a commercial product offering, such Contributor (&quot;Commercial
Contributor&quot;) hereby agrees to defend and indemnify every other
Contributor (&quot;Indemnified Contributor&quot;) against any losses, damages and
costs (collectively &quot;Losses&quot;) arising from claims, lawsuits and other
legal actions brought by a third party against the Indemnified Contributor to
the extent caused by the acts or omissions of such Commercial Contributor in
connection with its distribution of the Program in a commercial product
offering. The obligations in this section do not apply to any claims or Losses
relating to any actual or alleged intellectual property infringement. In order
to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
Contributor in writing of such claim, and b) allow the Commercial Contributor
to control, and cooperate with the Commercial Contributor in, the defense and
any related settlement negotiations. The Indemnified Contributor may participate
in any such claim at its own expense.</span> </p>
<p><span style='font-size:10.0pt'>For example, a Contributor might include the
Program in a commercial product offering, Product X. That Contributor is then a
Commercial Contributor. If that Commercial Contributor then makes performance
claims, or offers warranties related to Product X, those performance claims and
warranties are such Commercial Contributor's responsibility alone. Under this
section, the Commercial Contributor would have to defend claims against the
other Contributors related to those performance claims and warranties, and if a
court requires any other Contributor to pay any damages as a result, the
Commercial Contributor must pay those damages.</span> </p>
<p><b><span style='font-size:10.0pt'>5. NO WARRANTY</span></b> </p>
<p><span style='font-size:10.0pt'>EXCEPT AS EXPRESSLY SET FORTH IN THIS
AGREEMENT, THE PROGRAM IS PROVIDED ON AN &quot;AS IS&quot; BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,
WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
responsible for determining the appropriateness of using and distributing the
Program and assumes all risks associated with its exercise of rights under this
Agreement , including but not limited to the risks and costs of program errors,
compliance with applicable laws, damage to or loss of data, programs or
equipment, and unavailability or interruption of operations. </span></p>
<p><b><span style='font-size:10.0pt'>6. DISCLAIMER OF LIABILITY</span></b> </p>
<p><span style='font-size:10.0pt'>EXCEPT AS EXPRESSLY SET FORTH IN THIS
AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF
THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGES.</span> </p>
<p><b><span style='font-size:10.0pt'>7. GENERAL</span></b> </p>
<p><span style='font-size:10.0pt'>If any provision of this Agreement is invalid
or unenforceable under applicable law, it shall not affect the validity or
enforceability of the remainder of the terms of this Agreement, and without
further action by the parties hereto, such provision shall be reformed to the
minimum extent necessary to make such provision valid and enforceable.</span> </p>
<p><span style='font-size:10.0pt'>If Recipient institutes patent litigation
against any entity (including a cross-claim or counterclaim in a lawsuit)
alleging that the Program itself (excluding combinations of the Program with
other software or hardware) infringes such Recipient's patent(s), then such
Recipient's rights granted under Section 2(b) shall terminate as of the date
such litigation is filed. </span></p>
<p><span style='font-size:10.0pt'>All Recipient's rights under this Agreement
shall terminate if it fails to comply with any of the material terms or
conditions of this Agreement and does not cure such failure in a reasonable
period of time after becoming aware of such noncompliance. If all Recipient's
rights under this Agreement terminate, Recipient agrees to cease use and
distribution of the Program as soon as reasonably practicable. However,
Recipient's obligations under this Agreement and any licenses granted by
Recipient relating to the Program shall continue and survive. </span></p>
<p><span style='font-size:10.0pt'>Everyone is permitted to copy and distribute
copies of this Agreement, but in order to avoid inconsistency the Agreement is
copyrighted and may only be modified in the following manner. The Agreement
Steward reserves the right to publish new versions (including revisions) of
this Agreement from time to time. No one other than the Agreement Steward has
the right to modify this Agreement. The Eclipse Foundation is the initial
Agreement Steward. The Eclipse Foundation may assign the responsibility to
serve as the Agreement Steward to a suitable separate entity. Each new version
of the Agreement will be given a distinguishing version number. The Program
(including Contributions) may always be distributed subject to the version of
the Agreement under which it was received. In addition, after a new version of
the Agreement is published, Contributor may elect to distribute the Program
(including its Contributions) under the new version. Except as expressly stated
in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to
the intellectual property of any Contributor under this Agreement, whether
expressly, by implication, estoppel or otherwise. All rights in the Program not
expressly granted under this Agreement are reserved.</span> </p>
<p><span style='font-size:10.0pt'>This Agreement is governed by the laws of the
State of New York and the intellectual property laws of the United States of
America. No party to this Agreement will bring a legal action under this
Agreement more than one year after the cause of action arose. Each party waives
its rights to a jury trial in any resulting litigation.</span> </p>
<p class=MsoNormal><![if !supportEmptyParas]>&nbsp;<![endif]><o:p></o:p></p>
</div>
</body>
</html>

120
xCAT-SoftLayer/bin/getslnodes Executable file
View File

@ -0,0 +1,120 @@
#!/usr/bin/perl
# Query the softlayer account for info about all of the bare metal servers and
# put the info in mkdef stanza format, so the node can be defined in the xcat db
# so that xcat can manage/deploy them.
use strict;
use Getopt::Long;
use Data::Dumper;
#$Data::Dumper::Maxdepth=2;
# Globals - these are set once and then only read.
my $HELP;
my $VERBOSE;
my %CONFIG; # attributes read from config file
my $usage = sub {
my $exitcode = shift @_;
print "Usage: getslnodes [-?|-h|--help] [-v|--verbose] [<hostname-match>]\n\n";
if (!$exitcode) {
print "getslnodes queries your SoftLayer account and gets attributes for each\n";
print "server. The attributes can be piped to 'mkdef -z' to define the nodes\n";
print "in the xCAT DB so that xCAT can manage them. getslnodes\n";
print "requires a .slconfig file in your home directory that contains your\n";
print "SoftLayer userid, API key, and location of API perl module, in attr=val format.\n";
}
exit $exitcode;
};
# Process the cmd line args
Getopt::Long::Configure("bundling");
#Getopt::Long::Configure("pass_through");
Getopt::Long::Configure("no_pass_through");
if (!GetOptions('h|?|help' => \$HELP, 'v|verbose' => \$VERBOSE)) { $usage->(1); }
if ($HELP) { $usage->(0); }
if (scalar(@ARGV)>1) { $usage->(1); }
my $hnmatch = $ARGV[0]; # if they specified a hostname match, only show svrs that start with that
readconf("$ENV{HOME}/.slconfig"); # get the userid and api key from the config file
#my $api_username = 'SL276540';
#my $api_key = '799d5d9267a927a330ec016f00bfe17e6fc532d203cf68b3b0d997b2d27a3ce1';
my $slinstalled = eval { push @INC, $CONFIG{apidir}; require SoftLayer::API::SOAP; };
if (!$slinstalled) { die "Error: the SoftLayer::API::SOAP perl module is not installed. Download it using 'git clone https://github.com/softlayer/softlayer-api-perl-client' and put the directory in ~/.slconfig ."; }
my $client = SoftLayer::API::SOAP->new('SoftLayer_Account', undef, $CONFIG{userid}, $CONFIG{apikey});
my $mask = "mask[operatingSystem.passwords,remoteManagementAccounts,remoteManagementComponent,backendNetworkComponents]";
$client->setObjectMask($mask);
#print $client->fault;
#print $client->faultstring;
#print "\n";
my $hw = $client->getHardware();
my $servers = $hw->result;
foreach my $server (@$servers) {
if ($server->{fullyQualifiedDomainName} =~ m/$hnmatch/) {
print "\n".$server->{hostname}.":\n";
print "\tobjtype=node\n";
print "\tgroups=slnode,ipmi,all\n";
print "\tmgt=ipmi\n";
print "\tbmc=".$server->{remoteManagementComponent}->{ipmiIpAddress}."\n";
print "\tbmcusername=".$server->{remoteManagementAccounts}->[0]->{username}."\n";
print "\tbmcpassword=".$server->{remoteManagementAccounts}->[0]->{password}."\n";
print "\tmac=".$server->{backendNetworkComponents}->[0]->{macAddress}."\n";
print "\tip=".$server->{privateIpAddress}."\n";
print "\tnetboot=xnba\n";
print "\tarch=x86_64\n";
print "\tusercomment=hostname:".$server->{fullyQualifiedDomainName}.", user:".$server->{operatingSystem}->{passwords}->[0]->{username}.", pw:".$server->{operatingSystem}->{passwords}->[0]->{password}."\n";
#print Dumper($server->{remoteManagementAccounts});
#print "#Softlayer_account_info_for ".$server->{fullyQualifiedDomainName} . " Username: ";
#print $server->{operatingSystem}->{passwords}->[0]->{username} . " Password: ";
#print $server->{operatingSystem}->{passwords}->[0]->{password}. "\n";
#print "nodeadd ".$server->{hostname}." groups=saptest ipmi.password=".$server->{remoteManagementAccounts}->[0]->{password}." ipmi.bmc=".$server->{remoteManagementComponent}->{ipmiIpAddress};
#print " mac.mac=".$server->{backendNetworkComponents}->[0]->{macAddress};
#print " hosts.ip=".$server->{privateIpAddress} ."\n";
}
}
exit(0);
# Pring msg only if -v was specified
sub verbose { if ($VERBOSE) { print shift, "\n"; } }
# Read the config file. Format is attr=val on each line. Should contain at leas the userid and apikey.
# This function fills in the global %CONFIG hash.
sub readconf {
my $conffile = shift @_;
open(FILE, $conffile) || die "Error: can not open config file $conffile: $!\n";
while (<FILE>) {
my $line = $_;
chomp($line);
if ($line =~ /^#/ || $line =~/^\s*$/) { next; } # skip comment lines
my ($key, $value) = split(/\s*=\s*/, $line, 2);
if (!defined($value)) { die "Error: line '$line' does not have format attribute=value\n"; }
$CONFIG{$key} = $value;
}
close FILE;
verbose('%CONFIG hash: ' . Dumper(\%CONFIG));
# the config file needs to contain at least the userid and api key
if (!defined($CONFIG{userid}) || !defined($CONFIG{apikey}) || !defined($CONFIG{apidir})) {
die "Error: the config file must contain values for userid, apikey, and apidir.\n";
}
}
#$mask = "mask[operatingSystem.passwords]";
#$client->setObjectMask($mask);
#my $vs = $client->getVirtualGuests();
#my $servers = $vs->result;
#foreach my $server (@$servers) {
# if ($server->{fullyQualifiedDomainName} eq "xcat1-sap.saptest.ibm.com") {
# print $server->{primaryIpAddress}."\n";
# print $server->{operatingSystem}->{passwords}->[0]->{password}."\n";
# }
#}

264
xCAT-SoftLayer/bin/modifygrub Executable file
View File

@ -0,0 +1,264 @@
#!/usr/bin/perl
# Modify the grub config file on the node to boot the specified kernel and initrd.
# This script is meant to be run on the node via xdsh -e.
# Currently requires that dns on the mn be configured and working to resolve the short node names.
use strict;
use Getopt::Long;
use Data::Dumper;
use Socket;
# Globals - these are set once and then only read.
my $HELP;
my $VERBOSE;
my $WAITTIME;
my $XCATNETBOOTTITLE = 'xCAT network boot kernel and initrd';
my $usage = sub {
my $exitcode = shift @_;
print "Usage: modifygrub [-?|-h|--help] [-v|--verbose] [-w <waittime>] <kernel-path> <initrd-path> <kernel-parms> <mn-ip>\n\n";
if (!$exitcode) {
print "Modify the grub config file on the node to boot the specified kernel and initrd.\n";
}
exit $exitcode;
};
if (-f '/etc/os-release') { die "This script doesn't support ubuntu yet.\n"; }
# Process the cmd line args
Getopt::Long::Configure("bundling");
#Getopt::Long::Configure("pass_through");
Getopt::Long::Configure("no_pass_through");
if (!GetOptions('h|?|help' => \$HELP, 'v|verbose' => \$VERBOSE, 'w|waittime=s' => \$WAITTIME)) { $usage->(1); }
if ($HELP) { $usage->(0); }
if (scalar(@ARGV) != 4) { $usage->(1); }
if (!defined($WAITTIME)) { $WAITTIME = 60; } # seconds to wait after configuring the nic (to let the switch handle the state change)
my %args;
$args{kernelpath} = $ARGV[0];
$args{initrdpath} = $ARGV[1];
$args{kernelparms} = $ARGV[2];
$args{mnip} = $ARGV[3];
addKernelParms(\%args); # replace and add some parms to args{kernelparms}
updateGrub(\%args); # update the grub config with an entry filled with the info in args
exit(0);
# Add ip and net info to the kernel parms. Modifies the kernelparms value of the args hash passed in.
sub addKernelParms {
my $args = shift @_;
# replace '!myipfn!' with the mn ip
my $mnip = $args->{mnip};
$args->{kernelparms} =~ s/!myipfn!/$mnip/g;
# replace <nodename> with the nodename
my $nodename = $ENV{NODE}; # this env var is set by xdsh
$args->{kernelparms} =~ s/<nodename>/$nodename/g;
# get node ip and add it to the kernel parms
my ($nic, $ip, $netmask, $gateway) = getNodeIpInfo($args);
if (!$ip) { die "Error: could not find the NIC that would connect to the xCAT mgmt node's IP (".$args->{mnip}.").\n"; }
$args->{kernelparms} .= " hostip=$ip netmask=$netmask gateway=$gateway dns=$mnip hostname=$nodename netdevice=$nic netwait=$WAITTIME textmode=1";
}
# get this nodes nic, ip, netmask, and gateway. Returns them in a 4 element array.
sub getNodeIpInfo {
my $args = shift @_;
my ($ipprefix) = $args->{mnip}=~m/^(\d+\.\d+)\./; #todo: this is a hack, just using the 1st 2 octets of the mn ip addr
verbose("using IP prefix $ipprefix");
# parse ip addr show output, looking for ipprefix, to determine nic and ip
my @output = runcmd("ip addr show");
my ($nic, $ipandmask);
foreach my $line (@output) {
my ($nictmp, $iptmp);
if (($nictmp) = $line=~m/^\d+:\s+(\S+): /) { $nic = $nictmp; } # new stanza, remember it
if (($iptmp) = $line=~m/^\s+inet\s+($ipprefix\S+) /) { $ipandmask = $iptmp; last; } # got ip, we are done
}
my ($ip, $netmask) = convertIpAndMask($ipandmask);
# if the nic is a bonded nic (common on sl), then find the 1st real nic that is part of it
my $realnic = $nic;
if ($nic =~ /^bond/) {
my @nics = grep(m/\s+master\s+$nic\s+/, @output);
if (!scalar(@nics)) { die "Error: can't find the NICs that are part of $nic.\n"; }
($realnic) = $nics[0]=~m/^\d+:\s+(\S+): /;
}
# finally, find the gateway
my $gateway;
my @output = runcmd("ip route");
# we are looking for a line like: 10.0.0.0/8 via 10.54.51.1 dev bond0
my @networks = grep(m/ via .* $nic\s*$/, @output);
if (scalar(@networks)) { ($gateway) = $networks[0]=~m/ via\s+(\S+)/; }
else {
# use the mn ip as a fall back
$gateway = $args->{mnip};
verbose("using xCAT mgmt node IP as the fall back gateway.");
}
verbose("IP info: realnic=$realnic, ip=$ip, netmask=$netmask, gateway=$gateway");
return ($realnic, $ip, $netmask, $gateway);
}
# Convert an ip/mask in slash notation (like 10.0.0.1/26) to separate ip and netmask like 10.0.0.1 and 255.255.255.192
sub convertIpAndMask {
my $ipandmask = shift @_;
my ($ip, $masknum) = split('/', $ipandmask);
my $netbin = oct("0b" . '1' x $masknum . '0' x (32-$masknum)); # create a str like '1111100', then convert to binary
my @netarr=unpack('C4',pack('N',$netbin)); # separate into the 4 octets
my $netmask=join('.',@netarr); # put them together into the normal looking netmask
return ($ip, $netmask);
}
# not used - resolve the hostname to an ip addr
sub getipaddr {
my $hostname = shift @_;
my $packed_ip;
$packed_ip = inet_aton($hostname);
if (!$packed_ip) { return undef; }
return inet_ntoa($packed_ip);
}
# Update the grub config file with a new stanza for booting our kernel and initrd
sub updateGrub {
my $args = shift @_;
# how we specify the path for the kernel and initrd is different on redhat and suse
my $fileprefix;
if (isRedhat()) { $fileprefix = '/'; }
elsif (isSuse()) { $fileprefix = '/boot/'; }
else { die "Error: currently only support red hat or suse distros.\n"; }
# open the grub file and see if it is in there or if we have to add it
my $grubfile = findGrubPath();
verbose("reading $grubfile");
open(FILE, $grubfile) || die "Error: can not open config file $grubfile for reading: $!\n";
my @lines = <FILE>;
close FILE;
# this is the entry we want in the grub file
my @rootlines = grep(/^\s+root\s+/, @lines); # copy one of the existing root lines
if (!scalar(@rootlines)) { die "Error: can't find an existing line for 'root' in the grub config file\n"; }
my ($rootline) = $rootlines[0] =~ m/^\s*(.*?)\s*$/;
my @entry = (
"title $XCATNETBOOTTITLE\n",
"\t$rootline\n",
"\tkernel " . $fileprefix . $args->{kernelpath} . ' ' . $args->{kernelparms} . "\n",
"\tinitrd " . $fileprefix . $args->{initrdpath} . "\n",
);
my $needtowritefile = 1;
if (grep(/^title\s+$XCATNETBOOTTITLE/, @lines)) { $needtowritefile = updateGrubEntry(\@lines, \@entry); } # there is already an entry in there
else { addGrubEntry (\@lines, \@entry); }
# write the file with the new/updated xcat entry
if ($needtowritefile) {
verbose("updating $grubfile");
open(FILE, '>', $grubfile) || die "Error: can not open config file $grubfile for writing: $!\n";
print FILE @lines;
close FILE;
}
else { print "Info: $grubfile did not need modifying. It was already up to date.\n"; }
}
# add our entry as the 1st one in the grub file
sub addGrubEntry {
my ($lines, $entry) = @_;
# find the index of the 1st stanza (it starts with 'title')
my $i;
for ($i=0; $i<scalar(@$lines); $i++) {
if ($lines->[$i] =~ m/^title\s+/) { verbose('adding xcat entry before:'.$lines->[$i]); last; } # found it
}
# splice the entry right before the i-th line (which may also be 1 past the end)
splice(@$lines, $i, 0, @$entry);
}
# check the xcat entry in the grub file and see if it needs to be updated. Return 1 if it does.
sub updateGrubEntry {
my ($lines, $entry) = @_;
#print Dumper($lines), Dumper($entry);
# find the index of the xcat stanza
my $i;
for ($i=0; $i<scalar(@$lines); $i++) {
if ($lines->[$i] =~ m/^title\s+$XCATNETBOOTTITLE/) { last; } # found it
}
# compare the next few lines with the corresponding line in @$entries and replace if different
my $replaced = 0;
for (my $j=0; $j<scalar(@$entry); $j++) {
#print "comparing:\n ", $lines->[$i+$j], "\n ", $entry->[$j], "\n";
if ($lines->[$i+$j] ne $entry->[$j]) { # this line was different
$lines->[$i+$j] = $entry->[$j];
$replaced = 1;
}
}
return $replaced;
}
# depending on the distro, find the correct grub file and return its path
sub findGrubPath {
# for rhel/centos it is /boot/grub/grub.conf, for sles it is /boot/grub/menu.lst
my @paths = qw(/boot/grub/grub.conf /boot/grub/menu.lst);
foreach my $p (@paths) {
if (-f $p) { return $p; }
}
die "Error: Can't find grub config file.\n";
#todo: support ubuntu: you add an executable file in /etc/grub.d named 06_xcatnetboot that prints out the
# entry to add. Then run grub-mkconfig.
}
# Pring msg only if -v was specified
sub verbose { if ($VERBOSE) { print shift, "\n"; } }
# Check the distro we are running on
sub isSuse { return (-e '/etc/SuSE-release'); }
sub isRedhat { return (-e '/etc/redhat-release' || -e '/etc/centos-release' || -e '/etc/fedora-release'); } # add chk for fedora
# Run a command. If called in the context of return an array, it will capture the output
# of the cmd and return it. Otherwise, it will display the output to stdout.
# If the cmd has a non-zero rc, this function will die with a msg.
sub runcmd
{
my ($cmd) = @_;
my $rc;
$cmd .= ' 2>&1' ;
verbose($cmd);
my @output;
if (wantarray) {
@output = `$cmd`;
$rc = $?;
}
else {
system($cmd);
$rc = $?;
}
if ($rc) {
$rc = $rc >> 8;
if ($rc > 0) { die "Error: rc $rc return from cmd: $cmd\n"; }
else { die "Error: system error returned from cmd: $cmd\n"; }
}
elsif (wantarray) { return @output; }
}

236
xCAT-SoftLayer/bin/pushinitrd Executable file
View File

@ -0,0 +1,236 @@
#!/usr/bin/perl
# Copy the initrd, kernel, params, and static IP info to nodes, so they can net install
# even across vlans (w/o setting up pxe/dhcp broadcast relay). This assumes a working
# OS is on the node. This script is primarily meant to be used in the softlayer environment.
#todo: site attr for using static ip?
use strict;
use Getopt::Long;
use Data::Dumper;
# Globals - these are set once and then only read.
my $HELP;
my $VERBOSE;
my $WAITTIME;
my $NOAUTOINST;
my $usage = sub {
my $exitcode = shift @_;
print "Usage: pushinitrd [-?|-h|--help] [-v|--verbose] [-w <waittime>] <noderange>\n\n";
if (!$exitcode) {
print "Copy the initrd, kernel, params, and static IP info to nodes, so they can net install\n";
print "even across vlans (w/o setting up pxe/dhcp broadcast relay). This assumes a working\n";
print "OS is on the node, that you've run nodeset for these nodes, and that all of the nodes\n";
print "are using the same osimage.\n";
}
exit $exitcode;
};
# Process the cmd line args
Getopt::Long::Configure("bundling");
#Getopt::Long::Configure("pass_through");
Getopt::Long::Configure("no_pass_through");
if (!GetOptions('h|?|help' => \$HELP, 'v|verbose' => \$VERBOSE, 'w|waittime=s' => \$WAITTIME, 'a|noautoinst' => \$NOAUTOINST)) { $usage->(1); }
if ($HELP) { $usage->(0); }
if (scalar(@ARGV) != 1) { $usage->(1); }
if (!defined($WAITTIME)) { $WAITTIME = 75; } # seconds to wait after configuring the nic (to let the switch handle the state change)
my $noderange = $ARGV[0];
my %bootparms = getBootParms($noderange);
copyFilesToNodes($noderange, \%bootparms);
updateGrubOnNodes($noderange, \%bootparms);
if (!$NOAUTOINST) { modifyAutoinstFiles($noderange, \%bootparms); }
exit(0);
# Query the db for the kernel, initrd, and kcmdline attributes of the 1st node in the noderange
sub getBootParms {
my $nr = shift @_;
my %bootparms;
my @output = runcmd("nodels $nr bootparams.kernel bootparams.initrd bootparams.kcmdline");
# the attributes can be displayed in a different order than requested, so need to grep for them
my @gresults;
foreach my $a (qw(kernel initrd kcmdline)) {
my $attr = "bootparams.$a";
@gresults = grep(/^\S+:\s+$attr:/, @output);
if (!scalar(@gresults)) { die "Error: attribute $attr not defined for the noderange. Did you run 'nodeset <noderange> osimage=<osimage>' ?\n"; }
# for now just pick the 1st one. They should all be the same, except for the node name in kcmdline
chomp($gresults[0]);
$gresults[0] =~ s/^\S+:\s+$attr:\s*//;
$bootparms{$a} = $gresults[0];
if ($a eq 'kcmdline') { $bootparms{$a} =~ s|/install/autoinst/\S+|/install/autoinst/<nodename>|; }
}
# get the mgmt node cluster-facing ip addr
@output = runcmd('lsdef -t site -i master -c');
chomp($output[0]);
my ($junk, $ip) = split(/=/, $output[0]);
$bootparms{mnip} = $ip;
verbose(Dumper(\%bootparms));
return %bootparms;
}
# Copy the kernel and initrd to the nodes
# Args: noderange, reference to the bootparms hash
sub copyFilesToNodes {
my $nr = shift @_;
my $bootparms = shift @_;
foreach my $a (qw(kernel initrd)) {
my $file = $bootparms->{$a};
my $localfile = "/tftpboot/$file";
# for the
my $remotefile = '/boot/' . remoteFilename($file);
print "Copying $localfile to $nr:$remotefile\n";
runcmd("xdcp $nr -p $localfile $remotefile");
}
}
# Form the remote file name, using the last 2 parts of the path, separated by "-"
sub remoteFilename {
my $f = shift @_;
$f =~ s|^.*/([^/]+)/([^/]+)$|$1-$2|;
return $f;
}
# Run the modifygrub script on the nodes to update the grub config file
# Args: noderange, reference to the bootparms hash
sub updateGrubOnNodes {
my $nr = shift @_;
my $bootparms = shift @_;
my $vtxt = ($VERBOSE ? '-v' : '');
my @output = runcmd('which modifygrub');
my $modifygrub = $output[0];
chomp($modifygrub);
my $cmd = "xdsh $nr -e $modifygrub $vtxt -w $WAITTIME " . remoteFilename($bootparms->{kernel}) . ' ' . remoteFilename($bootparms->{initrd}) . ' ';
# we need to quote the kernel parms, both here when passing it to xdsh, and on the node
# when xdsh is passing it to modifygrub. The way to get single quotes inside single quotes
# is to quote each of the outer single quotes with double quotes.
$cmd .= q("'"') . $bootparms->{kcmdline} . q('"'");
$cmd .= ' ' . $bootparms->{mnip};
print "Running modifygrub on $nr to update the grub configuration.\n";
runcmd($cmd);
}
# Hack the autoinst files to wait in a key spot to make them work even tho it takes
# the NICs almost a min before they can transmit after a state change.
#todo: this has only been tested with SLES nodes
sub modifyAutoinstFiles {
my $nr = shift @_;
my $bootparms = shift @_;
# expand the noderange into a list of nodes
my @nodes = runcmd("nodels $nr");
chomp(@nodes);
# Edit each file to have chroot.sles insert a wait at the end of /etc/init.d/network
# this finds the end of boot.sh script (which is chroot.sles)
my $search = '\n\]\]>\s*</source>\s*</script>\s*</chroot-scripts>';
my $file = '/mnt/etc/init.d/network'; # at this point in the installation, the permanent file system is just mounted
#my $waitstring = 'echo Sleeping for 55s;sleep 55';
# this is the string to insert in the nodes /etc/init.d/network script. It is a while loop pinging the mn, but some of the chars need to be escape for sed
my $waitstring = 'echo Waiting to reach xCAT mgmt node...;while \[ \$\(\(xcati+=1\)\) -le 60 \] \&\& ! ping -c2 -w3 ' . $bootparms->{mnip} .'; do echo i=\$xcati ; done; sleep 10';
# this crazy sed string is from google. It gathers up the whole file into the hold buffer, and then the substitution is done on the whole file
my $sedstring = q|sed -n '1h;1!H;${;g;s/\(\t\treload_firewall\n\)\n/\1\t\t| . $waitstring . q(\n\n/g;p;}') . " $file > $file.new";
# finally create the perl replace string that will be used to modify the autoinst file
my $replace = "$sedstring\nchmod 755 $file.new; mv -f $file.new $file";
# now actually update the file
print "Updating /install/autoinst files.\n";
foreach my $n (@nodes) {
my $f = "/install/autoinst/$n";
my $matches = sed($f, $search, $replace, mode=>'insertbefore');
if (!$matches) { die "Error: could not find the right place in $f to insert the sed of the network wait.\n"; }
}
}
# this is like multi-line sed replace function
# Args: filename, search-string, replace-string
sub sed {
my ($file, $search, $replace, %options) = @_;
#my $opts = 's';
#if ($options{global}) { $opts .= 'g'; }
# open the file for reading
verbose("reading $file");
open(FILE, $file) || die "Error: can not open file $file for reading: $!\n";
my $lines;
while (<FILE>) { $lines .= $_; }
#verbose('file length is '.length($lines));
close FILE;
# we also need to look for this string 1st
my $replacecopy = $replace; # a search string can't have special chars in it
$replacecopy =~ s/(\W)/\\$1/g; # so escape all of the meta characters
#print "replacecopy=$replacecopy\n";
# check to see if the replace string is already in the file
if ($lines =~ m/$replacecopy/s) {
print "$file did not need updating.\n";
return 1;
}
# search/replace and see if there were any matches
my $matches;
if ($options{mode} eq 'insertbefore') { $matches = $lines =~ s/($search)/\n$replace\n$1/s; }
elsif ($options{mode} eq 'insertafter') { $matches = $lines =~ s/($search)/$1\n$replace\n/s; }
elsif ($options{mode} eq 'replace') { $matches = $lines =~ s/$search/$replace/s; }
else { die "Internal error: don't suppor sed mode of $options{mode}.\n"; }
# write file if necessary
if ($matches) {
verbose("updating $file");
open(FILE, '>', $file) || die "Error: can not open file $file for writing: $!\n";
print FILE $lines;
close FILE;
}
return $matches;
}
# Pring msg only if -v was specified
sub verbose { if ($VERBOSE) { print shift, "\n"; } }
# Run a command. If called in the context of return an array, it will capture the output
# of the cmd and return it. Otherwise, it will display the output to stdout.
# If the cmd has a non-zero rc, this function will die with a msg.
sub runcmd
{
my ($cmd) = @_;
my $rc;
$cmd .= ' 2>&1' ;
verbose($cmd);
my @output;
if (wantarray) {
@output = `$cmd`;
$rc = $?;
}
else {
system($cmd);
$rc = $?;
}
if ($rc) {
$rc = $rc >> 8;
if ($rc > 0) { die "Error: rc $rc return from cmd: $cmd\n"; }
else { die "Error: system error returned from cmd: $cmd\n"; }
}
elsif (wantarray) { return @output; }
}

View File

@ -0,0 +1,84 @@
=head1 NAME
B<getslnodes> - queries your SoftLayer account and gets attributes for each server.
=head1 SYNOPSIS
B<getslnodes> [B<-v>|B<--verbose>] [I<hostname-match>]
B<getslnodes> [B<-?> | B<-h> | B<--help>]
=head1 DESCRIPTION
The B<getslnodes> command queries your SoftLayer account and gets attributes for each
server. The attributes can be piped to 'mkdef -z' to define the nodes
in the xCAT DB so that xCAT can manage them.
Before using this command, you must download and install the SoftLayer API perl module.
For example:
cd /usr/local/lib
git clone https://github.com/softlayer/softlayer-api-perl-client.git
You also need to follow these directions to get your SoftLayer API key: http://knowledgelayer.softlayer.com/procedure/retrieve-your-api-key
B<getslnodes> requires a .slconfig file in your home directory that contains your
SoftLayer userid, API key, and location of the SoftLayer API perl module, in attr=val format.
For example:
# Config file used by the xcat cmd getslnodes
userid = joe_smith
apikey = 1234567890abcdef1234567890abcdef1234567890abcdef
apidir = /usr/local/lib/softlayer-api-perl-client
=head1 OPTIONS
=over 10
=item B<-?|-h|--help>
Display usage message.
=item B<-v|--version>
Command Version.
=back
=head1 RETURN VALUE
0 The command completed successfully.
1 An error has occurred.
=head1 EXAMPLES
=over 3
=item 1.
Display information about all of the nodes in your SoftLayer account:
getslnodes
=item 2.
Display information about all of the nodes whose hostname starts with foo:
getslnodes foo
=item 3.
Create xCAT node defintions in the xCAT DB for all of the nodes in your SoftLayer account:
getslnodes | mkdef -z
=back
=head1 FILES
/opt/xcat/bin/getslnodes
=head1 SEE ALSO
L<pushinitrd(1)|pushinitrd.1>

View File

@ -0,0 +1,66 @@
=head1 NAME
B<pushinitrd> - queries your SoftLayer account and gets attributes for each server.
=head1 SYNOPSIS
B<pushinitrd> [B<-v>|B<--verbose>] [B<-w> I<waittime>] [I<noderange>]
B<pushinitrd> [B<-?> | B<-h> | B<--help>]
=head1 DESCRIPTION
The B<pushinitrd> command copies the initrd, kernel, params, and static IP info to nodes, so they can be net installed
even across vlans (w/o setting up pxe/dhcp broadcast relay). This assumes a working
OS is on the nodes. Before running this command, you must run nodeset for these nodes.
All of the nodes given to one invocation of B<pushinitrd> must be using the same osimage.
Before using this command, if will be most convenient if you exchange the ssh keys using:
xdsh <noderange> -K
=head1 OPTIONS
=over 10
=item B<-w> I<waittime>
The number of seconds the initrd should wait before trying to communicate over the network.
The default is 75. This translates into the netwait kernel parameter and is usually needed
in a SoftLayer environment because it can take a while for a NIC to be active after changing state.
=item B<-?|-h|--help>
Display usage message.
=item B<-v|--version>
Command Version.
=back
=head1 RETURN VALUE
0 The command completed successfully.
1 An error has occurred.
=head1 EXAMPLES
=over 3
=item 1.
Configure nodes for net installing in a SoftLayer environment:
pushinitrd <noderange>
=back
=head1 FILES
/opt/xcat/bin/pushinitrd
=head1 SEE ALSO
L<getslnodes(1)|getslnodes.1>

View File

@ -0,0 +1,6 @@
#!/bin/bash
# set the default route of the node to the ip address and nic passed in
set -x
ip route replace to default via $1 dev $2

View File

@ -0,0 +1,20 @@
#!/bin/sh
# This is modified from the standard xcat post.sles.common in that it does not set up
# the ifcfg-eth0 file to do dhcp and it does not restart the network. It just leaves
# ifcfg-eth0 the way autoyast configured it, assuming we set it statically.
# save what autoyast set network config to, to help with debugging
cp /etc/sysconfig/network/ifcfg-eth0 /tmp/ifcfg-eth0.orig
cp /etc/hosts /tmp/hosts.orig
cp /etc/resolv.conf /tmp/resolv.conf.orig
cp /etc/HOSTNAME /tmp/HOSTNAME.orig
#cd /etc/sysconfig/network
perl -pi -e 's/^FIREWALL="yes"/FIREWALL="no"/' /etc/sysconfig/network/config
# autoyast already set hostname correctly
HOSTNAME=$(hostname -s)
echo $HOSTNAME

View File

@ -0,0 +1,105 @@
<?xml version="1.0"?>
<!DOCTYPE profile SYSTEM "/usr/share/YaST2/include/autoinstall/profile.dtd">
<!-- The 2 main differences from the standard xcat compute.sles11.tmpl are:
1. instead of dhcp settings in the networking section it puts static info there
2. it includes post.sles.softlayer.common instead of post.sles11 and post.sles.common -->
<profile xmlns="http://www.suse.com/1.0/yast2ns" xmlns:config="http://www.suse.com/1.0/configns">
<install>
<bootloader>
<write_bootloader config:type="boolean">true</write_bootloader>
<activate config:type="boolean">true</activate>
<kernel_parameters></kernel_parameters>
<lba_support config:type="boolean">false</lba_support>
<linear config:type="boolean">false</linear>
<location>mbr</location>
</bootloader>
<general>
<clock>
<hwclock>GMT</hwclock>
<timezone>#TABLE:site:key=timezone:value#</timezone>
</clock>
<keyboard>
<keymap>english-us</keymap>
</keyboard>
<language>en_US</language>
<mode>
<confirm config:type="boolean">false</confirm>
<forceboot config:type="boolean">false</forceboot>
<interactive_boot config:type="boolean">false</interactive_boot>
<reboot config:type="boolean">true</reboot>
</mode>
<mouse>
<id>non</id>
</mouse>
<signature-handling>
<accept_non_trusted_gpg_key config:type="boolean">true</accept_non_trusted_gpg_key>
<accept_unknown_gpg_key config:type="boolean">true</accept_unknown_gpg_key>
<accept_unsigned_file config:type="boolean">true</accept_unsigned_file>
</signature-handling>
</general>
<partitioning config:type="list">
<!-- XCAT-PARTITION-START -->
<drive>
<device>XCATPARTITIONHOOK</device>
<initialize config:type="boolean">true</initialize>
<use>all</use>
</drive>
<!-- XCAT-PARTITION-END -->
</partitioning>
<software>
<patterns config:type="list">
#INCLUDE_DEFAULT_PTRNLIST_S#
</patterns>
<packages config:type="list">
#INCLUDE_DEFAULT_PKGLIST_S#
</packages>
</software>
</install>
<configure>
<users config:type="list">
<user>
<username>root</username>
<user_password>#CRYPT:passwd:key=system,username=root:password#</user_password>
<encrypted config:type="boolean">true</encrypted>
<forename/>
<surname/>
</user>
</users>
<networking>
<keep_install_network config:type="boolean">true</keep_install_network>
<dns>
<domain>#TABLE:site:key=domain:value#</domain>
<hostname>#TABLE:nodelist:$NODE:node#</hostname>
<nameservers config:type="list">
<nameserver>#XCATVAR:XCATMASTER#</nameserver>
</nameservers>
<searchlist config:type="list">
<search>#TABLE:site:key=domain:value#</search>
</searchlist>
</dns>
<routing>
<ip_forward config:type="boolean">false</ip_forward>
</routing>
</networking>
<scripts>
#INCLUDE:#ENV:XCATROOT#/share/xcat/install/scripts/pre.sles#
#INCLUDE:#ENV:XCATROOT#/share/xcat/install/scripts/chroot.sles#
<post-scripts config:type="list">
<script>
<filename>xcat.sh</filename>
<interpreter>shell</interpreter>
<source>
<![CDATA[
#INCLUDE:#ENV:XCATROOT#/share/xcat/install/scripts/post.sles.softlayer.common#
#INCLUDE:#ENV:XCATROOT#/share/xcat/install/scripts/post.xcat#
]]>
</source>
</script>
</post-scripts>
</scripts>
</configure>
</profile>

View File

@ -0,0 +1,74 @@
Summary: Utilities to make xCAT work in a SoftLayer environment
Name: xCAT-SoftLayer
Version: %(cat Version)
Release: snap%(date +"%Y%m%d%H%M")
Epoch: 4
License: EPL
Group: Applications/System
Source: xCAT-SoftLayer-%(cat Version).tar.gz
Packager: IBM Corp.
Vendor: IBM Corp.
Distribution: %{?_distribution:%{_distribution}}%{!?_distribution:%{_vendor}}
Prefix: /opt/xcat
BuildRoot: /var/tmp/%{name}-%{version}-%{release}-root
%ifos linux
BuildArch: noarch
%endif
Requires: xCAT-server
#Requires: xCAT-server >= %{epoch}:%(cat Version|cut -d. -f 1,2)
Provides: xCAT-SoftLayer = %{epoch}:%{version}
%description
xCAT-SoftLayer provides Utilities to make xCAT work in a SoftLayer environment. This package should be installed on your management server
# %define VERBOSE %(if [ "$VERBOSE" = "1" -o "$VERBOSE" = "yes" ];then echo 1; else echo 0; fi)
# %define NOVERBOSE %(if [ "$VERBOSE" = "1" -o "$VERBOSE" = "yes" ];then echo 0; else echo 1; fi)
# %define NOVERBOSE %{?VERBOSE:1}%{!?VERBOSE:0}
%prep
# %if %NOVERBOSE
# echo NOVERBOSE is on
# set +x
# %elseif
# set -x
# %endif
%setup -q -n xCAT-SoftLayer
%build
# Convert pods to man pages and html pages
./xpod2man
%install
rm -rf $RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT/%{prefix}/bin
mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/xcat/install
mkdir -p $RPM_BUILD_ROOT/install/postscripts
mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/doc/packages/xCAT-SoftLayer
mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/man/man1
mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/doc/man1
cp -p -R share/xcat/install/* $RPM_BUILD_ROOT/%{prefix}/share/xcat/install/
cp -d bin/* $RPM_BUILD_ROOT/%{prefix}/bin
chmod 755 $RPM_BUILD_ROOT/%{prefix}/bin/*
cp -d postscripts/* $RPM_BUILD_ROOT/install/postscripts
chmod 755 $RPM_BUILD_ROOT/install/postscripts/*
cp LICENSE.html $RPM_BUILD_ROOT/%{prefix}/share/doc/packages/xCAT-SoftLayer
chmod 644 $RPM_BUILD_ROOT/%{prefix}/share/doc/packages/xCAT-SoftLayer/*
cp share/man/man1/* $RPM_BUILD_ROOT/%{prefix}/share/man/man1
chmod 444 $RPM_BUILD_ROOT/%{prefix}/share/man/man1/*
cp share/doc/man1/* $RPM_BUILD_ROOT/%{prefix}/share/doc/man1
chmod 644 $RPM_BUILD_ROOT/%{prefix}/share/doc/man1/*
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
#%doc LICENSE.html
%{prefix}
/install/postscripts

214
xCAT-SoftLayer/xpod2man Executable file
View File

@ -0,0 +1,214 @@
#!/usr/bin/perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
# First builds the xCAT summary man page from Synopsis of each man page.
# Then converts all of the pod man pages into html (including links to each other)
# We assume that this script is run in the xCAT-vlan-2.0 dir, so everything is
# done relative to that.
use strict;
#use lib '.';
use Pod::Man;
use Pod::Html;
my $poddir = 'pods';
my $mandir = 'share/man';
my $htmldir = 'share/doc';
my $cachedir = '/tmp';
my @pods = getPodList($poddir);
#foreach (@pods) { print "$_\n"; } exit;
# Build the cmd overview page.
#writesummarypage("$poddir/man1/xcat.1.pod", @pods);
# Build the man page for each pod.
#mkdir($mandir) or die "Error: could not create $mandir.\n";
print "Converting PODs to man pages...\n";
foreach my $podfile (@pods) {
my $manfile = $podfile;
$manfile =~ s/^$poddir/$mandir/; # change the beginning of the path
$manfile =~ s/\.pod$//; # change the ending
my $mdir = $manfile;
$mdir =~ s|/[^/]*$||; # get rid of the basename part
if (system("mkdir -p $mdir")) { die "Error: could not create $mdir.\n"; }
my ($section) = $podfile =~ /\.(\d+)\.pod$/;
convertpod2man($podfile, $manfile, $section);
}
my @dummyPods = createDummyPods($poddir, \@pods);
# Build the html page for each pod.
#mkdir($htmldir) or die "Error: could not create $htmldir.\n";
print "Converting PODs to HTML pages...\n";
# have to clear the cache, because old entries can cause a problem
unlink("$cachedir/pod2htmd.tmp", "$cachedir/pod2htmi.tmp");
foreach my $podfile (@pods) {
my $htmlfile = $podfile;
$htmlfile =~ s/^$poddir/$htmldir/; # change the beginning of the path
$htmlfile =~ s/\.pod$/\.html/; # change the ending
my $hdir = $htmlfile;
$hdir =~ s|/[^/]*$||; # get rid of the basename part
if (system("mkdir -p $hdir")) { die "Error: could not create $hdir.\n"; }
#print "$podfile, $htmlfile, $poddir, $htmldir\n";
convertpod2html($podfile, $htmlfile, $poddir, $htmldir);
}
# Remove the dummy pods
unlink @dummyPods;
rmdir "$poddir/man7";
exit;
# To enable linking between the cmd man pages and the db man pages, need to:
# grep thru the cmd pods searching for references (L<>) to any section 5 man page
# if that pod does not exist, create an empty one that will satisfy pod2html
# keep track of all dummy pods created, so they can be removed later
sub createDummyPods {
my ($poddir, $pods) = @_;
my $cmd = "grep -r -E 'L<.+\\([57]\\)\\|.+\\.[57]>' " . $poddir;
#print "Running cmd: ", $cmd, "\n";
my @lines = `$cmd`;
if ($?) { print "Error running: $cmd\n"; print join('', @lines); }
#my @lines;
#system($cmd);
my @dummyPods;
foreach my $l (@lines) {
#print "$l\n";
my @matches = $l =~ /L<([^\(]+)\(([57])\)\|\1\.[57]>/g; # get all the matches in the line
# The above line should create the array with every other entry being the man page name
# and every other entry is the section # (5 or 7)
my $cmd;
while ($cmd=shift @matches) {
#foreach my $m (@matches) {
my $section = shift @matches;
my $filename = "$poddir/man$section/$cmd.$section.pod";
#print "$filename\n";
if (!(grep /^$filename$/, @$pods) && !(grep /^$filename$/, @dummyPods)) { push @dummyPods, $filename; }
}
}
# Create these empty files
print "Creating empty linked-to files: ", join(', ', @dummyPods), "\n";
mkdir "$poddir/man7";
foreach my $d (@dummyPods) {
if (!open(TMP, ">>$d")) { warn "Could not create dummy pod file $d ($!)\n"; }
else { close TMP; }
}
return @dummyPods;
}
# Recursively get the list of pod man page files.
sub getPodList {
my $poddir = shift;
my @files;
# 1st get toplevel dir listing
opendir(DIR, $poddir) or die "Error: could not read $poddir.\n";
my @topdir = grep !/^\./, readdir(DIR); # /
close(DIR);
# Now go thru each subdir (these are man1, man3, etc.)
foreach my $mandir (@topdir) {
opendir(DIR, "$poddir/$mandir") or die "Error: could not read $poddir/$mandir.\n";
my @dir = grep !/^\./, readdir(DIR); # /
close(DIR);
foreach my $file (@dir) {
push @files, "$poddir/$mandir/$file";
}
}
return sort @files;
}
# Create the xcat man page that gives a summary description of each xcat cmd.
# Not used.
sub writesummarypage {
my $file = shift; # relative path file name of the man page
# the rest of @_ contains the pod files that describe each cmd
open(FILE, ">$file") or die "Error: could not open $file for writing.\n";
print FILE <<'EOS1';
=head1 NAME
B<xcat> - extreme Cluster Administration Tool.
=head1 DESCRIPTION
Extreme Cluster Administration Toolkit (xCAT). xCAT is a scalable distributed computing management
and provisioning tool that provides a unified interface for hardware control, discovery, and
OS diskful/diskfree deployment.
=head1 XCAT DATABASE
All of the cluster configuration information is in the xCAT database. See L<xcatdb(5)|xcatdb.5> for
descriptions of every table in the database.
=head1 XCAT COMMANDS
What follows is a short description of each xCAT command. To get more information about a particular
command, see its man page. Note that the commands are listed in alphabetical order B<within each section>,
i.e. all the commands in section 1, then the commands in section 3, etc.
=over 12
EOS1
# extract the summary for each cmd from its man page
foreach my $manpage (@_) {
my ($sectionnum) = $manpage =~ /\.(\d+)\.pod$/;
# Suck in the whole file, then we will parse it.
open(MANPAGE, "$manpage") or die "Error: could not open $manpage for reading.\n";
my @contents = <MANPAGE>;
my $wholemanpage = join('', @contents);
close(MANPAGE);
# This regex matches: optional space, =head1, space, title, space, cmd, space, description, newline
my ($cmd, $description) = $wholemanpage =~ /^\s*=head1\s+\S+\s+(\S+)\s+(.+?)\n/si;
if (!defined($cmd)) { print "Warning: $manpage is not in a recognized structure. It will be ignored.\n"; next; }
if (!defined($description)) { print "Warning: $manpage does not have a description for $cmd. It will be ignored.\n"; next; }
$cmd =~ s/^.<(.+)>$/$1/; # if the cmd name has pod formatting around it, strip it off
$description =~ s/^-\s*//; # if the description has a leading hypen, strip it off
print FILE "\n=item L<$cmd($sectionnum)|$cmd.$sectionnum>\n\n".$description."\n";
}
# Artificially add the xcattest cmd, because the xCAT-test rpm will add this
print FILE "\n=item L<xcattest(1)|xcattest.1>\n\nRun automated xCAT test cases.\n";
print FILE <<"EOS3";
=back
EOS3
close FILE;
}
# Create the html page for one pod.
sub convertpod2html {
my ($podfile, $htmlfile, $poddir, $htmldir) = @_;
#TODO: use --css=<stylesheet> and --title=<pagetitle> to make the pages look better
pod2html($podfile,
"--outfile=$htmlfile",
"--podpath=man1",
"--podroot=$poddir",
"--htmldir=$htmldir",
"--recurse",
"--cachedir=$cachedir",
);
}
# Create the man page for one pod.
sub convertpod2man {
my ($podfile, $manfile, $section) = @_;
my $parser = Pod::Man->new(section => $section);
$parser->parse_from_file($podfile, $manfile);
}

View File

@ -117,7 +117,7 @@ if ((!$imagename) && (!$profile) && (!$os) && (!$arch)) {
if ($? == 0) {
if (($tmpimgs) && ($tmpimgs !~ /^Could/)) { #Could is returned when the osimage table is empty
my @images=split('\n', $tmpimgs);
print "Do you want to re-genarate an existing image from the osimage table? ";
print "Do you want to re-generate an existing image from the osimage table? ";
print "[y/n] ";
my $conf = <stdin>;
chomp($conf);
@ -128,7 +128,7 @@ if ((!$imagename) && (!$profile) && (!$os) && (!$arch)) {
foreach(sort @images){
print " $_\n";
}
# default is the first image cause in many cases
# default is the first image
print "Which image do you want to re-generate? [";
print $images[0];
print "] ";
@ -294,13 +294,10 @@ if ($profile) { print " Profile: $profile\n"; }
# get the interface
if ((!$imagename) && (!$interface)){
while(1){
print "Which network interface do you want the image to boot from? [";
print "eth0";
print "] ";
print "OPTIONAL: Which specific network interface will the image boot from? [<blank>]";
$interface = <stdin>;
chomp($interface);
if($interface eq ""){
$interface = "eth0";
last;
}else{
print "You want your stateless machines to boot off of ";
@ -317,8 +314,9 @@ if ((!$imagename) && (!$interface)){
}
}
}
if ($interface) { print " Interface: $interface\n"; }
else { print " No interface specified. The interface will be determined at network boot time.\n"; }
}
if ($interface) { print " Interface: $interface\n"; }

View File

@ -205,10 +205,10 @@ if ($::osname eq 'AIX')
&setulimits;
}
# if not just odbc update and not already running mysql or mysqlsetup -u
# if not just odbc update and not already running mysql or mysqlsetup -u or -L
# Get root and admin passwords
#
if ((($odbconly == 0) && ( $::xcatrunningmysql == 0)) || $::UPDATE )
if ((($odbconly == 0) && ( $::xcatrunningmysql == 0)) || $::UPDATE || $::SETUPLL )
{ # not just updating the odbc
if ($ENV{'XCATMYSQLADMIN_PW'}) # input env sets the password
{

145
xCAT-client/podchecker Executable file
View File

@ -0,0 +1,145 @@
#!/usr/bin/perl
eval 'exec perl -S $0 "$@"'
if 0;
#############################################################################
# podchecker -- command to invoke the podchecker function in Pod::Checker
#
# Copyright (c) 1998-2000 by Bradford Appleton. All rights reserved.
# This file is part of "PodParser". PodParser is free software;
# you can redistribute it and/or modify it under the same terms
# as Perl itself.
#############################################################################
use strict;
#use diagnostics;
=head1 NAME
podchecker - check the syntax of POD format documentation files
=head1 SYNOPSIS
B<podchecker> [B<-help>] [B<-man>] [B<-(no)warnings>] [I<file>S< >...]
=head1 OPTIONS AND ARGUMENTS
=over 8
=item B<-help>
Print a brief help message and exit.
=item B<-man>
Print the manual page and exit.
=item B<-warnings> B<-nowarnings>
Turn on/off printing of warnings. Repeating B<-warnings> increases the
warning level, i.e. more warnings are printed. Currently increasing to
level two causes flagging of unescaped "E<lt>,E<gt>" characters.
=item I<file>
The pathname of a POD file to syntax-check (defaults to standard input).
=back
=head1 DESCRIPTION
B<podchecker> will read the given input files looking for POD
syntax errors in the POD documentation and will print any errors
it find to STDERR. At the end, it will print a status message
indicating the number of errors found.
Directories are ignored, an appropriate warning message is printed.
B<podchecker> invokes the B<podchecker()> function exported by B<Pod::Checker>
Please see L<Pod::Checker/podchecker()> for more details.
=head1 RETURN VALUE
B<podchecker> returns a 0 (zero) exit status if all specified
POD files are ok.
=head1 ERRORS
B<podchecker> returns the exit status 1 if at least one of
the given POD files has syntax errors.
The status 2 indicates that at least one of the specified
files does not contain I<any> POD commands.
Status 1 overrides status 2. If you want unambiguous
results, call B<podchecker> with one single argument only.
=head1 SEE ALSO
L<Pod::Parser> and L<Pod::Checker>
=head1 AUTHORS
Please report bugs using L<http://rt.cpan.org>.
Brad Appleton E<lt>bradapp@enteract.comE<gt>,
Marek Rouchal E<lt>marekr@cpan.orgE<gt>
Based on code for B<Pod::Text::pod2text(1)> written by
Tom Christiansen E<lt>tchrist@mox.perl.comE<gt>
=cut
use Pod::Checker;
use Pod::Usage;
use Getopt::Long;
## Define options
my %options;
## Parse options
GetOptions(\%options, qw(help man warnings+ nowarnings)) || pod2usage(2);
pod2usage(1) if ($options{help});
pod2usage(-verbose => 2) if ($options{man});
if($options{nowarnings}) {
$options{warnings} = 0;
}
elsif(!defined $options{warnings}) {
$options{warnings} = 1; # default is warnings on
}
## Dont default to STDIN if connected to a terminal
pod2usage(2) if ((@ARGV == 0) && (-t STDIN));
## Invoke podchecker()
my $status = 0;
@ARGV = qw(-) unless(@ARGV);
for my $podfile (@ARGV) {
if($podfile eq '-') {
$podfile = '<&STDIN';
}
elsif(-d $podfile) {
warn "podchecker: Warning: Ignoring directory '$podfile'\n";
next;
}
my $errors =
podchecker($podfile, undef, '-warnings' => $options{warnings});
if($errors > 0) {
# errors occurred
$status = 1;
printf STDERR ("%s has %d pod syntax %s.\n",
$podfile, $errors,
($errors == 1) ? 'error' : 'errors');
}
elsif($errors < 0) {
# no pod found
$status = 2 unless($status);
print STDERR "$podfile does not contain any pod commands.\n";
}
else {
print STDERR "$podfile pod syntax OK.\n";
}
}
exit $status;

View File

@ -24,7 +24,9 @@ B<chvm> I<noderange> [B<lparname>={B<*>|B<name>}]
B<chvm> I<noderange> [B<vmcpus=min/req/max>] [B<vmmemory=min/req/max>]
[B<vmphyslots=drc_index1,drc_index2...>] [B<vmothersetting=hugepage:N,bsr:N>]
[B<vmnics=vlan1[,vlan2..]]> [B<vmstorage=<N|viosnode:slotid>>] [B<--vios>]
[B<del_vadapter=slotid>]
=head2 VMware/KVM specific:
B<chvm> I<noderange> [B<-a> I<size>] [B<-d> I<disk>] [B<-p> I<disk>] [B<--resize> B<disk>=I<size>] [B<--cpus> I<count>] [B<--mem> I<memory>]
@ -111,7 +113,7 @@ The administrator should use lsvm to get the profile content, and then edit the
For normal power machine:
chvm could be used to modify the resources assigned to partitions. The admin shall specify the attributes with options I<vmcpus>, I<vmmemory>, I<vmphyslots> and/or I<vmothersetting>. If nothing specified, nothing will be returned.
chvm could be used to modify the resources assigned to partitions. The admin shall specify the attributes with options I<vmcpus>, I<vmmemory>, I<vmphyslots>, I<vmothersetting>, I<vmnics> and/or I<vmstorage>. If nothing specified, nothing will be returned.
=head2 VMware/KVM specific:
@ -199,6 +201,14 @@ Set LPAR name for the specified lpars. If '*' specified, it means to get names f
To specify the parameters that will be modified.
=item B<vmnics=value> B<vmstorage=value> [B<--vios>]
To create new virtual adapter for the specified node.
=item B<del_vadapter=value>
To specify the slot id of the virtual adapter will be deleted.
=back
=head2 VMware/KVM specific:

View File

@ -0,0 +1,138 @@
=head1 B<NAME>
B<chzone> - Changes a zone defined in the cluster.
=head1 B<SYNOPSIS>
B<chzone> <zonename> [B<--defaultzone>] [-K] [B<-k> I<full path to the ssh RSA private key>] [B<-a> I<noderange> | B<-r> I<noderange>] [B<-g>] [B<-f>] [B<-s> I<yes|no>] [-V]
B<chzone> [B<-h> | B<-v>]
=head1 B<DESCRIPTION>
The B<chzone> command is designed to change the definition of a zone previous defined in the cluster.
The chzone command is only supported on Linux ( No AIX support).
The nodes are not updated with the new root ssh keys by chzone. You must run updatenode -k or xdsh -K to the nodes to update the root ssh keys to the new generated zone keys. This will also sync any service nodes with the zone keys, if you have a hierarchical cluster.
Note: if any zones in the zone table, there must be one and only one defaultzone. Otherwise, errors will occur.
=head1 B<OPTIONS>
=over 5
=item B<-h>|B<--help>
Displays usage information.
=item B<-v>|B<--version>
Displays command version and build date.
=item B<-k | --sshkeypath> I<full path to the ssh RSA private key>
This is the path to the id_rsa key that will be used to build new root's ssh keys for the zone. If -k is used, it will generate the ssh public key from the input ssh RSA private key, and store both in /etc/xcat/sshkeys/<zonename>/.ssh directory.
=item B<-K | --genkeys>
Using this flag, will generate new ssh RSA private and public keys for the zone into the /etc/xcat/sshkeys/<zonename>/.ssh directory.
The nodes are not automatically updated with the new root ssh keys by chzone. You must run updatenode -k or xdsh -K to the nodes to update the root ssh keys to the new generated zone keys. This will also sync any service nodes with the zone keys, if you have a hierarchical cluster.
=item B<--default>
if --defaultzone is input, then it will set the zone defaultzone attribute to yes.
if --defaultzone is input and another zone is currently the default,
then the -f flag must be used to force a change to the new defaultzone.
If -f flag is not use an error will be returned and no change made.
Note: if any zones in the zone table, there must be one and only one defaultzone. Otherwise, errors will occur.
=item B<-a | --addnoderange> I<noderange>
For each node in the noderange, it will set the zonename attribute for that node to the input zonename.
If the -g flag is also on the command, then
it will add the group name "zonename" to each node in the noderange.
=item B<-r | --rmnoderange> I<noderange>
For each node in the noderange, if the node is a member of the input zone, it will remove the zonename attribute for that node.
If any of the nodes in the noderange is not a member of the zone, you will get an error and nothing will be changed.
If the -g flag is also on the command, then
it will remove the group name "zonename" from each node in the noderange.
=item B<-s| --sshbetweennodes> B<yes|no>
If -s entered, the zone sshbetweennodes attribute will be set to yes or no based on the input. When this is set to yes, then ssh will be setup to allow passwordless root access between nodes. If no, then root will be prompted for a password when running ssh between the nodes in the zone.
=item B<-f | --force>
Used with the (--defaultzone) flag to override the current default zone.
=item B<-g | --assigngroup>
Used with the (-a or -r ) flag to add or remove the group zonename for all nodes in the input noderange.
=item B<-V>|B<--Verbose>
Verbose mode.
=back
=head1 B<Examples>
=over 3
=item *
To chzone zone1 to the default zone, enter:
B<chzone> I<zone1> --default -f
=item *
To generate new root ssh keys for zone2A using the ssh id_rsa private key in /root/.ssh:
B<chzone> I<zone2A> -k /root/.ssh
Note: you must use xdsh -K or updatenode -k to update the nodes with the new keys
=item *
To generate new root ssh keys for zone2A, enter :
B<chzone> I<zone2A> -K
Note: you must use xdsh -K or updatenode -k to update the nodes with the new keys
=item *
To add a new group of nodes (compute3) to zone3 and add zone3 group to the nodes, enter:
B<chzone> I<zone3> -a compute3 -g
=item *
To remove a group of nodes (compute4) from zone4 and remove zone4 group from the nodes, enter:
B<chzone> I<zone4> -r compute4 -g
=item *
To change the sshbetweennodes setting on the zone to not allow passwordless ssh between nodes, enter:
B<chzone> I<zone5> -s no
Note: you must use xdsh -K or updatenode -k to update the nodes with this new setting.
=back
B<Files>
B</opt/xcat/bin/chzone/>
Location of the chzone command.
=head1 B<SEE ALSO>
L <mkzone(1)|mkzone.1>,L <rmzone(1)|rmzone.1>,L <xdsh(1)|xdsh.1>, L<updatenode(1)|updatenode.1>

View File

@ -6,10 +6,10 @@ B<genimage> - Generates a stateless image to be used for a diskless install.
B<genimage>
B<genimage> B<-o> I<osver> [B<-a> I<arch>] B<-p> I<profile> B<-i> I<nodebootif> B<-n> I<nodenetdrivers> [B<--onlyinitrd>] [B<-r> I<otherifaces>] [B<-k> I<kernelver>] [B<-g> I<krpmver>] [B<-m> I<statelite>] [B<-l> I<rootlimitsize>] [B<--permission> I<permission>] [B<--interactive>] [B<--dryrun>]
B<genimage> [B<-o> I<osver>] [B<-a> I<arch>] [B<-p> I<profile>] [B<-i> I<nodebootif>] [B<-n> I<nodenetdrivers>] [B<--onlyinitrd>] [B<-r> I<otherifaces>] [B<-k> I<kernelver>] [B<-g> I<krpmver>] [B<-m> I<statelite>] [B<-l> I<rootlimitsize>] [B<--permission> I<permission>] [B<--interactive>] [B<--dryrun>] [B<--ignorekernelchk>] I<imagename>
B<genimage> B<-o> I<osver> [B<-a> I<arch>] B<-p> I<profile> B<-i> I<nodebootif> B<-n> I<nodenetdrivers> [B<--onlyinitrd>] [B<-r> I<otherifaces>] [B<-k> I<kernelver>] [B<-g> I<krpmver>] [B<-m> I<statelite>] [B<-l> I<rootlimitsize>] [B<--permission> I<permission>] [B<--interactive>] [B<--dryrun>]
B<genimage> [B<-h> | B<--help> | B<-v> | B<--version>]
@ -17,43 +17,43 @@ B<genimage> [B<-h> | B<--help> | B<-v> | B<--version>]
=head1 DESCRIPTION
Generates a stateless and a statelite image that can be used to boot xCAT nodes in a diskless mode.
If I<imagename> is not specified, the default packages included
(and excluded) in the image are specified by
The I<imagename> format of the command is recommended. When specified, genimage will use the osimage definition for information to generate this image. Additional options specified on the command line will override any corresponding previous osimage settings, and will be written back to the osimage definition.
If I<imagename> is not specified (old method):
- the default packages included (and excluded) in the image are specified by
/opt/xcat/share/xcat/netboot/<os>/<profile>[.<osver>][.<arch>].pkglist and
/opt/xcat/share/xcat/netboot/<os>/<profile>[.<osver>][.<arch>].exlist.
Additional packages that are not from the os distro can be specified in a
- Additional packages that are not from the os distro can be specified in a
/opt/xcat/share/xcat/netboot/<os>/<profile>[.<osver>][.<arch>].otherpkgs.pkglist file.
Customized package list files can be specified under /install/custom/netboot/<os> directory. The generated image will be put in /install/netboot/<osver>/<arch>/<profile> directory.
- Customized package list files will override these files and can be specified under /install/custom/netboot/<os> directory.
- The generated image will be put in /install/netboot/<osver>/<arch>/<profile> directory.
The newly generated image names will have the following format:
- osimage definitions will be created in the I<linuximage> and I<osimage> tables. The newly generated image names will have the following format:
for stateless: <osver>-<arch>-netboot-<profile>
for stateless: <osver>-<arch>-netboot-<profile>
for statelite: <osver>-<arch>-statelite-<profile>
for statelite: <osver>-<arch>-statelite-<profile>
B<genimage> command will create them into I<linuximage> and I<osimage> tables.
If I<imagename> is specified, the package list file names are read from the I<osimage> table and I<linuximage> tables.
If B<genimage> runs on the management node, both the I<osimage> table and I<linuximage> table will be updated with the given values from the options.
The B<genimage> command will generate two initial ramdisks for B<stateless> and B<statelite>, one is B<initrd-stateless.gz>, the other one is B<initrd-statelite.gz>.
After your image is created, you can chroot to the
After your image is generated, you can chroot to the
image, install any additional software you would like, or make modifications to files, and then run the following command to prepare the image for deployment.
for stateless: B<packimage>
for statelite: B<liteimg>
Becides prompting for the input for some paramters, the B<genimage> command takes default quesses for the parameters not specified or not defined in the I<osimage> and I<linuximage> tables. It also makes default answers for questions from yum/zypper command when installing rpms into the image. Please use --interactive flag if you want yum/zypper command to prompt you for the answers.
Besides prompting for some paramter values, the B<genimage> command takes default guesses for the parameters not specified or not defined in the I<osimage> and I<linuximage> tables. It also assumes default answers for questions from the yum/zypper command when installing rpms into the image. Please use --interactive flag if you want the yum/zypper command to prompt you for the answers.
If B<--onlyinitrd> is specified, only regenerates the initrd for a stateless image to be used for a diskless install.
If B<--onlyinitrd> is specified, genimage only regenerates the initrd for a stateless image to be used for a diskless install.
The B<genimage> command must be run on a system that is the same architecture and same distro with same major release version as the nodes it will be
used on. If the management node is not the same architecture or same distro level, copy the contents of
@ -61,10 +61,9 @@ used on. If the management node is not the same architecture or same distro lev
the management node to that system. Then change directory to /opt/xcat/share/xcat/netboot/<os> and run ./genimage.
=head1 Parameters
I<imagename> specifies the name of a os image definition to be used. The specification for the image is storted in the I<osimage> table and I<linuximage> table.
I<imagename> specifies the name of an os image definition to be used. The specification for the image is stored in the I<osimage> table and I<linuximage> table.
=head1 OPTIONS
@ -88,7 +87,7 @@ the nodes' nodetype.profile attribute must be set to this same value.
=item B<-i> I<nodebootif>
The network interface the diskless node will boot over (e.g. eth0).
This argument is now optional, and allows you to specify the network boot interface to be configured in the image (e.g. eth0). If not specified, the interface will be determined and configured during the network boot process.
=item B<-n> I<nodenetdrivers>
@ -183,46 +182,53 @@ To prompt the user for inputs:
genimage
=item 2
To generate an image using information from an osimage definition:
To generate a fedora8 image for a compute node architecture
genimage myimagename
=item 3
To run genimage in test mode without actually generating an image:
genimage --dryrun myimagename
=item 4
To generate an image and have yum/zypper prompt for responses:
genimage myimagename --interactive
=item 5
To generate an image, replacing some values in the osimage definition:
genimage -i eth0 -n tg3 myimagename
=item 6
(old method) To generate a fedora8 image for a compute node architecture
x86_64 and place it in the
/install/netboot/fedora8/x86_64/compute/rootimg directory:
genimage -i eth0 -o fedora8 -p compute
=item 3
=item 7
(old method)
genimage -i eth0 -r eth1,eth2 -n tg3,bnx2 -o centos5.1 -p compute
=item 4
=item 8
(old method)
genimage -i eth0 -n tg3,bnx2 -o sles11 -p compute --interactive
=item 5
=item 9
(old method)
genimage -i eth0 -n igb,e1000e,e1000,bnx2,tg3 -o centos5.4 -p nfsroot --permission 777
=item 6
genimage -i eth0 -n tg3 myimagename
=item 7
genimage myimagename
=item 8
genimage myimagename --interactive
=item 9
To regenerate the initrd for a fedora8 image for a compute node architecture x86_64 and place it in the /install/netboot/fedora8/x86_64/compute/rootimg directory: change directory to /opt/xcat/share/xcat/netboot/fedora and run:
genimage --onlyinitrd -i eth0 -n tg3,bnx2 -o fedora8 -p compute
=item 10
(old method)
To regenerate the initrd for a fedora8 image for a compute node architecture x86_64 and place it in the /install/netboot/fedora8/x86_64/compute/rootimg directory:
genimage --dryrun myimagename
cd /opt/xcat/share/xcat/netboot/fedora
./genimage --onlyinitrd -i eth0 -n tg3,bnx2 -o fedora8 -p compute
=back

View File

@ -24,6 +24,7 @@ B<mkvm> I<noderange> [B<--full>]
B<mkvm> I<noderange> [B<vmcpus=min/req/max>] [B<vmmemory=min/req/max>]
[B<vmphyslots=drc_index1,drc_index2...>] [B<vmothersetting=hugepage:N,bsr:N>]
[B<vmnics=vlan1[,vlan2..]]> [B<vmstorage=<N|viosnode:slotid>>] [B<--vios>]
=head2 For KVM:
@ -55,7 +56,7 @@ Please note that the mkvm command currently only supports creating standard LPAR
With option I<full>, a partition using all the resources on a normal power machine will be created.
If no option is specified, a partition using the parameters specified with attributes such as 'vmcpus', 'vmmory', 'vmphyslots', 'vmothersetting' will be created. Those attributes can either be specified with '*def' commands running before or be specified with this command.
If no option is specified, a partition using the parameters specified with attributes such as 'vmcpus', 'vmmory', 'vmphyslots', 'vmothersetting', 'vmnics', 'vmstorage' will be created. Those attributes can either be specified with '*def' commands running before or be specified with this command.
=head2 For KVM and Vmware:
@ -89,9 +90,11 @@ The cpu count which will be created for the kvm/vmware virtual machine.
Request to create a new full system partition for each CEC.
=item B<vmcpus=value> B<vmmemory=value> B<vmphyslots=value> B<vmothersetting=value>
=item B<vmcpus=value> B<vmmemory=value> B<vmphyslots=value> B<vmothersetting=value> B<vmnics=value> B<vmstorage=value> [B<--vios>]
To specify the parameters which are used to create a partition. The I<vmcpus>, I<vmmemory> and I<vmphyslots> are necessay, and the value specified with this command have a more high priority. If the value of any of the three options is not specified, the corresponding value specified for the node object will be used. If any of the three attributes is neither specified with this command nor specified with the node object, error information will be returned. To reference to L<lsvm(1)|lsvm.1> for more information about 'drc_index' for I<vmphyslots>.
To specify the parameters which are used to create a partition. The I<vmcpus>, I<vmmemory> are necessay, and the value specified with this command have a more high priority. If the value of any of the three options is not specified, the corresponding value specified for the node object will be used. If any of the three attributes is neither specified with this command nor specified with the node object, error information will be returned. To reference to L<lsvm(1)|lsvm.1> for more information about 'drc_index' for I<vmphyslots>.
The option I<vios> is used to specify the partition that will be created is a VIOS partition. If specified, the value for I<vmstorage> shall be number which indicate the number of vSCSI server adapter will be created, and if no value specified for I<vmphyslots>, all the physical slot of the power machine will be asigned to VIOS partition. If not specified, it shall be in form of I<vios_name:server_slotid> to specify the vios and the virtual slot id of the vSCSI server adapter that will be connected from the Logical partition.
=item B<-f|--force>
@ -318,6 +321,32 @@ The output is similar to:
lpar1: 1/2/2
lpar1: 128.
10. To create a vios partition using some of the resources on normal power machine.
mkvm viosnode vmcpus=1/4/16 vmmemory=1G/4G/32G vmphyslots=0x21010201,0x21010200 vmnics=vlan1 vmstorage=5 --vios
The resouces for the node is similar to:
viosnode: Lpar Processor Info:
Curr Processor Min: 1.
Curr Processor Req: 4.
Curr Processor Max: 16.
viosnode: Lpar Memory Info:
Curr Memory Min: 1.00 GB(4 regions).
Curr Memory Req: 4.00 GB(16 regions).
Curr Memory Max: 32.00 GB(128 regions).
viosnode: 1,513,U78AA.001.WZSGVU7-P1-T7,0x21010201,0xc03(USB Controller)
viosnode: 1,512,U78AA.001.WZSGVU7-P1-T9,0x21010200,0x104(RAID Controller)
viosnode: 1,0,U8205.E6B.0612BAR-V1-C,0x30000000,vSerial Server
viosnode: 1,1,U8205.E6B.0612BAR-V1-C1,0x30000001,vSerial Server
viosnode: 1,3,U8205.E6B.0612BAR-V1-C3,0x30000003,vEth (port_vlanid=1,mac_addr=4211509276a7)
viosnode: 1,5,U8205.E6B.0612BAR-V1-C5,0x30000005,vSCSI Server
viosnode: 1,6,U8205.E6B.0612BAR-V1-C6,0x30000006,vSCSI Server
viosnode: 1,7,U8205.E6B.0612BAR-V1-C7,0x30000007,vSCSI Server
viosnode: 1,8,U8205.E6B.0612BAR-V1-C8,0x30000008,vSCSI Server
viosnode: 1,9,U8205.E6B.0612BAR-V1-C9,0x30000009,vSCSI Server
viosnode: 0/0/0
viosnode: 0.
=head1 FILES

View File

@ -0,0 +1,121 @@
=head1 B<NAME>
B<mkzone> - Defines a new zone in the cluster.
=head1 B<SYNOPSIS>
B<mkzone> <zonename> [B<--defaultzone>] [B<-k> I<full path to the ssh RSA private key>] [B<-a> I<noderange>] [B<-g>] [B<-f>] [B<-s> I<yes|no>] [-V]
B<mkzone> [B<-h> | B<-v>]
=head1 B<DESCRIPTION>
The B<mkzone> command is designed to divide the xCAT cluster into multiple zones. The nodes in each zone will share common root ssh keys. This allows the nodes in a zone to be able to as root ssh to each other without password, but cannot do the same to any node in another zone. All zones share a common xCAT Management Node and database including the site table, which defines the attributes of the entire cluster.
The mkzone command is only supported on Linux ( No AIX support).
The nodes are not updated with the new root ssh keys by mkzone. You must run updatenode -k or xdsh -K to the nodes to update the root ssh keys to the new generated zone keys. This will also sync any service nodes with the zone keys, if you have a hierarchical cluster.
Note: if any zones in the zone table, there must be one and only one defaultzone. Otherwise, errors will occur.
=head1 B<OPTIONS>
=over 5
=item B<-h>|B<--help>
Displays usage information.
=item B<-v>|B<--version>
Displays command version and build date.
=item B<-k | --sshkeypath> I<full path to the ssh RSA private key>
This is the path to the id_rsa key that will be used to build root's ssh keys for the zone. If -k is used, it will generate the ssh public key from the input ssh RSA private key and store both in /etc/xcat/sshkeys/<zonename>/.ssh directory.
If -f is not used, then it will generate a set of root ssh keys for the zone and store them in /etc/xcat/sshkeys/<zonename>/.ssh.
=item B<--default>
if --defaultzone is input, then it will set the zone defaultzone attribute to yes; otherwise it will set to no.
if --defaultzone is input and another zone is currently the default,
then the -f flag must be used to force a change to the new defaultzone.
If -f flag is not use an error will be returned and no change made.
Note: if any zones in the zone table, there must be one and only one defaultzone. Otherwise, errors will occur.
=item B<-a | --addnoderange> I<noderange>
For each node in the noderange, it will set the zonename attribute for that node to the input zonename.
If the -g flag is also on the command, then
it will add the group name "zonename" to each node in the noderange.
=item B<-s| --sshbetweennodes> B<yes|no>
If -s entered, the zone sshbetweennodes attribute will be set to yes or no. It defaults to yes. When this is set to yes, then ssh will be setup
to allow passwordless root access between nodes. If no, then root will be prompted for a password when running ssh between the nodes in the zone.
=item B<-f | --force>
Used with the (--defaultzone) flag to override the current default zone.
=item B<-g | --assigngroup>
Used with the (-a) flag to create the group zonename for all nodes in the input noderange.
=item B<-V>|B<--Verbose>
Verbose mode.
=back
=head1 B<Examples>
=over 3
=item *
To make a new zone1 using defaults , enter:
B<mkzone> I<zone1>
Note: with the first mkzone, you will automatically get the xcatdefault zone created as the default zone. This zone uses ssh keys from
<roothome>/.ssh directory.
=item *
To make a new zone2 using defaults and make it the default zone enter:
B<mkzone> I<zone2> --defaultzone -f
=item *
To make a new zone2A using the ssh id_rsa private key in /root/.ssh:
B<mkzone> I<zone2A> -k /root/.ssh
=item *
To make a new zone3 and assign the noderange compute3 to the zone enter:
B<mkzone> I<zone3> -a compute3
=item *
To make a new zone4 and assign the noderange compute4 to the zone and add zone4 as a group to each node enter:
B<mkzone> I<zone4> -a compute4 -g
=item *
To make a new zone5 and assign the noderange compute5 to the zone and add zone5 as a group to each node but not allow passwordless ssh between the nodes enter:
B<mkzone> I<zone5> -a compute5 -g -s no
=back
B<Files>
B</opt/xcat/bin/mkzone/>
Location of the mkzone command.
=head1 B<SEE ALSO>
L<chzone(1)|chzone.1>, L<rmzone(1)|rmzone.1>, L<xdsh(1)|xdsh.1>, L<updatenode(1)|updatenode.1>

View File

@ -0,0 +1,84 @@
=head1 B<NAME>
B<rmzone> - Removes a zone from the cluster.
=head1 B<SYNOPSIS>
B<rmzone> <zonename> [B<-g>] [B<-f>]
B<rmzone> [B<-h> | B<-v>]
=head1 B<DESCRIPTION>
The B<rmzone> command is designed to remove a previously defined zone from the cluster.
It will remove the zone entry in the zone table. It will remove the zone from the zonename attributes on the nodes that were assigned to the zone. Optionally, it will remove the zonename group from the nodes that were assigned to the zone.
It will also remove the root ssh keys that were created for that zone on the Management Node.
The rmzone command is only supported on Linux ( No AIX support).
The nodes are not automatically updated with new root ssh keys by rmzone. You must run updatenode -k or xdsh -K to the nodes to update the root ssh keys. The nodes new ssh key will be assigned from the defaultzone in the zone table, or if no entries in the zone table, the keys will come from /root/.ssh.
Note: if any zones in the zone table, there must be one and only one defaultzone. Otherwise, errors will occur.
=head1 B<OPTIONS>
=over 5
=item B<-h>|B<--help>
Displays usage information.
=item B<-v>|B<--version>
Displays command version and build date.
=item B<-f | --force>
Used to remove a zone that is defined as current default zone. This should only be done if you are removing all zones, or you will
adding a new zone or changing an existing zone to be the default zone.
=item B<-g | --assigngroup>
Remove the assigned group named B<zonename> from all nodes assigned to the zone being removed.
=item B<-V>|B<--Verbose>
Verbose mode.
=back
=head1 B<Examples>
=over 3
=item *
To remove zone1 from the zone table and the zonename attribute on all it's assigned nodes , enter:
B<rmzone> I<zone1>
=item *
To remove zone2 from the zone table, the zone2 zonename attribute, and the zone2 group assigned to all nodes that were in zone2, enter:
B<rmzone> I<zone2> -g
=item *
To remove zone3 from the zone table, all the node zone attributes and override the fact it is the defaultzone, enter:
B<rmzone> I<zone3> -g -f
=back
B<Files>
B</opt/xcat/bin/rmzone/>
Location of the rmzone command.
=head1 B<SEE ALSO>
L <mkzone(1)|mkzone.1>,L <chzone(1)|chzone.1>,L <xdsh(1)|xdsh.1>, L<updatenode(1)|updatenode.1>

View File

@ -8,6 +8,8 @@ B<updatenode> B<noderange> [B<-V>|B<--verbose>] [B<-F>|B<--sync>] [B<-f>|B<--sns
B<updatenode> B<noderange> [B<-k>|B<--security>] [B<-t timeout>]
B<updatenode> B<noderange> [B<-g>|B<--genmypost>]
B<updatenode> B<noderange> [B<-V>|B<--verbose>] [B<-t timeout>] [B<script1,script2...>]
B<updatenode> B<noderange> [B<-V>|B<--verbose>] [B<-f>|B<--snsync>]
@ -327,6 +329,11 @@ For statelite installations to sync files, you should use the
read-only option for files/directories listed in
litefile table with source location specified in the litetree table.
=item B<-g|--genmypost>
Will generate a new mypostscript file for the
nodes in the noderange, if site precreatemypostscripts is 1 or YES.
=item B<-h|--help>

View File

@ -435,6 +435,13 @@ Sets the command path to use on the targets. If B<DSH_PATH> is
not set, the default path defined in the profile of the
remote I<user_ID> is used.
=item B<DSH_REMOTE_PASSWORD>
If B<DSH_REMOTE_PASSWORD> is set to the password of the
userid (usually root) that will ssh to the node, then when
you use the -K flag, you will not be prompted for a password.
=item B<DSH_SYNTAX>
Specifies the shell syntax to use on remote targets; B<ksh> or

View File

@ -28,7 +28,7 @@ A network B<domain> and B<nameservers> values must be provided either in the B<n
Only entries in /etc/hosts or the hosts specified by B<noderange> that have a corresponding xCAT network definition will be added to DNS.
By default, B<makedns> sets up the B<named> service and updates the DNS records on the local system (mamagement node). If the -e flag is specified, it will also update the DNS records on any external DNS server that is listed in the /etc/resolv.conf on the management node. (Assuming the external DNS server can recognize the xCAT key as authentication.)
By default, B<makedns> sets up the B<named> service and updates the DNS records on the local system (management node). If the -e flag is specified, it will also update the DNS records on any external DNS server that is listed in the /etc/resolv.conf on the management node. (Assuming the external DNS server can recognize the xCAT key as authentication.)
For more information on Cluster Name Resolution:
https://sourceforge.net/apps/mediawiki/xcat/index.php?title=Cluster_Name_Resolution

View File

@ -12,7 +12,12 @@ B<mknb> I<arch>
The B<mknb> command is run by xCAT automatically, when xCAT is installed on the management node.
It creates a network boot root image (used for node discovery, BMC programming, and flashing)
for the same architecture that the management node is. So you normally do not need to run the B<mknb>
command yourself. Presently, only the arch x86_64 is supported.
command yourself.
If you do run B<mknb> to add custom utilities to your boot root image, and you have an xCAT Hierarchical Cluster with service nodes that each have a local /tftpboot directory (site sharedtftp=0), you will also need to copy the generated root image to each service node.
Presently, only the arch x86_64 is supported.
=head1 OPTIONS

View File

@ -6,11 +6,13 @@ B<tabprune> - Deletes records from the eventlog,auditlog,isnm_perf,isnm_perf_sum
B<tabprune> B<eventlog | auditlog> [B<-V>] B<-i> I<recid> |B<-n> I<number of records> | B<-p> I<percentage> | B<-d> I<number of days> | B<-a>
B<tabprune> B<tablename> B<-a>
B<tabprune> [B<-h>|B<--help>] [B<-v>|B<--version>]
=head1 DESCRIPTION
The tabprune command is used to delete records from the auditlog,eventlog,isnm_perf,isnm_perf_sum tables. As an option, the table header and all the rows pruned from the specified table will be displayed in CSV (comma separated values) format.
The tabprune command is used to delete records from the auditlog,eventlog,isnm_perf,isnm_perf_sum tables. As an option, the table header and all the rows pruned from the specified table will be displayed in CSV (comma separated values) format. The all records options (-a) can be used on any xCAT table.
=head1 OPTIONS
@ -27,7 +29,7 @@ you want to redirect them to a file to archive them.
=item B<-a>
Remove all records.
Remove all records from the input table name. This option can be used on any xCAT table.
=item B<-i> I<recid number>

View File

@ -25,6 +25,14 @@ if [ "$HOSTOS" = "mcp" ]; then
sed -i 's/ kexec//' $DRACUTMODDIR/install
sed -i 's/ klogd//' $DRACUTMODDIR/install
sed -i 's/ mdadm//' $DRACUTMODDIR/install
# These timezone files are not available in the latest mcp build
sed -i 's/dracut_install \/usr\/share\/zoneinfo\/posix\/Asia\/Riyadh87//' $DRACUTMODDIR/install
sed -i 's/dracut_install \/usr\/share\/zoneinfo\/posix\/Asia\/Riyadh88//' $DRACUTMODDIR/install
sed -i 's/dracut_install \/usr\/share\/zoneinfo\/posix\/Asia\/Riyadh89//' $DRACUTMODDIR/install
sed -i 's/dracut_install \/usr\/share\/zoneinfo\/posix\/Mideast\/Riyadh87//' $DRACUTMODDIR/install
sed -i 's/dracut_install \/usr\/share\/zoneinfo\/posix\/Mideast\/Riyadh88//' $DRACUTMODDIR/install
sed -i 's/dracut_install \/usr\/share\/zoneinfo\/posix\/Mideast\/Riyadh89//' $DRACUTMODDIR/install
fi
mkdir -p /tmp/xcatgenesis.$$/opt/xcat/share/xcat/netboot/genesis/`uname -m`/fs

View File

@ -103,7 +103,9 @@ done
echo -n "Acquired IPv4 address on $bootnic: "
ip addr show dev $bootnic|grep -v 'scope link'|grep -v 'dynamic'|grep -v inet6|grep inet|awk '{print $2}'
ntpd -g -x
(while ! ntpq -c "rv 0 state"|grep 'state=4' > /dev/null; do sleep 1; done; hwclock --systohc) &
# rv 0 state does not work with the new ntp versions
#(while ! ntpq -c "rv 0 state"|grep 'state=4' > /dev/null; do sleep 1; done; hwclock --systohc) &
(while [ "`ntpq -c \"rv 0 offset\" | grep \"offset=\" | awk -F \"=\" '{print $2}' | awk -F \".\" '{print $1}' | sed s/-//`" -ge 1000 ]; do sleep 1; done; hwclock --systohc) &
if dmidecode|grep IPMI > /dev/null; then
modprobe ipmi_si
modprobe ipmi_devintf

View File

@ -7,6 +7,6 @@ Standards-Version: 3.7.2
Package: xcat-server
Architecture: all
Depends: ${perl:Depends}, perl-xcat (>= 2.5.0-1), xcat-client (>= 2.5.0-1), libsys-syslog-perl, libio-socket-ssl-perl, libxml-simple-perl, make, libdbd-sqlite3-perl, libexpect-perl, libnet-dns-perl, libsoap-lite-perl, libxml-libxml-perl, libsnmp-perl, debootstrap
Depends: ${perl:Depends},grub2-xcat, perl-xcat (>= 2.5.0-1), xcat-client (>= 2.5.0-1), libsys-syslog-perl, libio-socket-ssl-perl, libxml-simple-perl, make, libdbd-sqlite3-perl, libexpect-perl, libnet-dns-perl, libsoap-lite-perl, libxml-libxml-perl, libsnmp-perl, debootstrap
Description: Server and configuration utilities of the xCAT management project
xCAT-server provides the core server and configuration management components of xCAT. This package should be installed on your management server

View File

@ -16,6 +16,7 @@ use xCAT::Utils;
use xCAT::TableUtils;
use xCAT::Template;
use xCAT::SvrUtils;
use xCAT::Zone;
#use Data::Dumper;
use File::Basename;
use Socket;
@ -186,10 +187,16 @@ sub makescript {
if($entries[0]) {
$installroot = $entries[0];
}
# Location of the customized template
my $tmpl="$installroot/postscripts/mypostscript.tmpl";
# if not customized template use the default
unless ( -r $tmpl) {
$tmpl="$::XCATROOT/share/xcat/templates/mypostscript/mypostscript.tmpl";
} else { # using customized template
# need to update with new added exports for this release
addexports($tmpl,$callback);
}
unless ( -r "$tmpl") {
@ -367,6 +374,16 @@ sub makescript {
}
$cloudinfo_hash = getcloudinfo($cloud_module_name, $cloud_exists);
}
# see if we are using zones. If we are then sshbetweennodes comes from the zone table not
# from the site table
my $usingzones;
if (xCAT::Zone->usingzones) {
$usingzones=1;
} else {
$usingzones=0;
}
foreach my $n (@$nodes ) {
$node = $n;
@ -477,9 +494,21 @@ sub makescript {
# for #INCLUDE_POSTBOOTSCRIPTS_LIST#
my $postbootscripts;
$postbootscripts = getPostbootScripts($node, $osimgname, $script_hash);
# if using zones then must go to the zone.sshbetweennodes
# else go to site.sshbetweennodes
my $enablesshbetweennodes;
my $zonename="\'\'";
if ($usingzones) {
$enablesshbetweennodes = enableSSHbetweennodeszones($node,$callback);
my $tmpzonename = xCAT::Zone->getmyzonename($node,$callback);
$zonename="\'";
$zonename .= $tmpzonename;
$zonename .="\'";
my $enablesshbetweennodes = enableSSHbetweennodes($node, \%::GLOBAL_SN_HASH, $groups_hash);
} else {
$enablesshbetweennodes = enableSSHbetweennodes($node, \%::GLOBAL_SN_HASH, $groups_hash);
}
my @clients;
my $cfgres;
my $cloudres;
@ -512,6 +541,7 @@ sub makescript {
$inc =~ s/#CLOUDINFO_EXPORT#/$cloudres/eg;
$inc =~ s/\$ENABLESSHBETWEENNODES/$enablesshbetweennodes/eg;
$inc =~ s/\$ZONENAME/$zonename/eg;
$inc =~ s/\$NSETSTATE/$nodesetstate/eg;
#$inc =~ s/#COMMAND:([^#]+)#/command($1)/eg;
@ -566,6 +596,69 @@ sub makescript {
}
}
#----------------------------------------------------------------------------
=head3 addexports
As we change the default mypostscript.tmpl, this routine will update
and existing customized template with the information
addexports($tmpl, $callback);
=cut
#-----------------------------------------------------------------------------
sub addexports
{
my $tmplfile = shift;
my $callback = shift;
# check for ZONENAME
my $cmd="cat $tmplfile \| grep ZONENAME";
my $result = xCAT::Utils->runcmd($cmd, -1);
if ($::RUNCMD_RC != 0) { # ZONENAME not in the customized template
$cmd = "cp $tmplfile $tmplfile.backup"; # backup the original
xCAT::Utils->runcmd($cmd, -1);
my $insertstr='ZONENAME=$ZONENAME';
my $insertstr2="export ZONENAME";
$cmd = "awk '{gsub(\"export ENABLESSHBETWEENNODES\",\"export ENABLESSHBETWEENNODES\\n$insertstr\\n$insertstr2 \"); print}' $tmplfile > $tmplfile.xcat";
xCAT::Utils->runcmd($cmd, 0);
if ($::RUNCMD_RC != 0)
{
my $rsp;
$rsp->{data}->[0] =
" Update of the $tmplfile file failed.";
xCAT::MsgUtils->message("SE", $rsp, $callback);
return 1;
}
$cmd = "cp -p $tmplfile.xcat $tmplfile "; # copy back the modified file
xCAT::Utils->runcmd($cmd, 0);
if ($::RUNCMD_RC != 0)
{
my $rsp;
$rsp->{data}->[0] =
" $cmd failed.";
xCAT::MsgUtils->message("SE", $rsp, $callback);
return 1;
}
$cmd = "rm $tmplfile.xcat ";
xCAT::Utils->runcmd($cmd, 0);
if ($::RUNCMD_RC != 0)
{
my $rsp;
$rsp->{data}->[0] =
" $cmd failed.";
xCAT::MsgUtils->message("SE", $rsp, $callback);
}
}
return 0;
}
sub getservicenode
{
# reads all nodes from the service node table
@ -792,7 +885,7 @@ sub getsshbetweennodes
Error:
none
Example:
my $enable = xCAT::TableUtils->enableSSH($node);
my $enable = xCAT::TableUtils->enableSSHbetweennodes($node,$sn_hash, $groups_hash);
Comments:
=cut
@ -818,6 +911,48 @@ sub enableSSHbetweennodes
}
#-------------------------------------------------------------------------------
=head3 enableSSHbetweennodeszones
Description: return how to fill in the ENABLESSHBETWEENNODES export in the mypostscript file
based on the setting in the zone table sshbetweennodes attribute
Arguments:
$node
$callback
Returns:
1 = enable ssh
0 = do not enable ssh
Globals:
none
Error:
none
Example:
my $enable = xCAT::TableUtils->enableSSHbetweennodeszones($node);
Comments:
=cut
#-----------------------------------------------------------------------------
sub enableSSHbetweennodeszones
{
my $node = shift;
my $callback = shift;
my $result;
my $enablessh=xCAT::Zone->enableSSHbetweennodes($node,$callback);
if ($enablessh == 1) {
$result = "'YES'";
} else {
$result = "'NO'";
}
return $result;
}

View File

@ -1215,6 +1215,7 @@ sub setup_TFTP
push @{$netmethods{$hmhash{$_}->[0]->{netboot}}}, $_;
}
}
$::DISABLENODESETWARNING=1; # stop the warnings about using install/netboot etc
$cmdref->{command}->[0] = "nodeset";
$cmdref->{inittime}->[0] = "1";
$cmdref->{arg}->[0] = "enact";

View File

@ -538,7 +538,7 @@ sub processArgs
# --nics is the equivalent of -i nicips,nichostnamesuffixes...
if ($::opt_nics) {
$::opt_i="nicips,nichostnamesuffixes,nihostnameprefixes,nictypes,niccustomscripts,nicnetworks,nicaliases";
$::opt_i="nicips,nichostnamesuffixes,nichostnameprefixes,nictypes,niccustomscripts,nicnetworks,nicaliases";
}
# -i and -s cannot be used together
@ -622,7 +622,8 @@ sub processArgs
# if it has an "=" sign its an attr=val - we hope
# - this will handle "attr= "
my ($attr, $value) = $a =~ /^\s*(\S+?)\s*=\s*(\S*.*)$/;
# The attribute itself might contain "space", like "nics.Local Connection Adapter 1" on windows
my ($attr, $value) = $a =~ /^\s*(.*?)\s*=\s*(\S*.*)$/;
if (!defined($attr) || !defined($value))
{
my $rsp;
@ -644,7 +645,7 @@ sub processArgs
my $nicattrs = 0;
foreach my $kattr (keys %::ATTRS)
{
if ($kattr =~ /^nic\w+\.\w+$/)
if ($kattr =~ /^nic\w+\..*$/)
{
$nicattrs = 1;
}
@ -850,7 +851,7 @@ sub processArgs
foreach my $dattr (@dispattrs)
{
# lsdef -t node -h -i nicips.eth0
if($dattr =~ /^(nic\w+)\.\w+$/)
if($dattr =~ /^(nic\w+)\..*$/)
{
$dattr = $1;
}
@ -1148,7 +1149,7 @@ sub processArgs
my $i = 0;
for ($i=0; $i < (scalar @::AttrList) ; $i++ )
{
if($::AttrList[$i] =~ /^(nic\w+)\.(\w+)$/)
if($::AttrList[$i] =~ /^(nic\w+)\.(.*)$/)
{
$::AttrList[$i] = $1;
push @{$::NicsAttrHash{$::AttrList[$i]}}, $2;
@ -1306,7 +1307,7 @@ sub defmk
{
my $attrorig = $attr;
# nicips.eth0 => nicips
if ($attr =~ /^(nic\w+)\.\w+$/)
if ($attr =~ /^(nic\w+)\..*$/)
{
$attr = $1;
}
@ -1950,7 +1951,7 @@ sub defch
{
my $attrorig = $attr;
# nicips.eth0 => nicips
if ($attr =~ /^(nic\w+)\.\w+$/)
if ($attr =~ /^(nic\w+)\..*$/)
{
$attr = $1;
}
@ -2638,7 +2639,7 @@ sub setFINALattrs
my %tmphash = ();
foreach my $nodeattr (keys %{$::CLIATTRS{$objname}})
{
if ($nodeattr =~ /^(nic\w+)\.\w+$/)
if ($nodeattr =~ /^(nic\w+)\..*$/)
{
my $tmpnicattr = $1;
if (!defined($tmphash{$tmpnicattr}))
@ -3411,7 +3412,7 @@ sub defls
my $rsp;
$rsp->{data}->[0] =
"Could not find an object named \'$obj\' of type \'$type\'.";
xCAT::MsgUtils->message("I", $rsp, $::callback);
xCAT::MsgUtils->message("E", $rsp, $::callback);
next;
}
}

View File

@ -63,7 +63,7 @@ sub preprocess_request
my @ents = xCAT::TableUtils->get_site_attribute("sharedtftp");
my $site_ent = $ents[0];
unless ( defined($site_ent)
and ($site_ent =~ /no/i or $site_ent =~ /0/))
and ($site_ent eq "no" or $site_ent eq "NO" or $site_ent eq "0"))
{
#unless requesting no sharedtftp, don't make hierarchical call
@ -257,6 +257,7 @@ sub mknetboot
my $site_ent = $ents[0];
if (!defined($site_ent) || ($site_ent =~ /no/i) || ($site_ent =~ /0/))
{
if (!defined($::DISABLENODESETWARNING)) { # set by AAsn.pm
$callback->(
{
warning => ["The options \"install\", \"netboot\", and \"statelite\" have been deprecated. They should continue to work in this release, but have not been tested as carefully, and some new functions are not available with these options. For full function and support, use \"nodeset <noderange> osimage=<osimage_name>\" instead."],
@ -264,6 +265,7 @@ sub mknetboot
);
# Do not print this warning message multiple times
last;
}
}
}
}
@ -930,10 +932,6 @@ sub mknetboot
);
}
#my $rc = xCAT::TableUtils->create_postscripts_tar();
#if ( $rc != 0 ) {
# xCAT::MsgUtils->message( "S", "Error creating postscripts tar file." );
#}
}
sub mkinstall
@ -1001,6 +999,7 @@ sub mkinstall
my $site_ent = $ents[0];
if (!defined($site_ent) || ($site_ent =~ /no/i) || ($site_ent =~ /0/))
{
if (!defined($::DISABLENODESETWARNING)) { # set by AAsn.pm
$callback->(
{
warning => ["The options \"install\", \"netboot\", and \"statelite\" have been deprecated. They should continue to work in this release, but have not been tested as carefully, and some new functions are not available with these options. For full function and support, use \"nodeset <noderange> osimage=<osimage_name>\" instead."],
@ -1008,6 +1007,7 @@ sub mkinstall
);
# Do not print this warning message multiple times
last;
}
}
}
}
@ -1577,6 +1577,7 @@ sub mksysclone
my $site_ent = $ents[0];
if (!defined($site_ent) || ($site_ent =~ /no/i) || ($site_ent =~ /0/))
{
if (!defined($::DISABLENODESETWARNING)) { # set by AAsn.pm
$callback->(
{
warning => ["The options \"install\", \"netboot\", and \"statelite\" have been deprecated. They should continue to work in this release, but have not been tested as carefully, and some new functions are not available with these options. For full function and support, use \"nodeset <noderange> osimage=<osimage_name>\" instead."],
@ -1584,6 +1585,7 @@ sub mksysclone
);
# Do not print this warning message multiple times
last;
}
}
}
}

View File

@ -4423,7 +4423,7 @@ sub process_request {
if ($request->{mtm} and $request->{mtm} =~ /^(\w{4})/) {
my $group = xCAT::data::ibmhwtypes::parse_group($request->{mtm});
if (defined($group)) {
xCAT::TableUtils->updatenodegroups($node, $group);
xCAT::TableUtils->updatenodegroups($node, $group.",all");
}
}
if ($mac) {

View File

@ -43,6 +43,7 @@ sub process_request {
my $path=undef;
my $noosimage=undef;
my $nonoverwrite=undef;
my $specific=undef;
$identified=0;
$::CDMOUNTPATH="/var/run/xcat/mountpoint";
@ -58,6 +59,7 @@ sub process_request {
'i|inspection' => \$inspection,
'p|path=s' => \$path,
'o|noosimage' => \$noosimage,
's|specific' => \$specific,
'w|nonoverwrite' => \$nonoverwrite,
);
if ($help) {
@ -143,6 +145,10 @@ sub process_request {
{
push @{$newreq->{arg}},("-p",$path);
}
if($specific)
{
push @{$newreq->{arg}},("-s");
}
if($inspection)
{

View File

@ -28,6 +28,7 @@ use strict;
use xCAT::Table;
use Data::Dumper;
use xCAT::NodeRange;
use xCAT::Zone;
use IO::Socket::INET;
use Time::HiRes qw(sleep);
@ -112,34 +113,71 @@ sub process_request
} else {
$root = "/root";
}
foreach my $parm (@params_to_return) {
# if paramter is ssh_root_key or ssh_root_pub_key then
# we need to see if a zonename is attached
# it comes in as ssh_root_key:zonename
# if zonename then we need to read the keys from the zone table sshkeydir attribute
my $errorfindingkeys=0;
my $foundkeys=0;
my $sshrootkeydir="$root/.ssh"; # old default
if ((($parm =~ /^ssh_root_key/) || ($parm =~ /^ssh_root_pub_key/)) && ($foundkeys==0)){
my ($rootkeyparm,$zonename) = split(/:/,$parm);
if ($zonename) {
$parm=$rootkeyparm; # take the zone off
`logger -t xCAT -p local4.info "credentials: The node is asking for zone:$zonename sshkeys ."`;
$sshrootkeydir = xCAT::Zone->getzonekeydir($zonename);
if ($sshrootkeydir == 1) { # error return
`logger -t xCAT -p local4.info "credentials: The node is asking for zone:$zonename sshkeys and the $zonename is not defined."`;
} else {
$foundkeys=1; # don't want to read the zone data twice
}
}
}
foreach (@params_to_return) {
if (/ssh_root_key/) {
unless (-r "$root/.ssh/id_rsa") {
if ($parm =~ /ssh_root_key/) {
unless (-r "$sshrootkeydir/id_rsa") {
push @{$rsp->{'error'}},"Unable to read root's private ssh key";
`logger -t xCAT -p local4.info "credentials: Unable to read root's private ssh key"` ;
next;
}
$tfilename = "$root/.ssh/id_rsa";
`logger -t xCAT -p local4.info "credentials: sending $parm"` ;
$tfilename = "$sshrootkeydir/id_rsa";
`logger -t xCAT -p local4.info "credentials: The ssh root private key is in $tfilename."`;
} elsif (/xcat_server_cred/) {
} elsif ($parm =~ /ssh_root_pub_key/) {
unless (-r "$sshrootkeydir/id_rsa.pub") {
push @{$rsp->{'error'}},"Unable to read root's public ssh key";
`logger -t xCAT -p local4.info "credentials: Unable to read root's public ssh key"` ;
next;
}
`logger -t xCAT -p local4.info "credentials: sending $parm"` ;
$tfilename = "$sshrootkeydir/id_rsa.pub";
`logger -t xCAT -p local4.info "credentials: The ssh root public key is in $tfilename."`;
} elsif ($parm =~ /xcat_server_cred/) {
unless (-r "/etc/xcat/cert/server-cred.pem") {
push @{$rsp->{'error'}},"Unable to read xcat_server_cred";
`logger -t xCAT -p local4.info "credentials: Unable to read xcat_server_cred"` ;
next;
}
`logger -t xCAT -p local4.info "credentials: sending $parm"` ;
$tfilename = "/etc/xcat/cert/server-cred.pem";
} elsif (/xcat_client_cred/ or /xcat_root_cred/) {
} elsif (($parm =~ /xcat_client_cred/) or ($parm =~ /xcat_root_cred/)) {
unless (-r "$root/.xcat/client-cred.pem") {
push @{$rsp->{'error'}},"Unable to read xcat_client_cred or xcat_root_cred";
`logger -t xCAT -p local4.info "credentials: Unable to read xcat_client_cred or xcat_root_cred"` ;
next;
}
`logger -t xCAT -p local4.info "credentials: sending $parm"` ;
$tfilename = "$root/.xcat/client-cred.pem";
} elsif (/ssh_dsa_hostkey/) {
} elsif ($parm =~ /ssh_dsa_hostkey/) {
`logger -t xCAT -p local4.info "credentials: sending $parm"` ;
if (-r "/etc/xcat/hostkeys/$client/ssh_host_dsa_key") {
$tfilename="/etc/xcat/hostkeys/$client/ssh_host_dsa_key";
} elsif (-r "/etc/xcat/hostkeys/ssh_host_dsa_key") {
@ -149,7 +187,8 @@ sub process_request
`logger -t xCAT -p local4.info "credentials: Unable to read private DSA key"` ;
next;
}
} elsif (/ssh_rsa_hostkey/) {
} elsif ($parm =~ /ssh_rsa_hostkey/) {
`logger -t xCAT -p local4.info "credentials: sending $parm"` ;
if (-r "/etc/xcat/hostkeys/$client/ssh_host_rsa_key") {
$tfilename="/etc/xcat/hostkeys/$client/ssh_host_rsa_key";
} elsif (-r "/etc/xcat/hostkeys/ssh_host_rsa_key") {
@ -159,7 +198,8 @@ sub process_request
`logger -t xCAT -p local4.info "credentials: Unable to read private RSA key"` ;
next;
}
} elsif (/xcat_cfgloc/) {
} elsif ($parm =~ /xcat_cfgloc/) {
`logger -t xCAT -p local4.info "credentials: sending $parm"` ;
unless (-r "/etc/xcat/cfgloc") {
push @{$rsp->{'error'}},"Unable to read /etc/xcat/cfgloc ";
`logger -t xCAT -p local4.info "credentials: Unable to read /etc/xcat/cfgloc"` ;
@ -167,7 +207,8 @@ sub process_request
}
$tfilename = "/etc/xcat/cfgloc";
} elsif (/krb5_keytab/) { #TODO: MUST RELAY TO MASTER
} elsif ($parm =~ /krb5_keytab/) { #TODO: MUST RELAY TO MASTER
`logger -t xCAT -p local4.info "credentials: sending $parm"` ;
my $princsuffix=$request->{'_xcat_clientfqdn'}->[0];
$ENV{KRB5CCNAME}="/tmp/xcat/krb5cc_xcat_$$";
system('kinit -S kadmin/admin -k -t /etc/xcat/krb5_pass xcat/admin');
@ -188,10 +229,11 @@ sub process_request
while (read($keytab,$buf,1140)) {
$tabdata.=MIME::Base64::encode_base64($buf);
}
push @{$rsp->{'data'}},{content=>[$tabdata],desc=>[$_]};
push @{$rsp->{'data'}},{content=>[$tabdata],desc=>[$parm]};
unlink "/tmp/xcat/keytab.$$";
next;
} elsif (/x509cert/) {
} elsif ($parm =~ /x509cert/) {
`logger -t xCAT -p local4.info "credentials: sending $parm"` ;
my $csr = $request->{'csr'}->[0];
my $csrfile;
my $oldumask = umask 0077;
@ -243,7 +285,7 @@ sub process_request
close($csrfile);
unlink "/tmp/xcat/client.cert.$$";
my $certcontents = join('',@certdata);
push @{$rsp->{'data'}},{content=>[$certcontents],desc=>[$_]};
push @{$rsp->{'data'}},{content=>[$certcontents],desc=>[$parm]};
} else {
next;
}
@ -253,7 +295,7 @@ sub process_request
@filecontent=<$tmpfile>;
close($tmpfile);
$retdata = "\n".join('',@filecontent);
push @{$rsp->{'data'}},{content=>[$retdata],desc=>[$_]};
push @{$rsp->{'data'}},{content=>[$retdata],desc=>[$parm]};
$retdata="";
@filecontent=();
}
@ -261,6 +303,7 @@ sub process_request
if (defined $rsp->{data}->[0]) {
#if we got the data from the file, send the data message to the client
xCAT::MsgUtils->message("D", $rsp, $callback, 0);
return;
}else {
#if the file doesn't exist, send the error message to the client
delete $rsp->{'data'};

View File

@ -389,7 +389,8 @@ sub process_request {
# - need domain for this node
my $host = $nodehash{$n}{host};
$domain=$nodedomains{$host};
unless ($domain =~ /^\./) { $domain = '.'.$domain; }
# remove the first . at domain name since it's not accepted by high dns parser
if ($domain =~ /^\./) { $domain =~ s/^\.//;; }
($canonical,$aliasstr) = split /[ \t]+/,$names,2;
if ($aliasstr) {
@ -403,13 +404,13 @@ sub process_request {
xCAT::SvrUtils::sendmsg(":Handling $node in /etc/hosts.", $callback);
unless ($canonical =~ /$domain/) {
$canonical.=$domain;
$canonical.=".".$domain;
}
# for only the sake of comparison, ensure consistant dot suffix
unless ($canonical =~ /\.\z/) { $canonical .= '.' }
foreach my $alias (@aliases) {
unless ($alias =~ /$domain/) {
$alias .= $domain;
$alias .= ".".$domain;
}
unless ($alias =~ /\.\z/) {
$alias .= '.';
@ -504,9 +505,11 @@ sub process_request {
$ctx->{slaves}=\@slave_ips;
}
$ctx->{domain} =~ s/^\.//; # remove . if it's the first char of domain name
$ctx->{zonestotouch}->{$ctx->{domain}}=1;
foreach (@networks) {
if ($_->{domain}) {
$_->{domain} =~ s/^\.//; # remove . if it's the first char of domain name
$ctx->{zonestotouch}->{$_->{domain}}=1;
}
}
@ -792,11 +795,11 @@ sub update_zones {
xCAT::SvrUtils::sendmsg("Updating zones.", $callback);
unless ($domain =~ /^\./) {
$domain = '.'.$domain;
if ($domain =~ /^\./) { # remove . if it's the first char of domain name
$domain =~ s/^\.//;
}
unless ($name =~ /\./) {
$name .= $domain;
$name .= ".".$domain;
}
unless ($name =~ /\.\z/) {
$name .= '.';
@ -1161,9 +1164,9 @@ sub add_or_delete_records {
}
my $domain = $nodedomains{$node};
unless ($domain =~ /^\./) { $domain = '.'.$domain; }
if ($domain =~ /^\./) { $domain =~ s/^\.//; } # remove . if it's the first char of domain name
unless ($name =~ /$domain/) { $name .= $domain } # $name needs to represent fqdn, but must preserve $node as a nodename for cfg lookup
unless ($name =~ /$domain/) { $name .= ".".$domain } # $name needs to represent fqdn, but must preserve $node as a nodename for cfg lookup
if ($ctx->{hoststab} and $ctx->{hoststab}->{$node} and $ctx->{hoststab}->{$node}->[0]->{ip}) {
@ips = ($ctx->{hoststab}->{$node}->[0]->{ip});

View File

@ -75,9 +75,9 @@ sub preprocess_request
my $stab = xCAT::Table->new('site');
my $sent;
($sent) = $stab->getAttribs({key => 'sharedtftp'}, 'value');
unless ( $sent
and defined($sent->{value})
and ($sent->{value} =~ /no/i or $sent->{value} =~ /0/))
unless ( $sent
and defined($sent->{value})
and ($sent->{value} eq "no" or $sent->{value} eq "NO" or $sent->{value} eq "0"))
{
#unless requesting no sharedtftp, don't make hierarchical call

View File

@ -285,6 +285,23 @@ sub setdestiny {
}
}
#if the postscripts directory exists then make sure it is
# world readable and executable by root; otherwise wget fails
my $installdir = xCAT::TableUtils->getInstallDir();
my $postscripts = "$installdir/postscripts";
if (-e $postscripts)
{
my $cmd = "chmod -R a+r $postscripts";
xCAT::Utils->runcmd($cmd, 0);
my $rsp = {};
if ($::RUNCMD_RC != 0)
{
$callback->({info=>"$cmd failed"});
}
}
#print Dumper($req);
# if precreatemypostscripts=1, create each mypostscript for each node

View File

@ -881,6 +881,37 @@ sub check_options
xCAT::MsgUtils->message("I", $rsp, $callback, 0);
return 0;
}
# if not help and not -n, dhcpd needs to be running
if (!($opt->{h})&& (!($opt->{n}))) {
if (xCAT::Utils->isLinux()) {
my @output = xCAT::Utils->runcmd("service dhcpd status", -1);
if ($::RUNCMD_RC != 0) { # not running
my $rsp = {};
$rsp->{data}->[0] = "dhcpd is not running. Run service dhcpd start and rerun your command.";
xCAT::MsgUtils->message("E", $rsp, $callback, 1);
return 1;
}
} else { # AIX
my @output = xCAT::Utils->runcmd("lssrc -s dhcpsd ", -1);
if ($::RUNCMD_RC != 0) { # not running
my $rsp = {};
$rsp->{data}->[0] = "dhcpsd is not running. Run startsrc -s dhcpsd and rerun your command.";
xCAT::MsgUtils->message("E", $rsp, $callback, 1);
return 1;
} else { # check the status
# the return output varies, sometime status is the third sometimes the 4th col
if (grep /inoperative/, @output)
{
my $rsp = {};
$rsp->{data}->[0] = "dhcpsd is not running. Run startsrc -s dhcpsd and rerun your command.";
xCAT::MsgUtils->message("E", $rsp, $callback, 1);
return 1;
}
}
}
}
# check to see if -q is listed with any other options which is not allowed
if ($opt->{q} and ($opt->{a} || $opt->{d} || $opt->{n} || $opt->{r} || $opt->{l} || $statements)) {
@ -956,7 +987,7 @@ sub preprocess_request
if ( $rc ) {
return [];
}
my $snonly=0;
my @entries = xCAT::TableUtils->get_site_attribute("disjointdhcps");
my $t_entry = $entries[0];
@ -1442,7 +1473,7 @@ sub process_request
next;
}
}
if ($ent[1] =~ m/(remote|ipoib|ib|vlan|bond|eth|myri|man|wlan|en\d+|em\d+)/)
if ($ent[1] =~ m/(remote|ipoib|ib|vlan|bond|eth|myri|man|wlan|en\S*\d+|em\S*\d+)/)
{ #Mask out many types of interfaces, like xCAT 1.x
$activenics{$ent[1]} = 1;
}

View File

@ -4141,10 +4141,12 @@ sub copycd {
}
#}
@ARGV = @{$request->{arg}};
my $includeupdate = 0;
GetOptions(
'n=s' => \$distname,
'a=s' => \$arch,
'm=s' => \$path
'm=s' => \$path,
's' => \$includeupdate
);
# run a few tests to see if the copycds should use this plugin
unless ($path){
@ -4236,6 +4238,34 @@ sub copycd {
}
}
close(LINE);
} elsif (-r $path . "/upgrade/metadata.xml") {
open(LINE,$path."/upgrade/metadata.xml");
my $detectdistname;
while (<LINE>) {
if (/esxVersion>([^<]*)</) {
my $version = $1;
while ($version =~ /\.0$/) {
$version =~ s/\.0$//;
}
$darch="x86_64";
$arch="x86_64";
$detectdistname = 'esxi' . $version;
$found=1;
} elsif (/esxRelease>([^<]*)</) {
unless ($includeupdate) {
next;
}
my $release = $1;
while ($release =~ /\.0$/) {
$release =~ s/\.0$//;
}
unless ($release ne "0") {
next;
}
$detectdistname .= '_' . $release;
}
}
unless ($distname) { $distname=$detectdistname; }
} elsif (-r $path . "/vmware-esx-base-readme") {
open(LINE,$path."/vmware-esx-base-readme");
while (<LINE>) {

View File

@ -0,0 +1,630 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::grub2;
use Data::Dumper;
use Sys::Syslog;
use xCAT::Scope;
use xCAT::Utils;
use xCAT::TableUtils;
use xCAT::ServiceNodeUtils;
use xCAT::NetworkUtils;
use xCAT::MsgUtils;
use File::Path;
use Socket;
use Getopt::Long;
use xCAT::Table;
my $request;
my %breaknetbootnodes;
our %normalnodes;
my %tftpserverip;
my $callback;
my $sub_req;
my $globaltftpdir = xCAT::TableUtils->getTftpDir();
my %usage = (
"nodeset" => "Usage: nodeset <noderange> [install|shell|boot|runcmd=bmcsetup|netboot|iscsiboot|osimage[=<imagename>]|offline]",
);
sub handled_commands {
return {
nodeset => "noderes:netboot"
}
}
sub check_dhcp {
return 1;
#TODO: omapi magic to do things right
my $node = shift;
my $dhcpfile;
open ($dhcpfile,$dhcpconf);
while (<$dhcpfile>) {
if (/host $node\b/) {
close $dhcpfile;
return 1;
}
}
close $dhcpfile;
return 0;
}
sub _slow_get_tftpdir { #make up for paths where tftpdir is not passed in
my $node=shift;
my $nrtab = xCAT::Table->new('noderes',-create=>0); #in order to detect per-node tftp directories
unless ($nrtab) { return $globaltftpdir; }
my $ent = $nrtab->getNodeAttribs($node,["tftpdir"]);
if ($ent and $ent->{tftpdir}) {
return $ent->{tftpdir};
} else {
return $globaltftpdir;
}
}
sub getstate {
my $node = shift;
my $tftpdir = shift;
unless ($tftpdir) { $tftpdir = _slow_get_tftpdir($node); }
if (check_dhcp($node)) {
if (-r $tftpdir . "/boot/grub2/".$node) {
my $fhand;
open ($fhand,$tftpdir . "/boot/grub2/".$node);
my $headline = <$fhand>;
close $fhand;
$headline =~ s/^#//;
chomp($headline);
return $headline;
} else {
return "boot";
}
} else {
return "discover";
}
}
sub setstate {
=pod
This function will manipulate the grub structure to match what the noderes/chain tables indicate the node should be booting.
=cut
my $node = shift;
my %bphash = %{shift()};
my %chainhash = %{shift()};
my %machash = %{shift()};
my $tftpdir = shift;
my %nrhash = %{shift()};
my $linuximghash = shift();
my $kern = $bphash{$node}->[0]; #$bptab->getNodeAttribs($node,['kernel','initrd','kcmdline']);
if ($kern->{kcmdline} =~ /!myipfn!/) {
my $ipfn = xCAT::NetworkUtils->my_ip_facing($node);
unless ($ipfn) {
my $servicenodes = $nrhash{$node}->[0];
if ($servicenodes and $servicenodes->{servicenode}) {
my @sns = split /,/, $servicenodes->{servicenode};
foreach my $sn ( @sns ) {
# We are in the service node pools, print error if no facing ip.
if (xCAT::InstUtils->is_me($sn)) {
my @myself = xCAT::NetworkUtils->determinehostname();
my $myname = $myself[(scalar @myself)-1];
$::callback->(
{
error => [
"$myname: Unable to determine the image server for $node on service node $sn"
],
errorcode => [1]
}
);
return;
}
}
} else {
$::callback->(
{
error => [
"$myname: Unable to determine the image server for $node"
],
errorcode => [1]
}
);
return;
}
} else {
$kern->{kcmdline} =~ s/!myipfn!/$ipfn/g;
}
}
if ($kern->{addkcmdline}) {
$kern->{kcmdline} .= " ".$kern->{addkcmdline};
}
if($linuximghash and $linuximghash->{'addkcmdline'})
{
unless($linuximghash->{'boottarget'})
{
$kern->{kcmdline} .= " ".$linuximghash->{'addkcmdline'};
}
}
my $pcfg;
unless (-d "$tftpdir/boot/grub2") {
mkpath("$tftpdir/boot/grub2");
}
my $nodemac;
my %client_nethash = xCAT::DBobjUtils->getNetwkInfo( [$node] );
open($pcfg,'>',$tftpdir."/boot/grub2/".$node);
my $cref=$chainhash{$node}->[0]; #$chaintab->getNodeAttribs($node,['currstate']);
if ($cref->{currstate}) {
print $pcfg "#".$cref->{currstate}."\n";
}
print $pcfg "set timeout=5\n";
$normalnodes{$node}=1; #Assume a normal netboot (well, normal dhcp,
#which is normally with a valid 'filename' field,
#but the typical ppc case will be 'special' makedhcp
#to clear the filename field, so the logic is a little
#opposite
if ($cref and $cref->{currstate} eq "boot") {
$breaknetbootnodes{$node}=1;
delete $normalnodes{$node}; #Signify to omit this from one makedhcp command
close($pcfg);
} elsif ($kern and $kern->{kernel}) {
#It's time to set grub configuration for this node to boot the kernel..
#get tftpserver
my $tftpserver;
if (defined ($nrhash{$node}->[0]) && $nrhash{$node}->[0]->{'tftpserver'}) {
$tftpserver = $nrhash{$node}->[0]->{'tftpserver'};
} elsif (defined ($nrhash{$node}->[0]) && $nrhash{$node}->[0]->{'xcatmaster'}) {
$tftpserver = $nrhash{$node}->[0]->{'xcatmaster'};
} else {
my @master = xCAT::TableUtils->get_site_attribute("master");
$tftpserver = $master[0];
}
my $serverip;
if (defined ($tftpserverip{$tftpserver})) {
$serverip = $tftpserverip{$tftpserver};
} else {
$serverip = xCAT::NetworkUtils->getipaddr($tftpserver);
unless ($serverip) {
syslog("local1|err","xCAT unable to resolve $tftpserver");
return;
}
$tftpserverip{$tftpserver} = $serverip;
}
print $pcfg "set default=\"xCAT OS Deployment\"\n";
print $pcfg "menuentry \"xCAT OS Deployment\" {\n";
print $pcfg " insmod http\n";
print $pcfg " insmod tftp\n";
print $pcfg " set root=http,$serverip\n";
print $pcfg " echo Loading Install kernel ...\n";
if ($kern and $kern->{kcmdline}) {
print $pcfg " linux $tftpdir/$kern->{kernel} $kern->{kcmdline}\n";
} else {
print $pcfg " linux $tftpdir/$kern->{kernel}\n";
}
print $pcfg " echo Loading initial ramdisk ...\n";
if ($kern and $kern->{initrd}) {
print $pcfg " initrd $tftpdir/$kern->{initrd}\n";
}
print $pcfg "}";
close($pcfg);
my $inetn = xCAT::NetworkUtils->getipaddr($node);
unless ($inetn) {
syslog("local1|err","xCAT unable to resolve IP for $node in grub2 plugin");
return;
}
} else {
close($pcfg);
}
my $ip = xCAT::NetworkUtils->getipaddr($node);
unless ($ip) {
syslog("local1|err","xCAT unable to resolve IP in grub2 plugin");
return;
}
my $mactab = xCAT::Table->new('mac');
my %ipaddrs;
$ipaddrs{$ip} = 1;
if ($mactab) {
my $ment = $machash{$node}->[0]; #$mactab->getNodeAttribs($node,['mac']);
if ($ment and $ment->{mac}) {
my @macs = split(/\|/,$ment->{mac});
foreach (@macs) {
$nodemac = $_;
if (/!(.*)/) {
my $ipaddr = xCAT::NetworkUtils->getipaddr($1);
if ($ipaddr) {
$ipaddrs{$ipaddr} = 1;
}
}
}
}
}
# Do not use symbolic link, p5 does not support symbolic link in /tftpboot
# my $hassymlink = eval { symlink("",""); 1 };
foreach $ip (keys %ipaddrs) {
my @ipa=split(/\./,$ip);
my $pname = "grub.cfg-" . sprintf("%02x%02x%02x%02x",@ipa);
unlink($tftpdir."/boot/grub2/".$pname);
link($tftpdir."/boot/grub2/".$node,$tftpdir."/boot/grub2/".$pname);
}
if ($nodemac =~ /:/) {
my $tmp = $nodemac;
$tmp =~ s/(..):(..):(..):(..):(..):(..)/$1-$2-$3-$4-$5-$6/g;
my $pname = "grub.cfg-01-" . $tmp;
unlink($tftpdir."/boot/grub2/".$pname);
link($tftpdir."/boot/grub2/".$node,$tftpdir."/boot/grub2/".$pname);
}
return;
}
my $errored = 0;
sub pass_along {
my $resp = shift;
$callback->($resp);
if ($resp and ($resp->{errorcode} and $resp->{errorcode}->[0]) or ($resp->{error} and $resp->{error}->[0])) {
$errored=1;
}
foreach (@{$resp->{node}}) {
if ($_->{error} or $_->{errorcode}) {
$errored=1;
}
}
}
sub preprocess_request {
my $req = shift;
if ($req->{_xcatpreprocessed}->[0] == 1) { return [$req]; }
my $callback1 = shift;
my $command = $req->{command}->[0];
my $sub_req = shift;
my @args=();
if (ref($req->{arg})) {
@args=@{$req->{arg}};
} else {
@args=($req->{arg});
}
@ARGV = @args;
my $nodes = $req->{node};
#use Getopt::Long;
Getopt::Long::Configure("bundling");
Getopt::Long::Configure("pass_through");
if (!GetOptions('h|?|help' => \$HELP, 'v|version' => \$VERSION) ) {
if($usage{$command}) {
my %rsp;
$rsp{data}->[0]=$usage{$command};
$callback1->(\%rsp);
}
return;
}
if ($HELP) {
if($usage{$command}) {
my %rsp;
$rsp{data}->[0]=$usage{$command};
$callback1->(\%rsp);
}
return;
}
if ($VERSION) {
my $ver = xCAT::Utils->Version();
my %rsp;
$rsp{data}->[0]="$ver";
$callback1->(\%rsp);
return;
}
if (@ARGV==0) {
if($usage{$command}) {
my %rsp;
$rsp{data}->[0]=$usage{$command};
$callback1->(\%rsp);
}
return;
}
#Assume shared tftp directory for boring people, but for cool people, help sync up tftpdirectory contents when
#if they specify no sharedtftp in site table
my @entries = xCAT::TableUtils->get_site_attribute("sharedtftp");
my $t_entry = $entries[0];
if ( defined($t_entry) and ($t_entry eq "0" or $t_entry eq "no" or $t_entry eq "NO")) {
# check for computenodes and servicenodes from the noderange, if so error out
my @SN;
my @CN;
xCAT::ServiceNodeUtils->getSNandCPnodes(\@$nodes, \@SN, \@CN);
unless (($args[0] eq 'stat') or ($args[0] eq 'enact')) {
if ((@SN > 0) && (@CN >0 )) { # there are both SN and CN
my $rsp;
$rsp->{data}->[0] =
"Nodeset was run with a noderange containing both service nodes and compute nodes. This is not valid. You must submit with either compute nodes in the noderange or service nodes. \n";
xCAT::MsgUtils->message("E", $rsp, $callback1);
return;
}
}
$req->{'_disparatetftp'}=[1];
if ($req->{inittime}->[0]) {
return [$req];
}
if (@CN >0 ) { # if compute nodes broadcast to all servicenodes
return xCAT::Scope->get_broadcast_scope($req,@_);
}
}
return [$req];
}
sub process_request {
$request = shift;
$callback = shift;
$::callback=$callback;
$sub_req = shift;
my $command = $request->{command}->[0];
%breaknetbootnodes=();
%normalnodes=();
my @args;
my @nodes;
my @rnodes;
if (ref($request->{node})) {
@rnodes = @{$request->{node}};
} else {
if ($request->{node}) { @rnodes = ($request->{node}); }
}
unless (@rnodes) {
if ($usage{$request->{command}->[0]}) {
$callback->({data=>$usage{$request->{command}->[0]}});
}
return;
}
#if not shared tftpdir, then filter, otherwise, set up everything
if ($request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
@nodes = ();
foreach (@rnodes) {
if (xCAT::NetworkUtils->nodeonmynet($_)) {
push @nodes,$_;
} else {
xCAT::MsgUtils->message("S", "$_: grub2 netboot: stop configuration because of none sharedtftp and not on same network with its xcatmaster.");
}
}
} else {
@nodes = @rnodes;
}
# return directly if no nodes in the same network
unless (@nodes) {
xCAT::MsgUtils->message("S", "xCAT: grub2 netboot: no valid nodes. Stop the operation on this server.");
return;
}
if (ref($request->{arg})) {
@args=@{$request->{arg}};
} else {
@args=($request->{arg});
}
#now run the begin part of the prescripts
unless ($args[0] eq 'stat') { # or $args[0] eq 'enact') {
$errored=0;
if ($request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children
$sub_req->({command=>['runbeginpre'],
node=>\@nodes,
arg=>[$args[0], '-l']},\&pass_along);
} else { #nodeset did not distribute to the service node, here we need to let runednpre to distribute the nodes to their masters
$sub_req->({command=>['runbeginpre'],
node=>\@rnodes,
arg=>[$args[0]]},\&pass_along);
}
if ($errored) {
my $rsp;
$rsp->{errorcode}->[0]=1;
$rsp->{error}->[0]="Failed in running begin prescripts.\n";
$callback->($rsp);
return;
}
}
#back to normal business
my $inittime=0;
if (exists($request->{inittime})) { $inittime= $request->{inittime}->[0];}
if (!$inittime) { $inittime=0;}
$errored=0;
unless ($args[0] eq 'stat') { # or $args[0] eq 'enact') {
$sub_req->({command=>['setdestiny'],
node=>\@nodes,
inittime=>[$inittime],
arg=>\@args},\&pass_along);
}
if ($errored) { return; }
my $bptab=xCAT::Table->new('bootparams',-create=>1);
my $bphash = $bptab->getNodesAttribs(\@nodes,['kernel','initrd','kcmdline','addkcmdline']);
my $chaintab=xCAT::Table->new('chain',-create=>1);
my $chainhash=$chaintab->getNodesAttribs(\@nodes,['currstate']);
my $noderestab=xCAT::Table->new('noderes',-create=>1);
my $nodereshash=$noderestab->getNodesAttribs(\@nodes,['tftpdir']);
my $mactab=xCAT::Table->new('mac',-create=>1);
my $machash=$mactab->getNodesAttribs(\@nodes,['mac']);
my $nrtab=xCAT::Table->new('noderes',-create=>1);
my $nrhash=$nrtab->getNodesAttribs(\@nodes,['servicenode','tftpserver','xcatmaster']);
my $typetab=xCAT::Table->new('nodetype',-create=>1);
my $typehash=$typetab->getNodesAttribs(\@nodes,['os','provmethod','arch','profile']);
my $linuximgtab=xCAT::Table->new('linuximage',-create=>1);
my $osimagetab=xCAT::Table->new('osimage',-create=>1);
my $rc;
my $errstr;
my $tftpdir;
foreach (@nodes) {
my %response;
if ($nodereshash->{$_} and $nodereshash->{$_}->[0] and $nodereshash->{$_}->[0]->{tftpdir}) {
$tftpdir = $nodereshash->{$_}->[0]->{tftpdir};
} else {
$tftpdir = $globaltftpdir;
}
$response{node}->[0]->{name}->[0]=$_;
if ($args[0] eq 'stat') {
$response{node}->[0]->{data}->[0]= getstate($_,$tftpdir);
$callback->(\%response);
} elsif ($args[0]) { #If anything else, send it on to the destiny plugin, then setstate
my $ent = $typehash->{$_}->[0];
my $osimgname = $ent->{'provmethod'};
my $linuximghash=undef;
unless($osimgname =~ /^(install|netboot|statelite)$/){
$linuximghash = $linuximgtab->getAttribs({imagename => $osimgname}, 'boottarget', 'addkcmdline');
}
($rc,$errstr) = setstate($_,$bphash,$chainhash,$machash,$tftpdir,$nrhash,$linuximghash);
if ($rc) {
$response{node}->[0]->{errorcode}->[0]= $rc;
$response{node}->[0]->{errorc}->[0]= $errstr;
$callback->(\%response);
}
}
}# end of foreach node
my @normalnodeset = keys %normalnodes;
my @breaknetboot=keys %breaknetbootnodes;
#print "grub2 :inittime=$inittime; normalnodeset=@normalnodeset; breaknetboot=@breaknetboot\n";
my %osimagenodehash;
for my $nn (@normalnodeset){
#record the os version for node
my $ent = $typehash->{$nn}->[0];
my $osimage=$ent->{'provmethod'};
if($osimage =~ /^(install|netboot|statelite)$/){
$osimage=($ent->{'os'}).'-'.($ent->{'arch'}).'-'.($ent->{'provmethod'}).'-'.($ent->{'profile'});
}
push @{$osimagenodehash{$osimage}}, $nn;
}
my $do_dhcpsetup=1;
my @entries = xCAT::TableUtils->get_site_attribute("dhcpsetup");
my $t_entry = $entries[0];
if (defined($t_entry) ) {
if ($t_entry =~ /0|n|N/) { $do_dhcpsetup=0; }
}
#Don't bother to try dhcp binding changes if sub_req not passed, i.e. service node build time
unless (($args[0] eq 'stat') || ($inittime) || ($args[0] eq 'offline')) {
foreach my $osimage (keys %osimagenodehash) {
#TOTO check the existence of grub2 executable files for corresponding arch
my $osimgent = $osimagetab->getAttribs({imagename => $osimage },'osarch');
my $validarch=undef;
if($osimgent and $osimgent->{'osarch'})
{
$validarch = $osimgent->{'osarch'};
}
if ($validarch =~ /ppc64/i)
{
$validarch="ppc"
}
my $grub2 = "/boot/grub2/grub2.".$validarch;
my $tftppath = $tftpdir . $grub2;
unless (-e "$tftppath") {
my $rsp;
push @{$rsp->{data}},
"stop configuration, missing $tftppath.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
return;
}
if ($do_dhcpsetup) {
if ($request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
$sub_req->({command=>['makedhcp'],
node=>\@{$osimagenodehash{$osimage}},
arg=>['-l','-s','filename = \"'.$grub2.'\";']},$callback);
} else {
$sub_req->({command=>['makedhcp'],
node=>\@{$osimagenodehash{$osimage}},
arg=>['-s','filename = \"'.$grub2.'\";']},$callback);
}
}
} #end of foreach osimagenodehash
if ($do_dhcpsetup) {
if ($request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
$sub_req->({command=>['makedhcp'],
node=>\@breaknetboot,
arg=>['-l','-s','filename = \"xcat/nonexistant_file_to_intentionally_break_netboot_for_localboot_to_work\";']},$callback);
} else {
$sub_req->({command=>['makedhcp'],
node=>\@breaknetboot,
arg=>['-s','filename = \"xcat/nonexistant_file_to_intentionally_break_netboot_for_localboot_to_work\";']},$callback);
}
}
}
#now run the end part of the prescripts
unless ($args[0] eq 'stat') { # or $args[0] eq 'enact')
$errored=0;
if ($request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children
$sub_req->({command=>['runendpre'],
node=>\@nodes,
arg=>[$args[0], '-l']},\&pass_along);
} else { #nodeset did not distribute to the service node, here we need to let runednpre to distribute the nodes to their masters
$sub_req->({command=>['runendpre'],
node=>\@rnodes,
arg=>[$args[0]]},\&pass_along);
}
if ($errored) {
my $rsp;
$rsp->{errorcode}->[0]=1;
$rsp->{error}->[0]="Failed in running end prescripts\n";
$callback->($rsp);
return;
}
}
}
#----------------------------------------------------------------------------
=head3 getNodesetStates
returns the nodeset state for the given nodes. The possible nodeset
states are: netboot, install, boot and discover.
Arguments:
nodes --- a pointer to an array of nodes
states -- a pointer to a hash table. This hash will be filled by this
function.The key is the nodeset status and the value is a pointer
to an array of nodes.
Returns:
(return code, error message)
=cut
#-----------------------------------------------------------------------------
sub getNodesetStates {
my $noderef=shift;
if ($noderef =~ /xCAT_plugin::grub2/) {
$noderef=shift;
}
my @nodes=@$noderef;
my $hashref=shift;
my $noderestab = xCAT::Table->new('noderes'); #in order to detect per-node tftp directories
my %nrhash = %{$noderestab->getNodesAttribs(\@nodes,[qw(tftpdir)])};
if (@nodes>0) {
foreach my $node (@nodes) {
my $tftpdir;
if ($nrhash{$node}->[0] and $nrhash{$node}->[0]->{tftpdir}) {
$tftpdir = $nrhash{$node}->[0]->{tftpdir};
} else {
$tftpdir = $globaltftpdir;
}
my $tmp=getstate($node, $tftpdir);
my @a=split(' ', $tmp);
$stat = $a[0];
if (exists($hashref->{$stat})) {
my $pa=$hashref->{$stat};
push(@$pa, $node);
}
else {
$hashref->{$stat}=[$node];
}
}
}
return (0, "");
}
1;

View File

@ -288,13 +288,20 @@ sub add_hosts_content {
{
addnode $callback, $nodename, $ip, $ref->{hostnames}, $domain;
}
else
{
my $rsp;
push @{$rsp->{data}}, "Invalid IP Addr \'$ref->{ip}\' for node \'$ref->{node}\'.";
xCAT::MsgUtils->message("E", $rsp, $callback);
}
else
{
my $rsp;
if (!$ip)
{
push @{$rsp->{data}}, "Ignoring node \'$nodename\', it can not be resolved.";
}
else
{
push @{$rsp->{data}}, "Ignoring node \'$nodename\', its ip address \'$ip\' is not valid.";
}
xCAT::MsgUtils->message("W", $rsp, $callback);
}
if (defined($ref->{otherinterfaces}))
{
addotherinterfaces $callback, $nodename, $ref->{otherinterfaces}, $domain;

View File

@ -6318,13 +6318,17 @@ sub preprocess_request {
if ($command eq "rpower") {
my $subcmd=$exargs[0];
if($subcmd eq ''){
$callback->({data=>["Please enter an action (eg: boot,off,on, etc)", $usage_string]});
#$callback->({data=>["Please enter an action (eg: boot,off,on, etc)", $usage_string]});
#Above statement will miss error code, so replaced by the below statement
$callback->({errorcode=>[1],data=>["Please enter an action (eg: boot,off,on, etc)", $usage_string]});
$request = {};
return 0;
}
if ( ($subcmd ne 'reseat') && ($subcmd ne 'stat') && ($subcmd ne 'state') && ($subcmd ne 'status') && ($subcmd ne 'on') && ($subcmd ne 'off') && ($subcmd ne 'softoff') && ($subcmd ne 'nmi')&& ($subcmd ne 'cycle') && ($subcmd ne 'reset') && ($subcmd ne 'boot') && ($subcmd ne 'wake') && ($subcmd ne 'suspend')) {
$callback->({data=>["Unsupported command: $command $subcmd", $usage_string]});
#$callback->({data=>["Unsupported command: $command $subcmd", $usage_string]});
#Above statement will miss error code, so replaced by the below statement
$callback->({errorcode=>[1],data=>["Unsupported command: $command $subcmd", $usage_string]});
$request = {};
return;
}

2
xCAT-server/lib/xcat/plugins/lsslp.pm Normal file → Executable file
View File

@ -368,7 +368,7 @@ sub parse_args {
###################################
my (@octets) = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
if ( scalar(@octets) != 4 ) {
return( [1,"Invalid IP address: $ip"] );
return( usage("Invalid IP address: $ip") );
}
foreach my $octet ( @octets ) {
if (( $octet < 0 ) or ( $octet > 255 )) {

View File

@ -239,7 +239,7 @@ sub add_known_host
xCAT::MsgUtils->message("E", $rsp, $callback, 1);
return 1;
}
chop($output[0]);
chomp($output[0]);
my ($hostname,$ip_address) = xCAT::NetworkUtils->gethostnameandip($node);
if (!$hostname || !$ip_address)
{

View File

@ -1626,13 +1626,16 @@ sub findme{
}
my @nodelist = keys %hostinfo_dict;
# call makehosts to get the IP by resolving the name
my $retref = xCAT::Utils->runxcmd({command=>["makehosts"], node=>\@nodelist, sequential=>[1]}, $request_command, 0, 2);
# call discover to notify client.
xCAT::MsgUtils->message('S', "Call discovered request.\n");
$request->{"command"} = ["discovered"];
$request->{"node"} = \@nodelist;
$request->{discoverymethod} = ['profile'];
my $retref = xCAT::Utils->runxcmd($request, $request_command, 0, 2);
$retref = "";
$retref = xCAT::Utils->runxcmd($request, $request_command, 0, 2);
my $retstrref = parse_runxcmd_ret($retref);
xCAT::MsgUtils->message('S', "Call nodemgmt plugins.\n");

View File

@ -11,9 +11,6 @@ use Getopt::Long;
require xCAT::Utils;
require xCAT::TableUtils;
use xCAT::ServiceNodeUtils;
my $addkcmdlinehandled;
my $request;
my $callback;
my $dhcpconf = "/etc/dhcpd.conf";
my $globaltftpdir = xCAT::TableUtils->getTftpDir();
#my $dhcpver = 3;
@ -93,7 +90,7 @@ sub setstate {
my $imgaddkcmdline=($linuximghash{'boottarget'})? undef:$linuximghash{'addkcmdline'};
my $kern = $bphash{$node}->[0]; #$bptab->getNodeAttribs($node,['kernel','initrd','kcmdline']);
if (not $addkcmdlinehandled->{$node} and ($kern->{addkcmdline} or ($imgaddkcmdline))) {
if (not $::PXE_addkcmdlinehandled->{$node} and ($kern->{addkcmdline} or ($imgaddkcmdline))) {
#Implement the kcmdline append here for
#most generic, least code duplication
@ -129,7 +126,7 @@ sub setstate {
$kcmdlinehack =~ s/#TABLE:([^:#]+):([^:#]+):([^:#]+)#/$naval/;
} else {
my $msg = "Table key of $2 not yet supported by boottarget mini-template";
$::callback->({
$::PXE_callback->({
error => ["$msg"],
errorcode => [1]
});
@ -148,7 +145,7 @@ sub setstate {
unless ($ipfn) {
my @myself = xCAT::NetworkUtils->determinehostname();
my $myname = $myself[(scalar @myself)-1];
$::callback->(
$::PXE_callback->(
{
error => [
"$myname: Unable to determine or reasonably guess the image server for $node"
@ -263,11 +260,11 @@ sub pass_along {
$errored=1;
}
if ($_->{_addkcmdlinehandled}) {
$addkcmdlinehandled->{$_->{name}->[0]}=1;
$::PXE_addkcmdlinehandled->{$_->{name}->[0]}=1;
return; #Don't send back to client this internal hint
}
}
$callback->($resp);
$::PXE_callback->($resp);
}
@ -328,7 +325,7 @@ sub preprocess_request {
#my $sent = $stab->getAttribs({key=>'sharedtftp'},'value');
my @entries = xCAT::TableUtils->get_site_attribute("sharedtftp");
my $t_entry = $entries[0];
if ( defined($t_entry) and ($t_entry == 0 or $t_entry =~ /no/i)) {
if ( defined($t_entry) and ($t_entry eq "0" or $t_entry eq "no" or $t_entry eq "NO")) {
# check for computenodes and servicenodes from the noderange, if so error out
my @SN;
my @CN;
@ -356,28 +353,28 @@ sub preprocess_request {
}
sub process_request {
$request = shift;
$callback = shift;
$::PXE_request = shift;
$::PXE_callback = shift;
my $sub_req = shift;
$::callback=$callback;
undef $::PXE_addkcmdlinehandled;
my @args;
my @nodes;
my @rnodes;
if (ref($request->{node})) {
@rnodes = @{$request->{node}};
if (ref($::PXE_request->{node})) {
@rnodes = @{$::PXE_request->{node}};
} else {
if ($request->{node}) { @rnodes = ($request->{node}); }
if ($::PXE_request->{node}) { @rnodes = ($::PXE_request->{node}); }
}
unless (@rnodes) {
if ($usage{$request->{command}->[0]}) {
$callback->({data=>$usage{$request->{command}->[0]}});
if ($usage{$::PXE_request->{command}->[0]}) {
$::PXE_callback->({data=>$usage{$::PXE_request->{command}->[0]}});
}
return;
}
#if not shared, then help sync up
if ($request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
if ($::PXE_request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
@nodes = ();
foreach (@rnodes) {
if (xCAT::NetworkUtils->nodeonmynet($_)) {
@ -396,16 +393,16 @@ sub process_request {
return;
}
if (ref($request->{arg})) {
@args=@{$request->{arg}};
if (ref($::PXE_request->{arg})) {
@args=@{$::PXE_request->{arg}};
} else {
@args=($request->{arg});
@args=($::PXE_request->{arg});
}
#now run the begin part of the prescripts
unless ($args[0] eq 'stat') { # or $args[0] eq 'enact') {
$errored=0;
if ($request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children
if ($::PXE_request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children
$sub_req->({command=>['runbeginpre'],
node=>\@nodes,
arg=>[$args[0], '-l']},\&pass_along);
@ -418,7 +415,7 @@ sub process_request {
my $rsp;
$rsp->{errorcode}->[0]=1;
$rsp->{error}->[0]="Failed in running begin prescripts\n";
$callback->($rsp);
$::PXE_callback->($rsp);
return;
}
}
@ -426,7 +423,7 @@ sub process_request {
#end prescripts code
if (! -r "$tftpdir/pxelinux.0") {
unless (-r "/usr/lib/syslinux/pxelinux.0" or -r "/usr/share/syslinux/pxelinux.0") {
$callback->({error=>["Unable to find pxelinux.0 "],errorcode=>[1]});
$::PXE_callback->({error=>["Unable to find pxelinux.0 "],errorcode=>[1]});
return;
}
if (-r "/usr/lib/syslinux/pxelinux.0") {
@ -437,14 +434,14 @@ sub process_request {
chmod(0644,"$tftpdir/pxelinux.0");
}
unless ( -r "$tftpdir/pxelinux.0" ) {
$callback->({errror=>["Unable to find pxelinux.0 from syslinux"],errorcode=>[1]});
$::PXE_callback->({errror=>["Unable to find pxelinux.0 from syslinux"],errorcode=>[1]});
return;
}
$errored=0;
my $inittime=0;
if (exists($request->{inittime})) { $inittime= $request->{inittime}->[0];}
if (exists($::PXE_request->{inittime})) { $inittime= $::PXE_request->{inittime}->[0];}
if (!$inittime) { $inittime=0;}
unless ($args[0] eq 'stat') { # or $args[0] eq 'enact') {
$sub_req->({command=>['setdestiny'],
@ -476,7 +473,7 @@ sub process_request {
$response{node}->[0]->{name}->[0]=$_;
if ($args[0] eq 'stat') {
$response{node}->[0]->{data}->[0]= getstate($_,$tftpdir);
$callback->(\%response);
$::PXE_callback->(\%response);
} elsif ($args[0]) { #If anything else, send it on to the destiny plugin, then setstate
my $ent = $nthash{$_}->[0];
my $osimgname = $ent->{'provmethod'};
@ -488,13 +485,13 @@ sub process_request {
if ($rc) {
$response{node}->[0]->{errorcode}->[0]= $rc;
$response{node}->[0]->{errorc}->[0]= $errstr;
$callback->(\%response);
$::PXE_callback->(\%response);
}
}
}
my $inittime=0;
if (exists($request->{inittime})) { $inittime= $request->{inittime}->[0];}
if (exists($::PXE_request->{inittime})) { $inittime= $::PXE_request->{inittime}->[0];}
if (!$inittime) { $inittime=0;}
#dhcp stuff -- inittime is set when xcatd on sn is started
@ -511,12 +508,12 @@ sub process_request {
#}
if ($do_dhcpsetup) {
if ($request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
if ($::PXE_request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
$sub_req->({command=>['makedhcp'],arg=>['-l'],
node=>\@nodes},$callback);
node=>\@nodes},$::PXE_callback);
} else {
$sub_req->({command=>['makedhcp'],
node=>\@nodes},$callback);
node=>\@nodes},$::PXE_callback);
}
}
@ -568,7 +565,7 @@ sub process_request {
#now run the end part of the prescripts
unless ($args[0] eq 'stat') { # or $args[0] eq 'enact')
$errored=0;
if ($request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children
if ($::PXE_request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children
$sub_req->({command=>['runendpre'],
node=>\@nodes,
arg=>[$args[0], '-l']},\&pass_along);
@ -581,7 +578,7 @@ sub process_request {
my $rsp;
$rsp->{errorcode}->[0]=1;
$rsp->{error}->[0]="Failed in running end prescripts\n";
$callback->($rsp);
$::PXE_callback->($rsp);
return;
}
}

View File

@ -957,7 +957,7 @@ sub tabprune
push @{$rsp{data}}, " tabprune <tablename> [-V] -d <# of days>";
push @{$rsp{data}}, " tabprune [-h|--help]";
push @{$rsp{data}}, " tabprune [-v|--version]";
push @{$rsp{data}}, " tables supported:eventlog,auditlog";
push @{$rsp{data}}, " tables supported:eventlog,auditlog,unless -a which supports all tables";
push @{$rsp{data}}, " -d option only supported for eventlog,auditlog";
if ($exitcode) { $rsp{errorcode} = $exitcode; }
$cb->(\%rsp);
@ -997,7 +997,7 @@ sub tabprune
}
$table=~ s/\s*//g; # remove blanks
if (($table ne "eventlog") && ($table ne "auditlog") && ($table ne "isnm_perf") && ($table ne "isnm_perf_sum") ) {
if (($table ne "eventlog") && ($table ne "auditlog") && ($table ne "isnm_perf") && ($table ne "isnm_perf_sum") && (! $ALL)) {
my %rsp;
$rsp{data}->[0] = "Table $table not supported, see tabprune -h for supported tables.";
$rsp{errorcode} = 1;
@ -2654,7 +2654,7 @@ sub getTablesNodesAttribs
my %noderecs;
my $recs;
# build the table name record
@{$noderecs{table}->[0]->{tablename}} = $tablename;
#@{$noderecs{table}->[0]->{tablename}} = $tablename;
# if request for ALL attributes
if (grep (/ALL/,@attrs)) { # read the schema and build array of all attrs
@attrs=();
@ -2681,6 +2681,7 @@ sub getTablesNodesAttribs
}
}
@{$noderecs{table}->[0]->{tablename}} = $tablename;
push @{$rsp{"table"}}, @{$noderecs{table}};
} # end of all table processing
# for checkin XML created
@ -2752,9 +2753,9 @@ sub getTablesAllRowAttribs
my $attr = $tabhash->{attr};
my @attrs=@$attr;
my $tab=xCAT::Table->new($tablename);
my %noderecs;
my %tblrecs;
# build the table name record
@{$noderecs{table}->[0]->{tablename}} = $tablename;
@{$tblrecs{table}->[0]->{tablename}} = $tablename;
# if request for ALL attributes
if (grep (/ALL/,@attrs)) { # read the schema and build array of all attrs
@attrs=();
@ -2767,7 +2768,6 @@ sub getTablesAllRowAttribs
}
# read all the attributes in this table
my @recs = $tab->getAllAttribs(@attrs);
my %tblrecs;
foreach my $rec (@recs) {
my %datseg=();
foreach my $key (keys %$rec) {

View File

@ -68,9 +68,10 @@ sub preprocess_request
my @entries = xCAT::TableUtils->get_site_attribute("sharedtftp");
my $t_entry = $entries[0];
unless ( defined($t_entry)
and ($t_entry =~ /no/i or $t_entry =~ /0/))
and ($t_entry eq "no" or $t_entry eq "NO" or $t_entry eq "0"))
{
#unless requesting no sharedtftp, don't make hierarchical call
return [$req];
}

View File

@ -11,9 +11,6 @@ use Getopt::Long;
use xCAT::MsgUtils;
use xCAT::ServiceNodeUtils;
use xCAT::TableUtils;
my $addkcmdlinehandled;
my $request;
my $callback;
my $dhcpconf = "/etc/dhcpd.conf";
my $tftpdir = "/tftpboot/vsmp";
#my $dhcpver = 3;
@ -75,7 +72,7 @@ sub setstate {
my %chainhash = %{shift()};
my %machash = %{shift()};
my $kern = $bphash{$node}->[0]; #$bptab->getNodeAttribs($node,['kernel','initrd','kcmdline']);
if (not $addkcmdlinehandled->{$node} and $kern->{addkcmdline}) { #Implement the kcmdline append here for
if (not $::VSMPPXE_addkcmdlinehandled->{$node} and $kern->{addkcmdline}) { #Implement the kcmdline append here for
#most generic, least code duplication
$kern->{kcmdline} .= " ".$kern->{addkcmdline};
}
@ -84,7 +81,7 @@ sub setstate {
unless ($ipfn) {
my @myself = xCAT::NetworkUtils->determinehostname();
my $myname = $myself[(scalar @myself)-1];
$callback->(
$::VSMPPXE_callback->(
{
error => [
"$myname: Unable to determine or reasonably guess the image server for $node"
@ -189,11 +186,11 @@ sub pass_along {
$errored=1;
}
if ($_->{_addkcmdlinehandled}) {
$addkcmdlinehandled->{$_->{name}->[0]}=1;
$::VSMPPXE_addkcmdlinehandled->{$_->{name}->[0]}=1;
return; #Don't send back to client this internal hint
}
}
$callback->($resp);
$::VSMPPXE_callback->($resp);
}
@ -260,7 +257,7 @@ sub preprocess_request {
my @entries = xCAT::TableUtils->get_site_attribute("sharedtftp");
my $t_entry = $entries[0];
if ( defined($t_entry) and ($t_entry == 0 or $t_entry =~ /no/i)) {
if ( defined($t_entry) and ($t_entry eq "0" or $t_entry eq "no" or $t_entry eq "NO")) {
# check for computenodes and servicenodes from the noderange, if so error out
my @SN;
my @CN;
@ -288,29 +285,30 @@ sub preprocess_request {
}
sub process_request {
$request = shift;
$callback = shift;
$::VSMPPXE_request = shift;
$::VSMPPXE_callback = shift;
my $sub_req = shift;
undef $::VSMPPXE_addkcmdlinehandled;
my @args;
my @nodes;
my @rnodes;
if (ref($request->{node})) {
@rnodes = @{$request->{node}};
if (ref($::VSMPPXE_request->{node})) {
@rnodes = @{$::VSMPPXE_request->{node}};
} else {
if ($request->{node}) {
@rnodes = ($request->{node});
if ($::VSMPPXE_request->{node}) {
@rnodes = ($::VSMPPXE_request->{node});
}
}
unless (@rnodes) {
if ($usage{$request->{command}->[0]}) {
$callback->({data=>$usage{$request->{command}->[0]}});
if ($usage{$::VSMPPXE_request->{command}->[0]}) {
$::VSMPPXE_callback->({data=>$usage{$::VSMPPXE_request->{command}->[0]}});
}
return;
}
#if not shared, then help sync up
if ($request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
if ($::VSMPPXE_request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
@nodes = ();
foreach (@rnodes) {
if (xCAT::NetworkUtils->nodeonmynet($_)) {
@ -329,17 +327,17 @@ sub process_request {
return;
}
if (ref($request->{arg})) {
@args=@{$request->{arg}};
if (ref($::VSMPPXE_request->{arg})) {
@args=@{$::VSMPPXE_request->{arg}};
} else {
@args=($request->{arg});
@args=($::VSMPPXE_request->{arg});
}
#now run the begin part of the prescripts
unless ($args[0] eq 'stat') { # or $args[0] eq 'enact') {
$errored=0;
if ($request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children
if ($::VSMPPXE_request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children
$sub_req->({command=>['runbeginpre'],
node=>\@nodes,
arg=>[$args[0], '-l']},\&pass_along);
@ -352,7 +350,7 @@ sub process_request {
my $rsp;
$rsp->{errorcode}->[0]=1;
$rsp->{error}->[0]="Failed in running begin prescripts\n";
$callback->($rsp);
$::VSMPPXE_callback->($rsp);
return;
}
}
@ -375,7 +373,7 @@ sub process_request {
if (! -r "$tftpdir/pxelinux.0") {
unless (-r "/usr/lib/syslinux/pxelinux.0" or -r "/usr/share/syslinux/pxelinux.0") {
$callback->({error=>["Unable to find pxelinux.0 "],errorcode=>[1]});
$::VSMPPXE_callback->({error=>["Unable to find pxelinux.0 "],errorcode=>[1]});
return;
}
if (-r "/usr/lib/syslinux/pxelinux.0") {
@ -386,14 +384,14 @@ sub process_request {
chmod(0644,"$tftpdir/pxelinux.0");
}
unless ( -r "$tftpdir/pxelinux.0" ) {
$callback->({errror=>["Unable to find pxelinux.0 from syslinux"],errorcode=>[1]});
$::VSMPPXE_callback->({errror=>["Unable to find pxelinux.0 from syslinux"],errorcode=>[1]});
return;
}
$errored=0;
my $inittime=0;
if (exists($request->{inittime})) { $inittime= $request->{inittime}->[0];}
if (exists($::VSMPPXE_request->{inittime})) { $inittime= $::VSMPPXE_request->{inittime}->[0];}
if (!$inittime) { $inittime=0;}
unless ($args[0] eq 'stat') { # or $args[0] eq 'enact') {
$sub_req->({command=>['setdestiny'],
@ -414,19 +412,19 @@ sub process_request {
$response{node}->[0]->{name}->[0]=$_;
if ($args[0] eq 'stat') {
$response{node}->[0]->{data}->[0]= getstate($_);
$callback->(\%response);
$::VSMPPXE_callback->(\%response);
} elsif ($args[0]) { #If anything else, send it on to the destiny plugin, then setstate
($rc,$errstr) = setstate($_,\%bphash,\%chainhash,\%machash);
if ($rc) {
$response{node}->[0]->{errorcode}->[0]= $rc;
$response{node}->[0]->{errorc}->[0]= $errstr;
$callback->(\%response);
$::VSMPPXE_callback->(\%response);
}
}
}
my $inittime=0;
if (exists($request->{inittime})) { $inittime= $request->{inittime}->[0];}
if (exists($::VSMPPXE_request->{inittime})) { $inittime= $::VSMPPXE_request->{inittime}->[0];}
if (!$inittime) { $inittime=0;}
#dhcp stuff -- inittime is set when xcatd on sn is started
@ -443,12 +441,12 @@ sub process_request {
#}
if ($do_dhcpsetup) {
if ($request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
if ($::VSMPPXE_request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
$sub_req->({command=>['makedhcp'],arg=>['-l'],
node=>\@nodes},$callback);
node=>\@nodes},$::VSMPPXE_callback);
} else {
$sub_req->({command=>['makedhcp'],
node=>\@nodes},$callback);
node=>\@nodes},$::VSMPPXE_callback);
}
}
@ -456,7 +454,7 @@ sub process_request {
#now run the end part of the prescripts
unless ($args[0] eq 'stat') { # or $args[0] eq 'enact')
$errored=0;
if ($request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children
if ($::VSMPPXE_request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children
$sub_req->({command=>['runendpre'],
node=>\@nodes,
arg=>[$args[0], '-l']},\&pass_along);
@ -469,7 +467,7 @@ sub process_request {
my $rsp;
$rsp->{errorcode}->[0]=1;
$rsp->{error}->[0]="Failed in running end prescripts\n";
$callback->($rsp);
$::VSMPPXE_callback->($rsp);
return;
}
}

View File

@ -19,6 +19,7 @@ use POSIX;
require xCAT::Table;
require xCAT::Utils;
require xCAT::Zone;
require xCAT::TableUtils;
require xCAT::ServiceNodeUtils;
require xCAT::MsgUtils;
@ -111,8 +112,9 @@ sub preprocess_request
$req = &parse_xdcp_cmd($req);
}
# if xdsh need to make sure request has full path to input files
# also process -K flag and use of zones
if ($command eq "xdsh") {
$req = &parse_xdsh_cmd($req);
$req = &parse_xdsh_cmd($req,$cb,$sub_req);
}
# there are nodes in the xdsh command, not xdsh to an image
@ -421,7 +423,10 @@ sub parse_xdcp_cmd
sub parse_xdsh_cmd
{
my $req=shift;
my $cb=shift;
my $sub_req=shift;
my $args=$req->{arg}; # argument
my $nodes = $req->{node};
my $currpath=$req->{cwd}->[0]; # current path when command was executed
my $orgargarraySize = @{$args}; # get the size of the arg array
@ARGV = @{$args}; # get arguments
@ -498,6 +503,45 @@ sub parse_xdsh_cmd
} # end -e option
# if -k options and there are zones and service nodes, we cannot allow
# servicenodes and compute nodes in the noderange. The /etc/xcat/sshkeys directory must be sync'd
# to the service nodes first. So they must run xdsh -K to the service nodes and then to the compute
# nodes.
if (defined($options{'ssh-setup'})) {
if (xCAT::Zone->usingzones) {
# check to see if service nodes and compute nodes in node range
my @SN;
my @CN;
xCAT::ServiceNodeUtils->getSNandCPnodes(\@$nodes, \@SN, \@CN);
if ((@SN > 0) && (@CN >0 )) { # there are both SN and CN
my $rsp;
$rsp->{data}->[0] =
"xdsh -K was run with a noderange containing both service nodes and compute nodes. This is not valid if using zones. You must run xdsh -K to the service nodes first to setup the service node to be able to run xdsh -K to the compute nodes. \n";
xCAT::MsgUtils->message("E", $rsp, $cb);
exit 1;
}
# if servicenodes for the node range this will force the update of
# the servicenode with /etc/xcat/sshkeys dir first
# if servicenodes and xdsh -K and using zones and we are on the Management Node
# then we need to sync
# /etc/xcat/sshkeys to the service nodes
# get list of all servicenodes
if (xCAT::Utils->isMN()) { # on the MN
my @snlist;
foreach my $sn (xCAT::ServiceNodeUtils->getSNList()) {
if (xCAT::NetworkUtils->thishostisnot($sn)) { # if it is not me, the MN
push @snlist, $sn;
}
}
if (@snlist) {
&syncSNZoneKeys($req, $cb, $sub_req, \@snlist);
}
}
} # not using zones
} # not -k flag
return $req;
}
@ -992,6 +1036,107 @@ sub process_nodes
return $newSNreq;
}
#-------------------------------------------------------
=head3 syncSNZoneKeys
Build the xdcp command to send the zone keys to the service nodes
Return an array of servicenodes that do not have errors
Returns error code:
if = 0, good return continue to process the
nodes.
if = 1, global error need to quit
=cut
#-------------------------------------------------------
sub syncSNZoneKeys
{
my $req = shift;
my $callback = shift;
my $sub_req = shift;
my $sn = shift;
my @snodes = @$sn;
$::RUNCMD_RC = 0;
my $file="/tmp/xcatzonesynclist";
# Run xdcp <servicenodes> -F /tmp/xcatzonesynclist
# can leave it , never changes and is built each time
my $content= "\"/etc/xcat/sshkeys/ -> /etc/xcat/sshkeys/\"";
`echo $content > $file`;
# xdcp rsync the file
my @sn = ();
#build the array of all service nodes
foreach my $node (@snodes)
{
# handle multiple servicenodes for one node
my @sn_list = split ',', $node;
foreach my $snode (@sn_list) {
push @sn, $snode;
}
}
@::good_SN = @sn; # initialize all good
# run the command to the servicenodes
# xdcp <sn> -o "--delete" -F <syncfile>
my $addreq;
$addreq->{'_xcatdest'} = $::mnname;
$addreq->{node} = \@sn;
$addreq->{noderange} = \@sn;
# check input request for --nodestatus
my $args=$req->{arg}; # argument
if (grep(/^--nodestatus$/, @$args)) {
push (@{$addreq->{arg}},"--nodestatus"); # return nodestatus
}
push (@{$addreq->{arg}},"-v");
push (@{$addreq->{arg}},"-o");
push (@{$addreq->{arg}},"--delete"); # will cleanup the directory if zones are removed
push (@{$addreq->{arg}},"-F");
push (@{$addreq->{arg}},$file);
$addreq->{command}->[0] = "xdcp"; # input command is xdsh, but we need to run xdcp -F
$addreq->{cwd}->[0] = $req->{cwd}->[0];
$addreq->{env} = $req->{env};
&process_request($addreq, $callback, $sub_req);
if ($::FAILED_NODES == 0)
{
@::good_SN = @sn; # all servicenodes were sucessful
}
else
{
@::bad_SN = @::DCP_NODES_FAILED;
# remove all failing nodes from the good list
my @tmpgoodnodes;
foreach my $gnode (@::good_SN) {
if (!grep(/$gnode/,@::bad_SN )) # if not a bad node
{
push @tmpgoodnodes, $gnode;
}
}
@::good_SN = @tmpgoodnodes;
}
# report bad service nodes
if (@::bad_SN)
{
my $rsp = {};
my $badnodes;
foreach my $badnode (@::bad_SN)
{
$badnodes .= $badnode;
$badnodes .= ", ";
}
chop $badnodes;
my $msg =
"\nThe following servicenodes: $badnodes have errors and cannot be updated\n Until the error is fixed, xdcp will not work to nodes serviced by these service nodes.";
$rsp->{data}->[0] = $msg;
xCAT::MsgUtils->message("D", $rsp, $callback);
}
return (0);
}
#-------------------------------------------------------

View File

@ -11,9 +11,7 @@ use Getopt::Long;
use xCAT::Utils;
use xCAT::TableUtils;
use xCAT::ServiceNodeUtils;
my $addkcmdlinehandled;
my $request;
my $callback;
my $dhcpconf = "/etc/dhcpd.conf";
#my $tftpdir = "/tftpboot";
my $globaltftpdir = xCAT::TableUtils->getTftpDir();
@ -102,7 +100,7 @@ sub setstate {
if (ref $linuximghashref) { %linuximghash = %{$linuximghashref}; }
my $imgaddkcmdline=($linuximghash{'boottarget'})? undef:$linuximghash{'addkcmdline'};
my $kern = $bphash{$node}->[0]; #$bptab->getNodeAttribs($node,['kernel','initrd','kcmdline']);
unless ($addkcmdlinehandled->{$node}) { #Tag to let us know the plugin had a special syntax implemented for addkcmdline
unless ($::XNBA_addkcmdlinehandled->{$node}) { #Tag to let us know the plugin had a special syntax implemented for addkcmdline
if ($kern->{addkcmdline} or ($imgaddkcmdline)) {
#Implement the kcmdline append here for
@ -138,7 +136,7 @@ sub setstate {
$kcmdlinehack =~ s/#TABLE:([^:#]+):([^:#]+):([^:#]+)#/$naval/;
} else {
my $msg = "Table key of $2 not yet supported by boottarget mini-template";
$callback->({
$::XNBA_callback->({
error => ["$msg"],
errorcode => [1]
});
@ -279,11 +277,11 @@ sub pass_along {
$errored=1;
}
if ($_->{_addkcmdlinehandled}) {
$addkcmdlinehandled->{$_->{name}->[0]}=1;
$::XNBA_addkcmdlinehandled->{$_->{name}->[0]}=1;
return; #Don't send back to client this internal hint
}
}
$callback->($resp);
$::XNBA_callback->($resp);
}
@ -348,7 +346,7 @@ sub preprocess_request {
#they specify no sharedtftp in site table
my @entries = xCAT::TableUtils->get_site_attribute("sharedtftp");
my $t_entry = $entries[0];
if ( defined($t_entry) and ($t_entry == 0 or $t_entry =~ /no/i)) {
if ( defined($t_entry) and ($t_entry eq "0" or $t_entry eq "no" or $t_entry eq "NO")) {
# check for computenodes and servicenodes from the noderange, if so error out
my @SN;
my @CN;
@ -376,27 +374,28 @@ sub preprocess_request {
}
sub process_request {
$request = shift;
$callback = shift;
$::XNBA_request = shift;
$::XNBA_callback = shift;
my $sub_req = shift;
undef $::XNBA_addkcmdlinehandled; # clear out any previous value
my @args;
my @nodes;
my @rnodes;
if (ref($request->{node})) {
@rnodes = @{$request->{node}};
if (ref($::XNBA_request->{node})) {
@rnodes = @{$::XNBA_request->{node}};
} else {
if ($request->{node}) { @rnodes = ($request->{node}); }
if ($::XNBA_request->{node}) { @rnodes = ($::XNBA_request->{node}); }
}
unless (@rnodes) {
if ($usage{$request->{command}->[0]}) {
$callback->({data=>$usage{$request->{command}->[0]}});
if ($usage{$::XNBA_request->{command}->[0]}) {
$::XNBA_callback->({data=>$usage{$::XNBA_request->{command}->[0]}});
}
return;
}
#if not shared, then help sync up
if ($request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
if ($::XNBA_request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
@nodes = ();
foreach (@rnodes) {
if (xCAT::NetworkUtils->nodeonmynet($_)) {
@ -415,16 +414,16 @@ sub process_request {
return;
}
if (ref($request->{arg})) {
@args=@{$request->{arg}};
if (ref($::XNBA_request->{arg})) {
@args=@{$::XNBA_request->{arg}};
} else {
@args=($request->{arg});
@args=($::XNBA_request->{arg});
}
#now run the begin part of the prescripts
unless ($args[0] eq 'stat') { # or $args[0] eq 'enact') {
$errored=0;
if ($request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children
if ($::XNBA_request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children
$sub_req->({command=>['runbeginpre'],
node=>\@nodes,
arg=>[$args[0], '-l']},\&pass_along);
@ -437,7 +436,7 @@ sub process_request {
my $rsp;
$rsp->{errorcode}->[0]=1;
$rsp->{error}->[0]="Failed in running begin prescripts.\n";
$callback->($rsp);
$::XNBA_callback->($rsp);
return;
}
}
@ -445,21 +444,21 @@ sub process_request {
#back to normal business
if (! -r "$globaltftpdir/xcat/pxelinux.0") {
unless (-r $::XCATROOT."/share/xcat/netboot/syslinux/pxelinux.0") {
$callback->({error=>["Unable to find pxelinux.0 at ".$::XCATROOT."/share/xcat/netboot/syslinux/pxelinux.0"],errorcode=>[1]});
$::XNBA_callback->({error=>["Unable to find pxelinux.0 at ".$::XCATROOT."/share/xcat/netboot/syslinux/pxelinux.0"],errorcode=>[1]});
return;
}
copy($::XCATROOT."/share/xcat/netboot/syslinux/pxelinux.0","$globaltftpdir/xcat/pxelinux.0");
chmod(0644,"$globaltftpdir/xcat/pxelinux.0");
}
unless ( -r "$globaltftpdir/xcat/pxelinux.0" ) {
$callback->({error=>["Unable to find pxelinux.0 from syslinux"],errorcode=>[1]});
$::XNBA_callback->({error=>["Unable to find pxelinux.0 from syslinux"],errorcode=>[1]});
return;
}
my $inittime=0;
if (exists($request->{inittime})) { $inittime= $request->{inittime}->[0];}
if (exists($::XNBA_request->{inittime})) { $inittime= $::XNBA_request->{inittime}->[0];}
if (!$inittime) { $inittime=0;}
$errored=0;
unless ($args[0] eq 'stat') { # or $args[0] eq 'enact') {
@ -499,7 +498,7 @@ sub process_request {
$response{node}->[0]->{name}->[0]=$_;
if ($args[0] eq 'stat') {
$response{node}->[0]->{data}->[0]= getstate($_,$tftpdir);
$callback->(\%response);
$::XNBA_callback->(\%response);
} elsif ($args[0]) { #If anything else, send it on to the destiny plugin, then setstate
my $rc;
my $errstr;
@ -514,7 +513,7 @@ sub process_request {
#if ($rc) {
# $response{node}->[0]->{errorcode}->[0]= $rc;
# $response{node}->[0]->{errorc}->[0]= $errstr;
# $callback->(\%response);
# $::XNBA_callback->(\%response);
#}
if($args[0] eq 'offline') {
unlink($tftpdir."/xcat/xnba/nodes/".$_);
@ -540,12 +539,12 @@ sub process_request {
#}
if ($do_dhcpsetup) {
if ($request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
if ($::XNBA_request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
$sub_req->({command=>['makedhcp'],arg=>['-l'],
node=>\@nodes},$callback);
node=>\@nodes},$::XNBA_callback);
} else {
$sub_req->({command=>['makedhcp'],
node=>\@nodes},$callback);
node=>\@nodes},$::XNBA_callback);
}
}
}
@ -553,7 +552,7 @@ sub process_request {
#now run the end part of the prescripts
unless ($args[0] eq 'stat') { # or $args[0] eq 'enact')
$errored=0;
if ($request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children
if ($::XNBA_request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children
$sub_req->({command=>['runendpre'],
node=>\@nodes,
arg=>[$args[0], '-l']},\&pass_along);
@ -566,7 +565,7 @@ sub process_request {
my $rsp;
$rsp->{errorcode}->[0]=1;
$rsp->{error}->[0]="Failed in running end prescripts.\n";
$callback->($rsp);
$::XNBA_callback->($rsp);
return;
}
}

View File

@ -13,11 +13,8 @@ use Socket;
use Getopt::Long;
use xCAT::Table;
my $request;
my %breaknetbootnodes;
our %normalnodes;
my $callback;
my $sub_req;
my $dhcpconf = "/etc/dhcpd.conf";
my $globaltftpdir = xCAT::TableUtils->getTftpDir();
#my $dhcpver = 3;
@ -104,7 +101,7 @@ sub setstate {
if (xCAT::InstUtils->is_me($sn)) {
my @myself = xCAT::NetworkUtils->determinehostname();
my $myname = $myself[(scalar @myself)-1];
$::callback->(
$::YABOOT_callback->(
{
error => [
"$myname: Unable to determine the image server for $node on service node $sn"
@ -116,7 +113,7 @@ sub setstate {
}
}
} else {
$::callback->(
$::YABOOT_callback->(
{
error => [
"$myname: Unable to determine the image server for $node"
@ -177,7 +174,7 @@ sub setstate {
delete $normalnodes{$node}; #Signify to omit this from one makedhcp command
#$sub_req->({command=>['makedhcp'], #batched elsewhere, this code is stale, hopefully
# node=>[$node],
# arg=>['-s','filename = \"xcat/nonexistant_file_to_intentionally_break_netboot_for_localboot_to_work\";']},$callback);
# arg=>['-s','filename = \"xcat/nonexistant_file_to_intentionally_break_netboot_for_localboot_to_work\";']},$::YABOOT_callback);
print $pcfg "bye\n";
close($pcfg);
} elsif ($kern and $kern->{kernel}) {
@ -231,13 +228,13 @@ sub setstate {
#to clear the filename field, so the logic is a little
#opposite
# $sub_req->({command=>['makedhcp'], #This is currently batched elswhere
# node=>[$node]},$callback); #It hopefully will perform correctly
# node=>[$node]},$::YABOOT_callback); #It hopefully will perform correctly
if ($cref and $cref->{currstate} eq "boot") {
$breaknetbootnodes{$node}=1;
delete $normalnodes{$node}; #Signify to omit this from one makedhcp command
#$sub_req->({command=>['makedhcp'], #batched elsewhere, this code is stale, hopefully
# node=>[$node],
# arg=>['-s','filename = \"xcat/nonexistant_file_to_intentionally_break_netboot_for_localboot_to_work\";']},$callback);
# arg=>['-s','filename = \"xcat/nonexistant_file_to_intentionally_break_netboot_for_localboot_to_work\";']},$::YABOOT_callback);
print $pcfg "bye\n";
close($pcfg);
} elsif ($kern and $kern->{kernel}) {
@ -309,7 +306,7 @@ sub pass_along {
# print Dumper($resp);
$callback->($resp);
$::YABOOT_callback->($resp);
if ($resp and ($resp->{errorcode} and $resp->{errorcode}->[0]) or ($resp->{error} and $resp->{error}->[0])) {
$errored=1;
}
@ -379,7 +376,8 @@ sub preprocess_request {
#if they specify no sharedtftp in site table
my @entries = xCAT::TableUtils->get_site_attribute("sharedtftp");
my $t_entry = $entries[0];
if ( defined($t_entry) and ($t_entry == 0 or $t_entry =~ /no/i)) {
if ( defined($t_entry) and ($t_entry eq "0" or $t_entry eq "no" or $t_entry eq "NO")) {
# check for computenodes and servicenodes from the noderange, if so error out
my @SN;
my @CN;
@ -408,31 +406,30 @@ sub preprocess_request {
sub process_request {
$request = shift;
$callback = shift;
$::callback=$callback;
$sub_req = shift;
my $command = $request->{command}->[0];
$::YABOOT_request = shift;
$::YABOOT_callback = shift;
my $sub_req = shift;
my $command = $::YABOOT_request->{command}->[0];
%breaknetbootnodes=();
%normalnodes=();
my @args;
my @nodes;
my @rnodes;
if (ref($request->{node})) {
@rnodes = @{$request->{node}};
if (ref($::YABOOT_request->{node})) {
@rnodes = @{$::YABOOT_request->{node}};
} else {
if ($request->{node}) { @rnodes = ($request->{node}); }
if ($::YABOOT_request->{node}) { @rnodes = ($::YABOOT_request->{node}); }
}
unless (@rnodes) {
if ($usage{$request->{command}->[0]}) {
$callback->({data=>$usage{$request->{command}->[0]}});
if ($usage{$::YABOOT_request->{command}->[0]}) {
$::YABOOT_callback->({data=>$usage{$::YABOOT_request->{command}->[0]}});
}
return;
}
#if not shared tftpdir, then filter, otherwise, set up everything
if ($request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
if ($::YABOOT_request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
@nodes = ();
foreach (@rnodes) {
if (xCAT::NetworkUtils->nodeonmynet($_)) {
@ -451,16 +448,16 @@ sub process_request {
return;
}
if (ref($request->{arg})) {
@args=@{$request->{arg}};
if (ref($::YABOOT_request->{arg})) {
@args=@{$::YABOOT_request->{arg}};
} else {
@args=($request->{arg});
@args=($::YABOOT_request->{arg});
}
#now run the begin part of the prescripts
unless ($args[0] eq 'stat') { # or $args[0] eq 'enact') {
$errored=0;
if ($request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children
if ($::YABOOT_request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children
$sub_req->({command=>['runbeginpre'],
node=>\@nodes,
arg=>[$args[0], '-l']},\&pass_along);
@ -473,14 +470,14 @@ sub process_request {
my $rsp;
$rsp->{errorcode}->[0]=1;
$rsp->{error}->[0]="Failed in running begin prescripts.\n";
$callback->($rsp);
$::YABOOT_callback->($rsp);
return;
}
}
#back to normal business
my $inittime=0;
if (exists($request->{inittime})) { $inittime= $request->{inittime}->[0];}
if (exists($::YABOOT_request->{inittime})) { $inittime= $::YABOOT_request->{inittime}->[0];}
if (!$inittime) { $inittime=0;}
$errored=0;
unless ($args[0] eq 'stat') { # or $args[0] eq 'enact') {
@ -520,7 +517,7 @@ sub process_request {
$response{node}->[0]->{name}->[0]=$_;
if ($args[0] eq 'stat') {
$response{node}->[0]->{data}->[0]= getstate($_,$tftpdir);
$callback->(\%response);
$::YABOOT_callback->(\%response);
} elsif ($args[0]) { #If anything else, send it on to the destiny plugin, then setstate
my $ent = $typehash->{$_}->[0];
my $osimgname = $ent->{'provmethod'};
@ -533,7 +530,7 @@ sub process_request {
if ($rc) {
$response{node}->[0]->{errorcode}->[0]= $rc;
$response{node}->[0]->{errorc}->[0]= $errstr;
$callback->(\%response);
$::YABOOT_callback->(\%response);
}
}
}# end of foreach node
@ -570,7 +567,16 @@ sub process_request {
$osn = $2;
$osm = 0;
}
#Redhat recommend to use grub2 instead of yaboot for rhels7 provision
if ( $osv =~ /rh/ and int($osn) == 7 ){
my $rsp;
push @{$rsp->{data}},
"stop configuration because yaboot DOES NOT work for $os provision, please change noderes.netboot=grub2 instead.\n";
xCAT::MsgUtils->message("E", $rsp, $::YABOOT_callback);
return;
}
if (($osv =~ /rh/ and int($osn) < 6) or
($osv =~ /sles/ and int($osn) < 11)) {
# check if yaboot-xcat installed
@ -579,7 +585,7 @@ sub process_request {
my $rsp;
push @{$rsp->{data}},
"stop configuration because yaboot-xcat need to be installed for $os.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
xCAT::MsgUtils->message("E", $rsp, $::YABOOT_callback);
return;
}
} elsif (($osv =~ /rh/ and int($osn) >= 6) or
@ -590,7 +596,7 @@ sub process_request {
my $rsp;
push @{$rsp->{data}},
"stop configuration because rsync does not exist or is not executable.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
xCAT::MsgUtils->message("E", $rsp, $::YABOOT_callback);
return;
}
my $yabootpath = $tftpdir."/yb/".$os;
@ -612,7 +618,7 @@ sub process_request {
my $rsp;
push @{$rsp->{data}},
"stop configuration because Unable to find the os shipped yaboot file.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
xCAT::MsgUtils->message("E", $rsp, $::YABOOT_callback);
return;
}
@ -623,7 +629,7 @@ sub process_request {
my $rsp;
push @{$rsp->{data}},
"stop configuration because $synccmd failed.\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
xCAT::MsgUtils->message("E", $rsp, $::YABOOT_callback);
return;
}
}
@ -665,42 +671,42 @@ sub process_request {
if (($osv =~ /rh/ and int($osn) >= 6) or
($osv =~ /sles/ and int($osn) >= 11)) {
my $fpath = "/yb/". $osentry."/yaboot";
if ($request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
if ($::YABOOT_request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
$sub_req->({command=>['makedhcp'],
node=>\@{$osimagenodehash{$osimage}},
arg=>['-l','-s','filename = \"'.$fpath.'\";']},$callback);
arg=>['-l','-s','filename = \"'.$fpath.'\";']},$::YABOOT_callback);
} else {
$sub_req->({command=>['makedhcp'],
node=>\@{$osimagenodehash{$osimage}},
arg=>['-s','filename = \"'.$fpath.'\";']},$callback);
arg=>['-s','filename = \"'.$fpath.'\";']},$::YABOOT_callback);
}
} else {
if ($request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command, only change local settings if already farmed
if ($::YABOOT_request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command, only change local settings if already farmed
$sub_req->({command=>['makedhcp'],arg=>['-l'],
node=>\@{$osimagenodehash{$osimage}}},$callback);
node=>\@{$osimagenodehash{$osimage}}},$::YABOOT_callback);
} else {
$sub_req->({command=>['makedhcp'],
node=>\@{$osimagenodehash{$osimage}}},$callback);
node=>\@{$osimagenodehash{$osimage}}},$::YABOOT_callback);
}
}
}
} else {
if ($request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command, only change local settings if already farmed
if ($::YABOOT_request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command, only change local settings if already farmed
$sub_req->({command=>['makedhcp'],arg=>['-l'],
node=>\@normalnodeset},$callback);
node=>\@normalnodeset},$::YABOOT_callback);
} else {
$sub_req->({command=>['makedhcp'],
node=>\@normalnodeset},$callback);
node=>\@normalnodeset},$::YABOOT_callback);
}
}
if ($request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
if ($::YABOOT_request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command
$sub_req->({command=>['makedhcp'],
node=>\@breaknetboot,
arg=>['-l','-s','filename = \"xcat/nonexistant_file_to_intentionally_break_netboot_for_localboot_to_work\";']},$callback);
arg=>['-l','-s','filename = \"xcat/nonexistant_file_to_intentionally_break_netboot_for_localboot_to_work\";']},$::YABOOT_callback);
} else {
$sub_req->({command=>['makedhcp'],
node=>\@breaknetboot,
arg=>['-s','filename = \"xcat/nonexistant_file_to_intentionally_break_netboot_for_localboot_to_work\";']},$callback);
arg=>['-s','filename = \"xcat/nonexistant_file_to_intentionally_break_netboot_for_localboot_to_work\";']},$::YABOOT_callback);
}
}
}
@ -708,7 +714,7 @@ sub process_request {
#now run the end part of the prescripts
unless ($args[0] eq 'stat') { # or $args[0] eq 'enact')
$errored=0;
if ($request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children
if ($::YABOOT_request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children
$sub_req->({command=>['runendpre'],
node=>\@nodes,
arg=>[$args[0], '-l']},\&pass_along);
@ -721,7 +727,7 @@ sub process_request {
my $rsp;
$rsp->{errorcode}->[0]=1;
$rsp->{error}->[0]="Failed in running end prescripts\n";
$callback->($rsp);
$::YABOOT_callback->($rsp);
return;
}
}

View File

@ -2,7 +2,7 @@
#-------------------------------------------------------
=head1
xCAT plugin package to handle mkzone,chzone,rmzone commands
xCAT plugin package to handle mkzone,chzone,Input rmzone commands
Supported command:
mkzone,chzone,rmzone - manage xcat cluster zones
@ -66,7 +66,7 @@ sub process_request
my $command = $request->{command}->[0];
my $rc=0;
# the directory which will contain the zone keys
my $keydir="/etc/xcat/sshkeydir/";
my $keydir="/etc/xcat/sshkeys/";
# check if Management Node, if not error
unless (xCAT::Utils->isMN())
@ -95,19 +95,33 @@ sub process_request
my $args = $request->{arg};
@ARGV = @{$args}; # get arguments
my %options = ();
$Getopt::Long::ignorecase = 0;
# Get the zonename if it is in the input
my @SaveARGV = @ARGV;
my $zonename;
my $arg= @SaveARGV[0];
if (!($arg =~ /-h/) && (!($arg =~ /-v/))) { # if not -h -v,then it must be a zone name
$zonename = @SaveARGV[0]; # here is the zonename, if there is one
if ($zonename) { # take zonename off the argument list so it will parse correctly
my $tmp = shift(@SaveARGV);
@ARGV = @SaveARGV;
}
}
Getopt::Long::Configure("posix_default");
Getopt::Long::Configure("no_gnu_compat");
Getopt::Long::Configure("bundling");
my %options = ();
if (
!GetOptions(
'a|noderange=s' => \$options{'noderange'},
'a|noderange=s' => \$options{'addnoderange'},
'r|noderange=s' => \$options{'rmnoderange'},
'defaultzone|defaultzone' => \$options{'defaultzone'},
'g|assigngrp' => \$options{'assigngroup'},
'f|force' => \$options{'force'},
'h|help' => \$options{'help'},
'k|sshkeypath=s' => \$options{'sshkeypath'},
'K|genkeys' => \$options{'gensshkeys'},
's|sshbetweennodes=s' => \$options{'sshbetweennodes'},
'v|version' => \$options{'version'},
'V|Verbose' => \$options{'verbose'},
)
@ -131,20 +145,55 @@ sub process_request
exit 0;
}
# test to see if the zonename was input
if (scalar(@ARGV) == 0) {
if (!$zonename) {
my $rsp = {};
$rsp->{error}->[0] =
"zonename not specified, see man page for syntax.";
"zonename not specified, it is required for this command.";
xCAT::MsgUtils->message("E", $rsp, $callback);
exit 1;
} else {
$request->{zonename} = $ARGV[0];
$request->{zonename} = $zonename;
}
# save input noderange
if ($options{'noderange'}) {
# if -s entered must be yes/1 or no/0
if ($options{'sshbetweennodes'}) {
if ($options{'sshbetweennodes'}=~ /^yes$/i || $options{'sshbetweennodes'} eq "1") {
$options{'sshbetweennodes'}= "yes";
} else {
if ($options{'sshbetweennodes'}=~ /^no$/i || $options{'sshbetweennodes'} eq "0") {
$options{'sshbetweennodes'}= "no";
} else {
my $rsp = {};
$rsp->{error}->[0] =
"The input on the -s flag $options{'sshbetweennodes'} is not valid.";
xCAT::MsgUtils->message("E", $rsp, $callback);
exit 1;
}
}
}
# check for site.sshbetweennodes attribute, put out a warning it will not be used as long
# as zones are defined in the zone table.
my @entries = xCAT::TableUtils->get_site_attribute("sshbetweennodes");
if ($entries[0]) {
my $rsp = {};
$rsp->{info}->[0] =
"The site table sshbetweennodes attribute is set to $entries[0]. It is not used when zones are defined. To get rid of this warning, remove the site table sshbetweennodes attribute.";
xCAT::MsgUtils->message("I", $rsp, $callback);
}
# -a and -r flags cannot be used together
if (($options{'addnoderange'}) && ($options{'rmnoderange'})) {
my $rsp = {};
$rsp->{error}->[0] =
"You may not use the -a flag to add nodes and the -r flag to remove nodes on one command.";
xCAT::MsgUtils->message("E", $rsp, $callback);
exit 1;
}
# save input noderange to add nodes
if ($options{'addnoderange'}) {
# check to see if Management Node is in the noderange, if so error
$request->{noderange}->[0] = $options{'noderange'};
$request->{noderange}->[0] = $options{'addnoderange'};
my @nodes = xCAT::NodeRange::noderange($request->{noderange}->[0]);
my @mname = xCAT::Utils->noderangecontainsMn(@nodes);
if (@mname)
@ -156,20 +205,25 @@ sub process_request
xCAT::MsgUtils->message("E", $rsp, $callback, 1);
exit 1;
}
# now check for service nodes in noderange. It they exist that is an error also.
my @SN;
my @CN;
xCAT::ServiceNodeUtils->getSNandCPnodes(\@nodes, \@SN, \@CN);
if (scalar(@SN))
{ # SN in the nodelist
my $nodes=join(',', @SN);
}
# save input noderange to remove nodes
if ($options{'rmnoderange'}) {
# check to see if Management Node is in the noderange, if so error
$request->{noderange}->[0] = $options{'rmnoderange'};
my @nodes = xCAT::NodeRange::noderange($request->{noderange}->[0]);
my @mname = xCAT::Utils->noderangecontainsMn(@nodes);
if (@mname)
{ # MN in the nodelist
my $nodes=join(',', @mname);
my $rsp = {};
$rsp->{error}->[0] =
"You must not run $command and include any service nodes: $nodes.";
"You must not run $command and include the management node: $nodes.";
xCAT::MsgUtils->message("E", $rsp, $callback, 1);
exit 1;
}
# now check for service nodes in noderange. It they exist that is an error also.
}
@ -188,14 +242,14 @@ sub process_request
}
if ($command eq "rmzone")
{
$rc=rmzone($request, $callback,\%options,$keydir);
$rc=rmzone($request, $callback,\%options);
}
my $rsp = {};
if ($rc ==0) {
$rsp->{info}->[0] = "The $command ran successfully.";
xCAT::MsgUtils->message("I", $rsp, $callback);
} else {
$rsp->{info}->[0] = "The $command had errors.";
$rsp->{error}->[0] = "The $command had errors.";
xCAT::MsgUtils->message("E", $rsp, $callback);
}
return $rc;
@ -207,7 +261,11 @@ sub process_request
=head3
Parses and runs mkzone
Input
request
callback
Input arguments from the GetOpts
zone ssh key dir
=cut
@ -221,18 +279,26 @@ sub mkzone
my $rsp = {};
$rsp->{error}->[0] =
"zonename not specified, see man page for syntax.";
"zonename not specified The zonename is required.";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
# test for -g, if no noderange this is an error
if (( ! defined($$options{'noderange'})) && ($$options{'assigngroup'})) {
if (( ! defined($$options{'addnoderange'})) && ($$options{'assigngroup'})) {
my $rsp = {};
$rsp->{error}->[0] =
" The -g flag requires a noderange ( -a).";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
# test for -r, not valid
if ($$options{'rmnoderange'}) {
my $rsp = {};
$rsp->{error}->[0] =
" The -r flag Is not valid for mkzone. Use chzone.";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
# check to see if the input zone already exists
if (xCAT::Zone->iszonedefined($request->{zonename})) {
my $rsp = {};
@ -243,12 +309,18 @@ sub mkzone
}
# Create path to generated ssh keys
# keydir comes in set to /etc/xcat/sshkeys
$keydir .= $request->{zonename};
$keydir .= "/.ssh";
# update the zone table
$rc=updatezonetable($request, $callback,$options,$keydir);
# add new zones to the zone table
$rc=addtozonetable($request, $callback,$options,$keydir);
if ($rc == 0) { # zone table setup is ok
$rc=updatenodelisttable($request, $callback,$options,$keydir);
# test for a noderange, if(-a) not supplied nothing to do
if (defined($$options{'addnoderange'})) {
$rc=addnodestozone($request, $callback,$options,$keydir);
}
if ($rc == 0) { # zone table setup is ok
# generate root ssh keys
$rc=gensshkeys($request, $callback,$options,$keydir);
@ -267,6 +339,10 @@ sub mkzone
=head3
Parses and runs chzone
Input
request
callback
Input arguments from the GetOpts
=cut
@ -275,35 +351,212 @@ sub mkzone
sub chzone
{
my ($request, $callback,$options,$keydir) = @_;
my $rc=0;
# Create default path to generated ssh keys
# keydir comes in set to /etc/xcat/sshkeys
$keydir .= $request->{zonename};
$keydir .= "/.ssh";
my $zonename=$request->{zonename};
# already checked but lets do it again, need a zonename
if (!($request->{zonename})) {
my $rsp = {};
$rsp->{error}->[0] =
"zonename not specified The zonename is required.";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
# see if they asked to do anything
if ((!($$options{'sshkeypath'})) && (!($$options{'gensshkeys'})) &&
(!( $$options{'addnoderange'})) && (!( $$options{'rmnoderange'})) &&
(!( $$options{'defaultzone'})) &&
(!($$options{'assigngroup'} )) && (!($$options{'sshbetweennodes'}))) {
my $rsp = {};
$rsp->{info}->[0] =
"chzone was run but nothing to do.";
xCAT::MsgUtils->message("I", $rsp, $callback);
return 0;
}
# test for -g, if no noderange (-r or -a) this is an error
if ((( ! defined($$options{'addnoderange'}))&& ( ! defined($$options{'rmnoderange'}))) && ($$options{'assigngroup'})) {
my $rsp = {};
$rsp->{error}->[0] =
" The -g flag requires a noderange using the -a or -r option.";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
# if -r remove nodes from zone, check to see that they are a member of the zone
# if not a member of the zone, error out and do nothing
if ($$options{'rmnoderange'}){
my @nodes = xCAT::NodeRange::noderange($request->{noderange}->[0]);
foreach my $node (@nodes) {
my $nodezonename=xCAT::Zone->getmyzonename($node);
if ($nodezonename ne $zonename) {
my $rsp = {};
$rsp->{error}->[0] =
" $node does not belong to the zone:$zonename. Rerun the chzone -r command with only nodes in the noderange that are currently assigned to the zone.";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
}
}
# get the zone ssh key directory. We don't have a good zone without it.
my $sshrootkeydir = xCAT::Zone->getzonekeydir($zonename);
if ($sshrootkeydir == 1) { # error return
#if we have been requested to regenerated the ssh keys continue
if (($$options{'sshkeypath'}) || ($$options{'gensshkeys'})) {
my $rsp = {};
$rsp->{info}->[0] =
" sshkeydir attribute not defined for $zonename. The zone sshkeydir will be regenerated.";
xCAT::MsgUtils->message("I", $rsp, $callback);
} else { # sshkeydir is missing and they did not request to regenerate, that is an error
my $rsp = {};
$rsp->{error}->[0] =
" sshkeydir attribute not defined for $zonename. The zone sshkeydir must be regenerated. Rerun this command with -k or -K options";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
} else { # we got a sshkeydir from the database, use it
$keydir=$sshrootkeydir;
}
# do we regenerate keys (-k or -K)
if (($$options{'sshkeypath'}) || ($$options{'gensshkeys'})) {
$rc=gensshkeys($request, $callback,$options,$keydir);
if ($rc != 0) {
return 1;
}
}
# update the zone table
$rc=updatezonetable($request, $callback,$options,$keydir);
if ($rc == 0) { # zone table setup is ok
# update the nodelist table
if (defined($$options{'addnoderange'})) {
$rc=addnodestozone($request, $callback,$options,$keydir);
} else { # note -a and -r are not allowed on one chzone
if (defined($$options{'rmnoderange'})) {
$rc=rmnodesfromzone($request, $callback,$options,$keydir);
}
}
}
# my $rsp = {};
#xCAT::MsgUtils->message("I", $rsp, $callback);
return 0;
return $rc;
}
#-------------------------------------------------------
=head3
Parses and runs rmzone
Input
request
callback
Input arguments from the GetOpts
=cut
#-------------------------------------------------------
sub rmzone
{
my ($request, $callback,$options,$keydir) = @_;
my ($request, $callback,$options) = @_;
# already checked but lets do it again, need a zonename, it is the only required parm
if (!($request->{zonename})) {
my $rsp = {};
$rsp->{error}->[0] =
"zonename not specified The zonename is required.";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
# check to see if the input zone already exists
# cannot remove it if it is not defined
my $zonename=$request->{zonename};
if (!(xCAT::Zone->iszonedefined($zonename))) {
my $rsp = {};
$rsp->{error}->[0] =
" zonename: $zonename is not defined. You cannot remove it.";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
# is this zone is the default zone you must force the delete
my $defaultzone =xCAT::Zone->getdefaultzone($callback);
if (($defaultzone eq $zonename) && (!($$options{'force'}))) {
my $rsp = {};
$rsp->{error}->[0] =
" You are removing the default zone: $zonename. You must define another default zone before deleting or use the -f flag to force the removal.";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
# my $rsp = {};
# get the zone ssh key directory
my $sshrootkeydir = xCAT::Zone->getzonekeydir($zonename);
if ($sshrootkeydir == 1) { # error return
my $rsp = {};
$rsp->{info}->[0] =
" sshkeydir attribute not defined for $zonename. Cannot remove it.";
xCAT::MsgUtils->message("I", $rsp, $callback);
} else { # remove the keys unless it is /root/.ssh
my $roothome = xCAT::Utils->getHomeDir("root");
$roothome .="\/.ssh";
if ($sshrootkeydir eq $roothome) { # will not delete /root/.ssh
my $rsp = {};
$rsp->{info}->[0] =
" $zonename sshkeydir is $roothome. This will not be deleted.";
xCAT::MsgUtils->message("I", $rsp, $callback);
} else { # not roothome/.ssh
# check to see if id_rsa.pub is there. I don't want to remove the
# wrong directory
# if id_rsa.pub exists remove the files
# then remove the directory
if ( -e "$sshrootkeydir/id_rsa.pub") {
my $cmd= "rm -rf $sshrootkeydir";
xCAT::Utils->runcmd($cmd,0);
if ($::RUNCMD_RC != 0)
{
my $rsp = {};
$rsp->{error}->[0] = "Command: $cmd failed";
xCAT::MsgUtils->message("E", $rsp, $callback);
}
my ($zonedir,$ssh)= split(/\.ssh/, $sshrootkeydir);
$cmd= "rmdir $zonedir";
xCAT::Utils->runcmd($cmd,0);
if ($::RUNCMD_RC != 0)
{
my $rsp = {};
$rsp->{error}->[0] = "Command: $cmd failed";
xCAT::MsgUtils->message("E", $rsp, $callback);
}
} else { # no id_rsa.pub key will not remove the files
my $rsp = {};
$rsp->{info}->[0] = "$sshrootkeydir did not contain an id_rsa.pub key, will not remove files";
xCAT::MsgUtils->message("I", $rsp, $callback);
}
}
}
#xCAT::MsgUtils->message("I", $rsp, $callback);
# open zone table and remove this entry
my $tab = xCAT::Table->new("zone");
if (!defined($tab)) {
my $rsp = {};
$rsp->{error}->[0] =
" Failure opening the zone table.";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
# remove the table entry
$tab->delEntries({zonename=>$zonename});
# remove zonename and possibly group name (-g flag) from any nodes defined in this zone
my $rc=rmnodesfromzone($request, $callback,$options,"ALL");
return $rc;
return 0;
}
@ -337,11 +590,11 @@ sub usage
my $usagemsg2="";
if ($command eq "mkzone") {
$usagemsg1 = " mkzone -h \n mkzone -v \n";
$usagemsg2 = " mkzone <zonename> [-V] [--defaultzone] [-k <full path to the ssh RSA private key] \n [-a <noderange>] [-g] [-f]";
$usagemsg2 = " mkzone <zonename> [-V] [--defaultzone] [-k <full path to the ssh RSA private key] \n [-a <noderange>] [-g] [-f] [-s <yes/no>]";
} else {
if ($command eq "chzone") {
$usagemsg1 = " chzone -h \n chzone -v \n";
$usagemsg2 = " chzone <zonename> [-V] [--defaultzone] [-k <full path to the ssh RSA private key] \n [-K] [-a <noderange>] [-r <noderange>] [-g] ";
$usagemsg2 = " chzone <zonename> [-V] [--defaultzone] [-k <full path to the ssh RSA private key] \n [-K] [-a <noderange>] [-r <noderange>] [-g] [-s <yes/no>]";
} else {
if ($command eq "rmzone") {
$usagemsg1 = " rmzone -h \n rmzone -v \n";
@ -349,7 +602,7 @@ sub usage
}
}
}
my $usagemsg .= $usagemsg1 .= $usagemsg2 .= "\n";
my $usagemsg .= $usagemsg1 .= $usagemsg2 ;
if ($callback)
{
my $rsp = {};
@ -366,7 +619,7 @@ sub usage
=head3
generate the ssh keys and store them in /etc/xcat/sshkeys/<zonename>
generate the ssh keys and store them in /etc/xcat/sshkeys/<zonename>/.ssh
=cut
@ -407,7 +660,7 @@ sub gensshkeys
#-------------------------------------------------------
=head3
updatezonetable
addtozonetable
Add the new zone to the zone table, check if already there and
error - use either chzone or -f to override default
@ -416,7 +669,7 @@ sub gensshkeys
=cut
#-------------------------------------------------------
sub updatezonetable
sub addtozonetable
{
my ($request, $callback,$options,$keydir) = @_;
my $rc=0;
@ -424,8 +677,28 @@ sub updatezonetable
my $tab = xCAT::Table->new("zone");
if ($tab)
{
# read a record from the zone table, if it is empty then add
# the xcatdefault entry
my @zones = $tab->getAllAttribs('zonename');
if (!(@zones)) { # table empty
my %xcatdefaultzone;
$xcatdefaultzone{defaultzone} ="yes";
$xcatdefaultzone{sshbetweennodes} ="yes";
my $roothome = xCAT::Utils->getHomeDir("root");
$roothome .="\/.ssh";
$xcatdefaultzone{sshkeydir} =$roothome;
$tab->setAttribs({zonename => "xcatdefault"}, \%xcatdefaultzone);
}
# now add the users zone
my %tb_cols;
$tb_cols{sshkeydir} = $keydir;
$tb_cols{sshkeydir} = $keydir; # key directory
# set sshbetweennodes attribute from -s flag or default to yes
if ( $$options{'sshbetweennodes'}) {
$tb_cols{sshbetweennodes} = $$options{'sshbetweennodes'};
} else {
$tb_cols{sshbetweennodes} = "yes";
}
my $zonename=$request->{zonename};
if ( $$options{'defaultzone'}) { # set the default
# check to see if a default already defined
@ -471,7 +744,82 @@ sub updatezonetable
#-------------------------------------------------------
=head3
updatenodelisttable
updatezonetable
change either the sshbetweennodes or defaultzone attribute
or generate new keys ( -k -K)
=cut
#-------------------------------------------------------
sub updatezonetable
{
my ($request, $callback,$options,$keydir) = @_;
my $zoneentry;
my $zonename=$request->{zonename};
# check for changes
if (($$options{'sshbetweennodes'}) || ( $$options{'defaultzone'}) ||
($$options{'sshkeypath'}) || ($$options{'gensshkeys'})) {
my $tab = xCAT::Table->new("zone");
if($tab) {
# now add the users changes
my %tb_cols;
# generated keys ( -k or -K)
if (($$options{'sshkeypath'}) || ($$options{'gensshkeys'})) {
$tb_cols{sshkeydir} = $keydir; # key directory
}
# set sshbetweennodes attribute from -s flag
if ( $$options{'sshbetweennodes'}) {
$tb_cols{sshbetweennodes} = $$options{'sshbetweennodes'};
}
# if --defaultzone
if ( $$options{'defaultzone'}) { # set the default
# check to see if a default already defined
my $curdefaultzone = xCAT::Zone->getdefaultzone($callback);
if (!(defined ($curdefaultzone))) { # no default defined
$tb_cols{defaultzone} ="yes";
} else { # already a default
if ($$options{'force'}) { # force the default
$tb_cols{defaultzone} ="yes";
$tab->setAttribs({zonename => $zonename}, \%tb_cols);
# now change the old default zone to not be the default
my %tb1_cols;
$tb1_cols{defaultzone} ="no";
$tab->setAttribs({zonename => $curdefaultzone}, \%tb1_cols);
$tab->commit();
$tab->close();
} else { # no force this is an error
my $rsp = {};
$rsp->{error}->[0] =
" Failure setting default zone. The defaultzone $curdefaultzone already exists. Use the -f flag if you want to override the current default zone.";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
}
} else { # not a default zone change, just commit the other changes
$tab->setAttribs({zonename => $zonename}, \%tb_cols);
$tab->commit();
$tab->close();
}
} else {
my $rsp = {};
$rsp->{error}->[0] =
" Failure opening the zone table.";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
}
return 0;
}
#-------------------------------------------------------
=head3
addnodestozone
Add the new zonename attribute to any nodes in the noderange ( if a noderange specified)
Add zonename group to nodes in the noderange if -g flag.
@ -480,19 +828,21 @@ sub updatezonetable
=cut
#-------------------------------------------------------
sub updatenodelisttable
sub addnodestozone
{
my ($request, $callback,$options,$keydir) = @_;
my $rc=0;
# test for a noderange, if not supplied nothing to do
if ( ! defined($$options{'noderange'})) {
return 0;
}
my $zonename=$request->{zonename};
# there is a node range. update the nodelist table
# if -g add zonename group also
my $group=$$options{'noderange'};
my @nodes = xCAT::NodeRange::noderange($request->{noderange}->[0]);
# check to see if noderange expanded
if (!(scalar @nodes)) {
my $rsp = {};
$rsp->{error}->[0] =
" The noderange $request->{noderange}->[0] is not valid. The nodes are not defined.";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
my $tab = xCAT::Table->new("nodelist");
if ($tab)
{
@ -516,5 +866,63 @@ sub updatenodelisttable
return $rc;
}
#-------------------------------------------------------
=head3
rmnodesfromzone
removes the zonename from all nodes with their zonename the input zone or
the noderange supplied on the -r flag
if -g, removes zonename group from all nodes defined with their zonename the input zone.
Note if $ALL is input it removes all nodes from the zone,
otherwise $request->{noderange} points to the noderange
=cut
#-------------------------------------------------------
sub rmnodesfromzone
{
my ($request, $callback,$options,$ALL) = @_;
my $zonename=$request->{zonename};
my $tab = xCAT::Table->new("nodelist");
if ($tab)
{
# read all the nodes with zonename
my @nodes;
if ($ALL) { # do all nodes
@nodes = xCAT::Zone->getnodesinzone($callback,$zonename);
} else { # the nodes in the noderange ( -r )
@nodes = xCAT::NodeRange::noderange($request->{noderange}->[0]);
# check to see if noderange expanded
if (!(scalar @nodes)) {
my $rsp = {};
$rsp->{error}->[0] =
" The noderange $request->{noderange}->[0] is not valid. The nodes are not defined.";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
}
# if -g then remove the zonename group attribute on each node
if ($$options{'assigngroup'}){
foreach my $node (@nodes) {
xCAT::TableUtils->rmnodegroups($node,$tab,$zonename);
}
}
# set the nodelist zonename to nothing
my $nozonename="";
$tab-> setNodesAttribs(\@nodes, { zonename => $nozonename });
$tab->commit();
$tab->close();
} else {
my $rsp = {};
$rsp->{error}->[0] =
" Failure opening the nodelist table.";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
return 0;
}
1;

View File

@ -540,11 +540,16 @@ if ($::INITIALINSTALL || $::FORCE)
elsif(-f "/etc/redhat-release")
{
$fwserv = "iptables";
if( -f "/usr/sbin/firewalld" )
{
$fwserv = "firewalld";
}
}
else
{
#Ubuntu: FIXME
}
if($fwserv)
{
my $cmd = "service $fwserv stop";
@ -855,19 +860,21 @@ sub settunables
{
# tuning ARP on Linux
# set for right now
my $cmd = "/bin/echo '1024' >/proc/sys/net/ipv4/neigh/default/gc_thresh1";
my $ECHO=xCAT::Utils->fullpathbin("echo");
my $cmd = "$ECHO '1024' >/proc/sys/net/ipv4/neigh/default/gc_thresh1";
my $outref = xCAT::Utils->runcmd("$cmd", 0);
if ($::RUNCMD_RC != 0)
{
xCAT::MsgUtils->message( 'E', "Could not run $cmd.");
}
$cmd = "/bin/echo '4096' >/proc/sys/net/ipv4/neigh/default/gc_thresh2";
$cmd = "$ECHO '4096' >/proc/sys/net/ipv4/neigh/default/gc_thresh2";
my $outref = xCAT::Utils->runcmd("$cmd", 0);
if ($::RUNCMD_RC != 0)
{
xCAT::MsgUtils->message( 'E', "Could not run $cmd.");
}
$cmd = "/bin/echo '8192' >/proc/sys/net/ipv4/neigh/default/gc_thresh3";
$cmd = "$ECHO '8192' >/proc/sys/net/ipv4/neigh/default/gc_thresh3";
my $outref = xCAT::Utils->runcmd("$cmd", 0);
if ($::RUNCMD_RC != 0)
{
@ -1257,7 +1264,7 @@ sub initDB
$chtabcmds .= "$::XCATROOT/sbin/chtab key=vsftp site.value=n;";
$chtabcmds .= "$::XCATROOT/sbin/chtab key=cleanupxcatpost site.value=no;";
$chtabcmds .= "$::XCATROOT/sbin/chtab key=dhcplease site.value=43200;";
$chtabcmds .= "$::XCATROOT/sbin/chtab key=useflowcontrol site.value=yes;";
#$chtabcmds .= "$::XCATROOT/sbin/chtab key=useflowcontrol site.value=yes;"; # need to fix 4031
if ($::osname eq 'AIX')
{
@ -1853,10 +1860,11 @@ sub setupLinuxexports
# restart nfs
my $cmd;
my $os = xCAT::Utils->osver();
my $SERVICE = xCAT::Utils->fullpathbin("service");
if ($os =~ /sles/) {
$cmd = "/sbin/service nfsserver restart";
$cmd = "$SERVICE nfsserver restart";
} else {
$cmd = "/sbin/service nfs restart";
$cmd = "$SERVICE nfs restart";
}
my $outref = xCAT::Utils->runcmd("$cmd", 0);
if ($::RUNCMD_RC != 0)
@ -1868,10 +1876,11 @@ sub setupLinuxexports
xCAT::MsgUtils->message('I', "NFS has been restarted.");
}
my $CHKCONFIG=xCAT::Utils->fullpathbin("chkconfig");
if ($os =~ /sles/) {
$cmd = "/sbin/chkconfig nfsserver on";
$cmd = "$CHKCONFIG nfsserver on";
} else {
$cmd = "/sbin/chkconfig nfs on";
$cmd = "$CHKCONFIG nfs on";
}
$outref = xCAT::Utils->runcmd("$cmd", 0);
if ($::RUNCMD_RC != 0)
@ -1969,10 +1978,14 @@ sub setuphttp
{ #for sles/ubuntu
$cmd = "/etc/init.d/apache2 stop; /etc/init.d/apache2 start";
}
else
elsif (-e "/etc/init.d/httpd")
{
$cmd = "/etc/init.d/httpd stop; /etc/init.d/httpd start";
}
else
{
$cmd = "service httpd stop; service httpd start";
}
my $outref = xCAT::Utils->runcmd("$cmd", 0);
if ($::RUNCMD_RC != 0)
@ -1996,10 +2009,26 @@ sub setuphttp
$cmd = "/sbin/chkconfig apache2 on";
}
}
# elsif (-e "/sbin/chkconfig")
# {
# $cmd = "/sbin/chkconfig httpd on";
# }
# elsif (-e "/usr/sbin/chkconfig")
# {
# $cmd = "/usr/sbin/chkconfig httpd on";
# }
# else
# {
# $cmd = "chkconfig httpd on";
# }
else
{
$cmd = "/sbin/chkconfig httpd on";
my $CHKCONFIG = xCAT::Utils->fullpathbin("chkconfig");
$cmd = "$CHKCONFIG httpd on";
}
$outref = xCAT::Utils->runcmd("$cmd", 0);
if ($::RUNCMD_RC != 0)
{

View File

@ -323,35 +323,42 @@ sleep 0.05; #up to 50 ms outage possible
my $conn;
next unless $conn = $socket->accept;
my @clients;
if ($inet6support) {
@clients = gethostbyaddr($conn->peeraddr,AF_INET6);
unless (@clients) { @clients = gethostbyaddr($conn->peeraddr,AF_INET); }
} else {
@clients = gethostbyaddr($conn->peeraddr,AF_INET);
}
my $client_name;
my $client_aliases;
my @clients;
if ($inet6support) {
($client_name,$client_aliases) = gethostbyaddr($conn->peeraddr,AF_INET6);
unless ($client_name) { ($client_name,$client_aliases) = gethostbyaddr($conn->peeraddr,AF_INET); }
} else {
($client_name,$client_aliases) = gethostbyaddr($conn->peeraddr,AF_INET);
}
$clients[0] = $client_name;
if ($client_aliases) {
push @clients, split(/\s+/,$client_aliases);
}
my $validclient=0;
my $node;
my $domain;
my $nd = xCAT::NetworkUtils->getNodeDomains(\@clients);
my %nodedomains = %{$nd};
foreach my $client (@clients) {
$domain = $nodedomains{$client};
my @ndn = ($client);
my $nd = xCAT::NetworkUtils->getNodeDomains(\@ndn);
my %nodedomains = %{$nd};
$domain = $nodedomains{$client};
$client =~ s/\..*//;
if ($domain) {
$client =~ s/\.$domain//;
} else {
$client =~ s/\..*//;
if ($domain) {
$client =~ s/\.$domain//;
} else {
$client =~ s/\..*//;
}
#ensure this is coming from a node IP at least
($node) = noderange($client);
if ($node) { #Means the source isn't valid
$validclient=1;
last;
}
}
#ensure this is coming from a node IP at least
($node) = noderange($client);
if ($node) { #Means the source isn't valid
$validclient=1;
last;
}
}
unless ($validclient) {

Some files were not shown because too many files have changed in this diff Show More