2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-05-20 07:44:53 +00:00

Merge pull request #4885 from xcat2/master

Merge master to 2.13 branch for 2.13.11 release(1)
This commit is contained in:
zet809
2018-03-05 17:44:56 +08:00
committed by GitHub
120 changed files with 4809 additions and 954 deletions
+1 -1
View File
@@ -1 +1 @@
2.13.10
2.13.11
+91
View File
@@ -0,0 +1,91 @@
#!/bin/bash
#
# Author: Yuan Bai (bybai@cn.ibm.com)
#
#
printusage()
{
echo "Usage : build-python-deb xcat-openbmc-py"
}
# For the purpose of getting the distribution name
if [[ ! -f /etc/lsb-release ]]; then
echo "ERROR: Could not find /etc/lsb-release, is this script executed on a Ubuntu machine?"
exit 1
fi
. /etc/lsb-release
# Check the necessary commands before starting the build
for cmd in dch dpkg-buildpackage
do
if ! type "$cmd" >/dev/null 2>&1
then
echo "ERROR: Required command, $package, not found." >&2
exit 1
fi
done
# Supported distributions
pkg_name=$1
if [ "$pkg_name" != "xcat-openbmc-py" ]; then
printusage
exit 1
fi
# Find where this script is located to set some build variables
old_pwd=`pwd`
cd `dirname $0`
curdir=`pwd`
if [ -z "$REL" ]; then
t=${curdir%/src/xcat-core}
REL=`basename $t`
fi
if [ "$PROMOTE" != 1 ]; then
ver=`cat Version`
echo "###############################"
echo "# Building xcat-openbmc-py package #"
echo "###############################"
#the package type: local | snap | alpha
#the build introduce string
build_string="Snap_Build"
xcat_release="snap$(date '+%Y%m%d%H%M')"
pkg_version="${ver}-${xcat_release}"
packages="xCAT-openbmc-py"
for file in $packages
do
file_low="${file,,}"
target_archs="all"
for target_arch in $target_archs
do
cd $file
CURDIR=$(pwd)
dch -v $pkg_version -b -c debian/changelog $build_string
if [ "$target_arch" = "all" ]; then
CURDIR=$(pwd)
cp ${CURDIR}/debian/control ${CURDIR}/debian/control.save.998
sed -i -e "s#>= 2.13-snap000000000000#= ${pkg_version}#g" ${CURDIR}/debian/control
dpkg-buildpackage -rfakeroot -uc -us
mv ${CURDIR}/debian/control.save.998 ${CURDIR}/debian/control
dh_testdir
dh_testroot
dh_clean -d
fi
rc=$?
if [ $rc -gt 0 ]; then
echo "Error: $file build package failed exit code $rc"
exit $rc
fi
rm -f debian/files
rm -f debian/xcat-openbmc-py.debhelper.log
rm -f debian/xcat-openbmc-py.substvars
sed -i -e "s/* Snap_Build//g" debian/changelog
cd -
rm -f ${file_low}_*.tar.gz
rm -f ${file_low}_*.changes
rm -f ${file_low}_*.dsc
done
done
fi
+1 -1
View File
@@ -183,8 +183,8 @@ then
short_short_ver=`cat Version|cut -d. -f 1`
build_time=`date`
build_machine=`hostname`
commit_id=`git rev-parse --short HEAD`
commit_id_long=`git rev-parse HEAD`
commit_id="${commit_id_long:0:7}"
package_dir_name=debs$REL
#TODO: define the core path and tarball name
+3 -3
View File
@@ -70,7 +70,7 @@ if [ -z "$UP" ]; then
fi
# These are the rpms that should be built for each kind of xcat build
ALLBUILD="perl-xCAT xCAT-client xCAT-server xCAT-test xCAT-buildkit xCAT xCATsn xCAT-genesis-scripts xCAT-SoftLayer xCAT-vlan xCAT-confluent xCAT-probe xCAT-csm"
ALLBUILD="perl-xCAT xCAT-client xCAT-server xCAT-test xCAT-buildkit xCAT xCATsn xCAT-genesis-scripts xCAT-SoftLayer xCAT-vlan xCAT-confluent xCAT-probe xCAT-csm xCAT-openbmc-py"
ZVMBUILD="perl-xCAT xCAT-server xCAT-UI"
ZVMLINK="xCAT-client xCAT xCATsn"
# xCAT and xCATsn have PCM specific configuration - conserver-xcat, syslinux-xcat
@@ -188,8 +188,8 @@ function setversionvars {
SHORTSHORTVER=`echo $VER|cut -d. -f 1`
BUILD_TIME=`date`
BUILD_MACHINE=`hostname`
COMMIT_ID=`git rev-parse --short HEAD`
COMMIT_ID_LONG=`git rev-parse HEAD`
COMMIT_ID="${COMMIT_ID_LONG:0:7}"
XCAT_RELEASE="snap$(date '+%Y%m%d%H%M')"
echo "$XCAT_RELEASE" >Release
}
@@ -323,7 +323,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 xCAT-SoftLayer xCAT-vlan xCAT-confluent xCAT-probe xCAT-csm; do
for rpmname in xCAT-client xCAT-server xCAT-IBMhpc xCAT-rmc xCAT-UI xCAT-test xCAT-buildkit xCAT-SoftLayer xCAT-vlan xCAT-confluent xCAT-probe xCAT-csm xCAT-openbmc-py; do
if [[ " $EMBEDBUILD " != *\ $rpmname\ * ]]; then continue; fi
if [ "$OSNAME" = "AIX" -a "$rpmname" = "xCAT-buildkit" ]; then continue; fi # do not build xCAT-buildkit on aix
if [ "$OSNAME" = "AIX" -a "$rpmname" = "xCAT-SoftLayer" ]; then continue; fi # do not build xCAT-softlayer on aix
+8
View File
@@ -47,6 +47,14 @@ The following commands are supported against a compute node:
The following commands are supported against a PDU:
* To change hostname of IR PDU: ::
# rspconfig f5pdu3 hosname=f5pdu3
* To change ip address of IR PDU: ::
# rsconfig f5pdu3 ip=x.x.x.x netmaks=255.x.x.x
* Check the status of the full PDU: ::
# rpower f5pdu3 stat
+1 -1
View File
@@ -20,7 +20,7 @@ xCAT uses snmp scan method to discover PDU. Make sure net-snmp-utils package is
-x XML formatted output.
-z Stanza formatted output.
-w Writes output to xCAT database.
--setup Process switch-based pdu discovery and configure the PDUs(it included passwordless , change ip address from dhcp to static and snmp configuration). It required predefined PDU node definition with switch name and switch port attributes for mapping. (Notes: only support for crpdu for now for this options)
--setup Process switch-based pdu discovery and configure the PDUs. For crpdu, --setup options will configure passwordless , change ip address from dhcp to static, hostname changes and snmp v3 configuration. For irpdu, it will configure ip address and hostname. It required predefined PDU node definition with switch name and switch port attributes for mapping.
Define PDU Objects
@@ -108,7 +108,7 @@ For system x machine, on sles10 set the crashkernelsize attribute like this: ::
chdef -t osimage <image name> crashkernelsize=<size>M@16M
On sles11 and rhels6 set the crashkernelsize attribute like this: ::
On sles11, rhels6 and above set the crashkernelsize attribute like this: ::
chdef -t osimage <image name> crashkernelsize=<size>M
@@ -118,13 +118,21 @@ Where <size> recommended value is 256. For more information about the size can r
`<http://www.novell.com/support/kb/doc.php?id=3374462>`_.
`<https://access.redhat.com/knowledge/docs/en-US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/s2-kdump-configuration-cli.html>`_.
`<https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/kernel_crash_dump_guide/sect-kdump-config-cli>`_.
For system p machine, set the crashkernelsize attribute to this: ::
chdef -t osimage <image name> crashkernelsize=<size>@32M
For Power System AC922, set the crashkernelsize attribute to this: ::
chdef -t osimage <image name> crashkernelsize=<size>M
Where <size> recommended value is 256, more information can refer the kdump document for the system x.
**Notes**: The ``crashkernel=`` option can be defined in multiple ways. If it is hard to decide the specific crashkernelsize, auto value can be used, the auto value enables automatic configuration of reserved memory based on the total amount of memory in the system like ``crashkernel=auto``.
When your node starts, and you get a kdump start error like this: ::
Your running kernel is using more than 70% of the amount of space you reserved for kdump, you should consider increasing your crashkernel
@@ -10,6 +10,8 @@ There are 2 ways to configure OS route in xCAT:
Before using ``makeroutes`` or ``setroute`` to configure OS route, details of the routes data such as routename, subnet, net mask and gateway should be stored in ``routes`` table.
**Notes**: the ``gateway`` in the ``networks`` table assigns ``gateway`` from DHCP to compute node, so if use ``makeroutes`` or ``setroute`` to configure OS static route for compute node, make sure there is no ``gateway`` for the specific network in ``networks`` table.
Configure ``routes`` table
``````````````````````````
@@ -11,11 +11,28 @@ SYNOPSIS
********
\ **rbeacon**\ [\ **-h | -**\ **-help | -v | -**\ **-version | -V | -**\ **-verbose**\ ]
BMC (using IPMI):
=================
\ **rbeacon**\ \ *noderange*\ {\ **on | blink | off | stat**\ }
\ **rbeacon**\ [\ **-h | -**\ **-help**\ ]
\ **rbeacon**\ {\ **-v | -**\ **-version**\ }
OpenPOWER BMC (using IPMI):
===========================
\ **rbeacon**\ \ *noderange*\ {\ **on | blink | off | stat**\ }
OpenPOWER OpenBMC:
==================
\ **rbeacon**\ \ *noderange*\ {\ **on | off**\ }
***********
@@ -19,15 +19,15 @@ Name
****************
\ **rflash**\ [\ **-h | -**\ **-help**\ | \ **-v | -**\ **-version**\ ]
\ **rflash**\ [\ **-h | -**\ **-help**\ | \ **-v | -**\ **-version**\ | \ **-V | -**\ **-verbose**\ ]
PPC (with HMC) specific:
========================
\ **rflash**\ \ *noderange*\ \ **-p**\ \ *directory*\ [\ **-**\ **-activate**\ {\ **concurrent | disruptive**\ }] [\ **-V | -**\ **-verbose**\ ]
\ **rflash**\ \ *noderange*\ \ **-p**\ \ *directory*\ [\ **-**\ **-activate**\ {\ **concurrent | disruptive**\ }]
\ **rflash**\ \ *noderange*\ {\ **-**\ **-commit | -**\ **-recover**\ } [\ **-V | -**\ **-verbose**\ ]
\ **rflash**\ \ *noderange*\ {\ **-**\ **-commit | -**\ **-recover**\ }
PPC (without HMC, using Direct FSP Management) specific:
@@ -50,7 +50,7 @@ OpenPOWER BMC specific (using IPMI):
====================================
\ **rflash**\ \ *noderange*\ [\ *hpm_file_path*\ | \ **-d**\ \ *data_directory*\ ] [\ **-c | -**\ **-check**\ ] [\ **-**\ **-retry=**\ \ *count*\ ] [\ **-V**\ ]
\ **rflash**\ \ *noderange*\ [\ *hpm_file_path*\ | \ **-d**\ \ *data_directory*\ ] [\ **-c | -**\ **-check**\ ] [\ **-**\ **-retry=**\ \ *count*\ ]
\ **rflash**\ \ *noderange*\ \ **-**\ **-recover**\ \ *bmc_file_path*\
@@ -90,7 +90,7 @@ OPTIONS
\ **-C|-**\ **-cleanup**\
Perform additional cleanup by running \ **nodeset offline**\ and \ **makeconservercf -d**\ on the objects specified in the \ *noderange*\ .
Perform additional cleanup by running \ **nodeset offline**\, \ **makeconservercf -d**\ and \ **makegocons --cleanup**\ on the objects specified in the \ *noderange*\ .
@@ -27,7 +27,7 @@ BMC (using IPMI):
=================
\ **rpower**\ \ *noderange*\ [\ **on | off | softoff | reset | boot | stat | state | status | wake | suspend**\ [\ **-w**\ \ *timeout*\ ] [\ **-o**\ ] [\ **-r**\ ]]
\ **rpower**\ \ *noderange*\ [\ **on | off | softoff | reset | boot | cycle | stat | state | status | wake | suspend**\ [\ **-w**\ \ *timeout*\ ] [\ **-o**\ ] [\ **-r**\ ]]
\ **rpower**\ \ *noderange*\ [\ **pduon | pduoff | pdustat | pdureset**\ ]
@@ -13,7 +13,7 @@ SYNOPSIS
\ **rsetboot**\ \ *noderange*\ [\ **hd | net | cd | default | stat**\ ] [\ **-u**\ ] [\ **-p**\ ]
\ **rsetboot**\ [\ **-h | -**\ **-help | -v | -**\ **-version**\ ]
\ **rsetboot**\ [\ **-h | -**\ **-help | -v | -**\ **-version | -V | -**\ **-verbose**\ ]
***********
@@ -62,7 +62,7 @@ OPTIONS
\ **-u**\
To specify the next boot mode to be "UEFI Mode".
To specify the next boot mode to be "UEFI Mode". (Not supported for OpenBMC)
@@ -19,7 +19,7 @@ SYNOPSIS
********
\ **rspconfig**\ [\ **-h | -**\ **-help | -v | -**\ **-version**\ ]
\ **rspconfig**\ [\ **-h | -**\ **-help | -v | -**\ **-version | -V | -**\ **-verbose**\ ]
BMC/MPA specific:
=================
@@ -47,10 +47,32 @@ OpenBMC specific:
=================
\ **rspconfig**\ \ *noderange*\ {\ **ipsrc | ip | netmask | gateway | hostname | vlan | sshcfg**\ }
\ **rspconfig**\ \ *noderange*\ {\ **ipsrc | ip | netmask | gateway | vlan**\ }
\ **rspconfig**\ \ *noderange*\ \ **admin_passwd**\ ={\ *currentpasswd,newpasswd*\ }
\ **rspconfig**\ \ *noderange*\ \ **autoreboot**\
\ **rspconfig**\ \ *noderange*\ \ **autoreboot={0|1}**\
\ **rspconfig**\ \ *noderange*\ \ **bootmode**\
\ **rspconfig**\ \ *noderange*\ \ **bootmode={safe|regular|setup}**\
\ **rspconfig**\ \ *noderange*\ \ **dump**\ [\ **-l | -**\ **-list**\ ] [\ **-g | -**\ **-generate**\ ] [\ **-c | -**\ **-clear**\ {\ *id*\ | \ **all**\ }] [\ **-d | -**\ **-download**\ {\ *id*\ | \ **all**\ }]
\ **rspconfig**\ \ *noderange*\ \ **gard -c|-**\ **-clear**\
\ **rspconfig**\ \ *noderange*\ \ **ip=dhcp**\
\ **rspconfig**\ \ *noderange*\ \ **hostname**\
\ **rspconfig**\ \ *noderange*\ \ **hostname**\ ={\* | \ *name*\ }
\ **rspconfig**\ \ *noderange*\ \ **ntpservers**\
\ **rspconfig**\ \ *noderange*\ \ **ntpservers**\ ={\ *ntpservers*\ }
\ **rspconfig**\ \ *noderange*\ \ **powerrestorepolicy**\
\ **rspconfig**\ \ *noderange*\ \ **powerrestorepolicy={always_on|restore|always_off}**\
@@ -59,13 +81,11 @@ OpenBMC specific:
\ **rspconfig**\ \ *noderange*\ \ **powersupplyredundancy={disabled|enabled}**\
\ **rspconfig**\ \ *noderange*\ \ **autoreboot**\
\ **rspconfig**\ \ *noderange*\ \ **sshcfg**\
\ **rspconfig**\ \ *noderange*\ \ **autoreboot={0|1}**\
\ **rspconfig**\ \ *noderange*\ \ **timesyncmethod**\
\ **rspconfig**\ \ *noderange*\ \ **bootmode**\
\ **rspconfig**\ \ *noderange*\ \ **bootmode={safe|regular|setup}**\
\ **rspconfig**\ \ *noderange*\ \ **timesyncmethod={manual|ntp}**\
MPA specific:
@@ -131,9 +151,9 @@ FSP/CEC specific:
\ **rspconfig**\ \ *noderange*\ \ **admin_passwd**\ ={\ *currentpasswd,newpasswd*\ }
\ **rspconfig**\ \ *noderange*\ \ **general_passwd**\ ={\ **currentpasswd,newpasswd**\ }
\ **rspconfig**\ \ *noderange*\ \ **general_passwd**\ ={\ *currentpasswd,newpasswd*\ }
\ **rspconfig**\ \ *noderange*\ \*\ **_passwd**\ ={\ **currentpasswd,newpasswd**\ }
\ **rspconfig**\ \ *noderange*\ \*\ **_passwd**\ ={\ *currentpasswd,newpasswd*\ }
\ **rspconfig**\ \ *noderange*\ {\ *hostname*\ }
@@ -194,9 +214,9 @@ FSP/CEC (using Direct FSP Management) Specific:
\ **rspconfig**\ \ *noderange*\ \ **admin_passwd**\ ={\ *currentpasswd,newpasswd*\ }
\ **rspconfig**\ \ *noderange*\ \ **general_passwd**\ ={\ **currentpasswd,newpasswd**\ }
\ **rspconfig**\ \ *noderange*\ \ **general_passwd**\ ={\ *currentpasswd,newpasswd*\ }
\ **rspconfig**\ \ *noderange*\ \*\ **_passwd**\ ={\ **currentpasswd,newpasswd**\ }
\ **rspconfig**\ \ *noderange*\ \*\ **_passwd**\ ={\ *currentpasswd,newpasswd*\ }
\ **rspconfig**\ \ *noderange*\ {\ **sysname**\ }
@@ -233,9 +253,9 @@ BPA/Frame (using Direct FSP Management) Specific:
\ **rspconfig**\ \ *noderange*\ \ **admin_passwd**\ ={\ *currentpasswd,newpasswd*\ }
\ **rspconfig**\ \ *noderange*\ \ **general_passwd**\ ={\ **currentpasswd,newpasswd**\ }
\ **rspconfig**\ \ *noderange*\ \ **general_passwd**\ ={\ *currentpasswd,newpasswd*\ }
\ **rspconfig**\ \ *noderange*\ \*\ **_passwd**\ ={\ **currentpasswd,newpasswd**\ }
\ **rspconfig**\ \ *noderange*\ \*\ **_passwd**\ ={\ *currentpasswd,newpasswd*\ }
\ **rspconfig**\ \ *noderange*\ {\ **frame**\ }
@@ -358,6 +378,12 @@ OPTIONS
\ **gard -c|-**\ **-clear**\
Clear gard file. [OpenBMC]
\ **garp**\ =\ *time*\
Get or set Gratuitous ARP generation interval. The unit is number of 1/2 second.
@@ -450,31 +476,31 @@ OPTIONS
\ **powerrestorepolicy**\
Display or control BMC Power Restore Policy attribute setting.
Display or control BMC Power Restore Policy attribute setting. [OpenBMC]
\ **powersupplyredundancy**\
Display or control BMC Power Supply Redundancy attribute setting.
Display or control BMC Power Supply Redundancy attribute setting. [OpenBMC]
\ **autoreboot**\
Display or control BMC Auto Reboot attribute setting.
Display or control BMC Auto Reboot attribute setting. [OpenBMC]
\ **bootmode**\
Display or control BMC Boot Mode attribute setting.
Display or control BMC Boot Mode attribute setting. [OpenBMC]
\ **dump**\
Manage OpenBMC system dumps. If no sub-option is provided, will generate, wait, and download the dump.
Generate/Manage BMC system dumps. If no sub-option is provided, will generate, wait, and download the dump. [OpenBMC]
\ **-c**\ will clear a single specified dump, or use 'all' to clear all dumps on the BMC.
@@ -495,6 +521,12 @@ OPTIONS
\ **timesyncmethod**\
Set the method for time synchronization on the BMC. [OpenBMC]
\ **network**\ ={[\ *ip*\ ],[\ *host*\ ],[\ *gateway*\ ],[\ *netmask*\ ]|\*}
For MPA: get or set the MPA network parameters. If '\*' is specified, all parameters are read from the xCAT database.
@@ -542,6 +574,12 @@ OPTIONS
\ **ntpservers**\
Get or set NTP servers name. [OpenBMC]
\ **pd1**\ ={\ **nonred | redwoperf | redwperf**\ }
Power Domain 1 - determines how an MPA responds to a loss of redundant power.
@@ -19,7 +19,7 @@ SYNOPSIS
********
\ **nodehm Attributes:**\ \ *node*\ , \ *power*\ , \ *mgt*\ , \ *cons*\ , \ *termserver*\ , \ *termport*\ , \ *conserver*\ , \ *serialport*\ , \ *serialspeed*\ , \ *serialflow*\ , \ *getmac*\ , \ *cmdmapping*\ , \ *consoleondemand*\ , \ *comments*\ , \ *disable*\
\ **nodehm Attributes:**\ \ *node*\ , \ *power*\ , \ *mgt*\ , \ *cons*\ , \ *termserver*\ , \ *termport*\ , \ *conserver*\ , \ *serialport*\ , \ *serialspeed*\ , \ *serialflow*\ , \ *getmac*\ , \ *cmdmapping*\ , \ *consoleondemand*\ , \ *consoleenabled*\ , \ *comments*\ , \ *disable*\
***********
@@ -114,6 +114,12 @@ nodehm Attributes:
\ **consoleenabled**\
A flag field to indicate whether the node is registered in the console server. If '1', console is enabled, if not set, console is not enabled.
\ **comments**\
Any user-written notes.
@@ -19,9 +19,9 @@ SYNOPSIS
********
\ **makegocons**\ [\ **-V|-**\ **-verbose**\ ] [\ **-d|-**\ **-delete**\ ] [\ *noderange*\ ]
\ **makegocons**\ [\ **-V|-**\ **-verbose**\ ] [\ **-d|-**\ **-delete**\ ] [\ **-q|-**\ **-query**\ ] [\ *noderange*\ ]
\ **makeconservercf**\ [\ **-h|-**\ **-help|-v|-**\ **-version**\ ]
\ **makegocons**\ [\ **-V|-**\ **-verbose**\ ] [\ **-C|-**\ **-cleanup**\ ]
***********
@@ -46,17 +46,18 @@ In the case of a hierarchical cluster (i.e. one with service nodes) \ **makegoco
which nodes will have their consoles accessed from the management node and which from a service node
(based on the nodehm.conserver attribute).
To start goconserver on the specified service node, setup goconserver package on that service node, then set
the \ **console**\ column of \ **servicenode**\ table to \ **2**\ .
To support diskless service node, a new column \ **consoleenabled**\ has been added in \ **nodehm**\ table, it is used by \ **makegocons**\
command to save the current console state for the node. After reinstalling the service node, the console storage file which maintain
the console nodes for goconserver is lost, xCAT would register the console nodes into goconserver based on \ **consoleenabled**\ attribute
when restarting xcatd service.
For openbmc which uses ssh as the terminal session connection method, goconserver can help save the system
resources as goconserver could handle the ssh connection within goroutine which is more light-weighted than the command process.
\ **Note:**\ goconserver is an experimental feature, it will not be installed with xcat and will only support the systemd based systems.
Download and setup the rpm or deb package manually. Release link:
.. code-block:: perl
https://github.com/chenglch/goconserver/releases
\ **Note:**\ goconserver only support the systemd based systems. It has been integrated with xCAT as a recommended package.
*******
@@ -71,6 +72,18 @@ OPTIONS
\ **-C|-**\ **-cleanup**\
Remove the entries for the nodes whose definitions have been removed from xCAT db.
\ **-q|-**\ **-query**\
List the console connection of the nodes. If noderange is not specified, all of the console nodes will be displayed.
\ **-v|-**\ **-version**\
Display version.
@@ -141,6 +154,16 @@ EXAMPLES
4. To list console connection for node01.
.. code-block:: perl
makegocons -q node01
********
SEE ALSO
-38
View File
@@ -1,38 +0,0 @@
#!/bin/bash
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
function makepythonrpm {
RPMNAME="$1"
SPEC_FILE="$RPMNAME.spec"
tar --exclude .svn -czvf $RPMROOT/SOURCES/$RPMNAME-${VER}.tar.gz $RPMNAME
rm -f $RPMROOT/SRPMS/$RPMNAME-$VER*rpm $RPMROOT/RPMS/noarch/$RPMNAME-$VER*rpm
echo "Building $RPMROOT/RPMS/noarch/$RPMNAME-$VER-snap*.noarch.rpm $EMBEDTXT..."
rpmbuild --quiet -ta $RPMROOT/SOURCES/$RPMNAME-${VER}.tar.gz --define "version $VER" $REL "$EASE"
if [ $? -eq 0 ]; then
exit 0
else
exit 1
fi
}
# Main code....
OSNAME=$(uname)
VER=`cat Version`
REL="--define"
EASE='usedate 1'
RPMROOT=/root/rpmbuild
mkdir -p $RPMROOT/SOURCES
rpmbuild --version > /dev/null
if [ $? -gt 0 ]; then
echo "Error: rpmbuild does not appear to be installed or working."
exit 2
fi
if [ -n "$1" -a "$1" = "xCAT-openbmc-py" ]; then
makepythonrpm $1
else
echo 'Usage: makepythonrpm xCAT-openbmc-py'
exit 1
fi
+3 -6
View File
@@ -1676,13 +1676,10 @@ sub readFileInput
# could have different default stanzas for different object types
if ($objectname =~ /default/) {
if ($objectname =~ /^default-([^-]+)$/) {
($junk1, $objtype) = split(/-/, $objectname);
if ($objtype) {
$objectname = 'default';
}
$objtype = $1;
$objectname = 'default';
next;
}
+9 -4
View File
@@ -541,7 +541,7 @@ sub sendnodeskeys
# command to make the temp directory on the node
my $spawnmkdir =
"$remoteshell $node -l $to_userid /bin/mkdir -p /tmp/$to_userid/.ssh";
"$remoteshell -o GlobalKnownHostsFile=/dev/null -o UserKnownHostsFile=/dev/null $node -l $to_userid /bin/mkdir -p /tmp/$to_userid/.ssh";
# command to copy the needed files to the node
@@ -588,6 +588,11 @@ sub sendnodeskeys
##########################################
# Expect error - report
##########################################
if($rc==1){
my $rsp = {};
$rsp->{error}->[0] = "Permission denied, please make sure the user $to_userid has been created on the node $node and the input password is right\n";
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
}
if (defined($result[1]))
{
my $msg = $result[1];
@@ -629,11 +634,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/id_rsa.pub $home/.ssh/copy.sh $home/.ssh/tmp/authorized_keys $to_userid\@$node:/tmp/$to_userid/.ssh";
"$remotecopy -o GlobalKnownHostsFile=/dev/null -o UserKnownHostsFile=/dev/null $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/id_rsa.pub $home/.ssh/copy.sh $home/.ssh/tmp/authorized_keys $to_userid\@$node:/tmp/$to_userid/.ssh";
"$remotecopy -o GlobalKnownHostsFile=/dev/null -o UserKnownHostsFile=/dev/null $home/.ssh/id_rsa.pub $home/.ssh/copy.sh $home/.ssh/tmp/authorized_keys $to_userid\@$node:/tmp/$to_userid/.ssh";
}
# send copy command
@@ -715,7 +720,7 @@ sub sendnodeskeys
# command to run copy.sh
my $spawnruncopy =
"$remoteshell $node -l $to_userid /tmp/$to_userid/.ssh/copy.sh $to_userid";
"$remoteshell -o GlobalKnownHostsFile=/dev/null -o UserKnownHostsFile=/dev/null $node -l $to_userid /tmp/$to_userid/.ssh/copy.sh $to_userid";
# send mkdir command
unless ($sendkeys->spawn($spawnruncopy))
+7 -17
View File
@@ -594,7 +594,7 @@ passed as argument rather than by table value',
},
},
nodehm => {
cols => [qw(node power mgt cons termserver termport conserver serialport serialspeed serialflow getmac cmdmapping consoleondemand comments disable)],
cols => [qw(node power mgt cons termserver termport conserver serialport serialspeed serialflow getmac cmdmapping consoleondemand consoleenabled comments disable)],
keys => [qw(node)],
tablespace => 'XCATTBS16K',
table_desc => "Settings that control how each node's hardware is managed. Typically, an additional table that is specific to the hardware type of the node contains additional info. E.g. the ipmi, mp, and ppc tables.",
@@ -612,6 +612,7 @@ passed as argument rather than by table value',
getmac => 'The method to use to get MAC address of the node with the getmac command. If not set, the mgt attribute will be used. Valid values: same as values for mgmt attribute.',
cmdmapping => 'The fully qualified name of the file that stores the mapping between PCM hardware management commands and xCAT/third-party hardware management commands for a particular type of hardware device. Only used by PCM.',
consoleondemand => "This overrides the value from site.consoleondemand. Set to 'yes', 'no', '1' (equivalent to 'yes'), or '0' (equivalent to 'no'). If not set, the default is the value from site.consoleondemand.",
consoleenabled => "A flag field to indicate whether the node is registered in the console server. If '1', console is enabled, if not set, console is not enabled.",
comments => 'Any user-written notes.',
disable => "Set to 'yes' or '1' to comment out this row.",
},
@@ -2184,6 +2185,10 @@ my @nodeattrs = (
tabentry => 'nodehm.consoleondemand',
access_tabentry => 'nodehm.node=attr:node',
},
{ attr_name => 'consoleenabled',
tabentry => 'nodehm.consoleenabled',
access_tabentry => 'nodehm.node=attr:node',
},
##################
# vpd table #
##################
@@ -4245,22 +4250,7 @@ push(@{ $defspec{group}->{'attrs'} }, @nodeattrs);
tabentry => 'pdu.outlet',
access_tabentry => 'pdu.node=attr:node',
},
{ attr_name => 'machinetype',
only_if => 'nodetype=pdu',
tabentry => 'pdu.machinetype',
access_tabentry => 'pdu.node=attr:node',
},
{ attr_name => 'modelnum',
only_if => 'nodetype=pdu',
tabentry => 'pdu.modelnum',
access_tabentry => 'pdu.node=attr:node',
},
{ attr_name => 'serialnum',
only_if => 'nodetype=pdu',
tabentry => 'pdu.serialnum',
access_tabentry => 'pdu.node=attr:node',
},
);
);
+28 -3
View File
@@ -186,6 +186,8 @@ sub bldnonrootSSHFiles
if (xCAT::Utils->isMN()) { # if on Management Node
if (!(-e "$home/.ssh/id_rsa.pub"))
{
$rsp->{data}->[0] = "$home/.ssh/id_rsa.pub does not exist!";
xCAT::MsgUtils->message("I", $rsp, $::CALLBACK);
return 1;
}
}
@@ -208,6 +210,11 @@ sub bldnonrootSSHFiles
if (xCAT::Utils->isMN()) { # if on Management Node
$cmd = " cp $home/.ssh/id_rsa.pub $home/.ssh/tmp/authorized_keys";
} else { # SN
if(!(-e "$home/.ssh/authorized_keys")){
$rsp->{data}->[0] = "$home/.ssh/authorized_keys does not exist, make sure you have setup the ssh-keys on this service node.\n";
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
return (1);
}
$cmd = " cp $home/.ssh/authorized_keys $home/.ssh/tmp/authorized_keys";
}
xCAT::Utils->runcmd($cmd, 0);
@@ -344,6 +351,11 @@ sub setupSSH
# Get the home directory
my $home = xCAT::Utils->getHomeDir($from_userid);
unless($home){
$rsp->{data}->[0] = "Cannot get the home directory for user \"$from_userid\", please make sure \"$from_userid\" user exists!";
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
return 1;
}
$ENV{'DSH_FROM_USERID_HOME'} = $home;
if ($from_userid eq "root")
{
@@ -356,6 +368,10 @@ sub setupSSH
# 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
if($::VERBOSE){
$rsp->{data}->[0] = "Generating SSH keys for $from_userid.\n";
xCAT::MsgUtils->message("I", $rsp, $::CALLBACK);
}
my $rc =
xCAT::RemoteShellExp->remoteshellexp("k", $::CALLBACK, $::REMOTE_SHELL, $n_str, $expecttimeout);
if ($rc != 0) {
@@ -363,11 +379,20 @@ sub setupSSH
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
}
}
# build the shell copy script, needed Perl not always there
# for root and non-root ids
open(FILE, ">$home/.ssh/copy.sh")
or die "cannot open file $home/.ssh/copy.sh\n";
if($::VERBOSE){
$rsp->{data}->[0] = "Creating helper script \"$home/.ssh/copy.sh\" to install the ssh key files, which will be sent and invoked to target node then.\n";
xCAT::MsgUtils->message("I", $rsp, $::CALLBACK);
}
unless(open(FILE, ">$home/.ssh/copy.sh"))
{
$rsp->{data}->[0] ="cannot create file $home/.ssh/copy.sh, please make sure the directory \"$home/.ssh\" exists and ssh keys have been setup on this node!\n";
xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
return 1;
}
print FILE "#!/bin/sh
umask 0077
home=`egrep \"^$to_userid:\" /etc/passwd | cut -f6 -d :`
+147 -57
View File
@@ -22,88 +22,124 @@ my %usage = (
rnetboot [-h|--help|-v|--version]
zVM specific:
rnetboot <noderange> [ipl= address]",
"rpower" =>
"Usage: rpower <noderange> [--nodeps] [on|onstandby|off|suspend|reset|stat|state|boot] [-V|--verbose] [-m table.colum==expectedstatus][-m table.colum==expectedstatus...] [-r <retrycount>] [-t <timeout>]
"rpower" => "",
"rpower.common" =>
"Usage:
Common:
rpower <noderange> [--nodeps] [on|onstandby|off|suspend|reset|stat|state|boot] [-V|--verbose] [-m table.colum==expectedstatus][-m table.colum==expectedstatus...] [-r <retrycount>] [-t <timeout>]
rpower [-h|--help|-v|--version]
BMC (using IPMI):
rpower noderange [on|off|softoff|reset|boot|stat|state|status|wake|suspend [-w timeout] [-o] [-r]]
",
"rpower.begin" =>
"BMC (using IPMI):
rpower noderange [on|off|softoff|reset|boot|cycle|stat|state|status|wake|suspend [-w timeout] [-o] [-r]]
rpower noderange [pduon|pduoff|pdustat]
OpenPOWER BMC:
OpenPOWER BMC:
rpower noderange [on|off|reset|boot|stat|state|status]
rpower noderange [pduon|pduoff|pdustat]
OpenPOWER OpenBMC:
",
"rpower.openbmc" =>
"OpenPOWER OpenBMC:
rpower noderange [on|off|softoff|reset|boot|bmcreboot|bmcstate|stat|state|status]
KVM Virtualization specific:
",
"rpower.end" =>
"KVM Virtualization specific:
rpower <noderange> [boot] [ -c <path to iso> ]
PPC (with IVM or HMC) specific:
PPC (with IVM or HMC) specific:
rpower <noderange> [--nodeps] [of] [-V|--verbose]
CEC (with HMC) specific:
CEC (with HMC) specific:
rpower <noderange> [on|off|reset|boot|onstandby]
LPAR(with HMC) specific:
LPAR(with HMC) specific:
rpower <noderange> [on|off|reset|stat|state|boot|of|sms|softoff]
CEC(using Direct FSP Management) specific:
CEC(using Direct FSP Management) specific:
rpower <noderange> [on|onstandby|off|stat|state|resetsp]
Frame(using Direct FSP Management) specific:
Frame(using Direct FSP Management) specific:
rpower <noderange> [stat|state|rackstandby|exit_rackstandby|resetsp]
LPAR(using Direct FSP Management) specific:
LPAR(using Direct FSP Management) specific:
rpower <noderange> [on|off|reset|stat|state|boot|of|sms]
Blade(using Direct FSP Management) specific:
Blade(using Direct FSP Management) specific:
rpower <noderange> [on|onstandby|off|cycle|state|sms]
Blade(using AMM) specific:
Blade(using AMM) specific:
rpower <noderange> [cycle|softoff] [-V|--verbose]
Lenovo high-density server specific:
rpower <noderange> [on|off|reset|boot|reseat]
zVM specific:
zVM specific:
rpower noderange [on|off|reset|stat|softoff]
MIC specific:
MIC specific:
rpower noderange [stat|state|on|off|reset|boot]
docker specific:
docker specific:
rpower noderange [start|stop|restart|pause|unpause|state]
pdu specific:
pdu specific:
rpower noderange [off|on|stat|status|reset]
rpower noderange [pduoff|pduon|pdustat|pdustatus|pdureset]
",
"rbeacon" =>
"Usage: rbeacon <noderange> [on|off|stat] [-V|--verbose]
rbeacon [-h|--help|-v|--version]",
"rvitals" =>
"rbeacon" =>"",
"rbeacon.common" =>
"Usage:
Common:
rbeacon [-h|--help|-v|--version|-V|--verbose]
",
"rbeacon.begin" =>
"BMC specific:
rbeacon [on|blink|off|stat]
OpenPOWER (IPMI) specific:
rbeacon [on|blink|off|stat]
",
"rbeacon.openbmc" =>
"OpenPOWER (OpenBMC) specific:
rbeacon [on|off]
",
"rvitals" => "",
"rvitals.common" =>
"Usage:
Common:
rvitals [-h|--help|-v|--version]
FSP/LPAR (with HMC) specific:
rvitals noderange {temp|voltage|lcds|all}
CEC/LPAR/Frame (using Direct FSP Management) specific:
rvitals noderange {rackenv|lcds|all}
MPA specific:
rvitals noderange {temp|voltage|wattage|fanspeed|power|leds|summary|all}
Blade specific:
rvitals noderange {temp|wattage|fanspeed|leds|summary|all}
BMC specific:
rvitals noderange {temp|voltage|wattage|fanspeed|power|leds|all}
OpenPOWER (IPMI) specific:
rvitals noderange [temp|voltage|wattage|fanspeed|power|leds|chassis|all]
OpenPOWER (OpenBMC) specific:
rvitals noderange [temp|voltage|wattage|fanspeed|power|leds|altitude|all]
MIC specific:
rvitals noderange {thermal|all}
pdu specific:
rvitals noderange ",
Common:
rvitals [-h|--help|-v|--version]
",
"rvitals.begin" =>
"FSP/LPAR (with HMC) specific:
rvitals noderange {temp|voltage|lcds|all}
CEC/LPAR/Frame (using Direct FSP Management) specific:
rvitals noderange {rackenv|lcds|all}
MPA specific:
rvitals noderange {temp|voltage|wattage|fanspeed|power|leds|summary|all}
Blade specific:
rvitals noderange {temp|wattage|fanspeed|leds|summary|all}
BMC specific:
rvitals noderange {temp|voltage|wattage|fanspeed|power|leds|all}
OpenPOWER (IPMI) specific:
rvitals noderange [temp|voltage|wattage|fanspeed|power|leds|chassis|all]
",
"rvitals.openbmc" =>
"OpenPOWER (OpenBMC) specific:
rvitals noderange [temp|voltage|wattage|fanspeed|power|leds|altitude|all]
",
"rvitals.end" =>
"MIC specific:
rvitals noderange {thermal|all}
pdu specific:
rvitals noderange ",
"reventlog" =>
"Usage: reventlog <noderange> [all [-s]|clear|<number of entries to retrieve> [-s]] [-V|--verbose]
reventlog <noderange> [resolved={<id list>|LED}]
reventlog [-h|--help|-v|--version]",
"rinv" =>
"rinv" => "",
"rinv.common" =>
"Usage:
Common:
rinv <noderange> [all|model|serial] [-V|--verbose]
rinv [-h|--help|-v|--version]
BMC/MPA specific:
",
"rinv.begin" =>
"BMC/MPA specific:
rinv <noderange> [model|serial|asset|vpd|deviceid|guid|firm|dimm|mprom|all]
OpenPOWER (IPMI) server specific:
rinv <noderange> [model|serial|deviceid|uuid|guid|vpd|mprom|firm|all]
OpenPOWER (OpenBMC) server specific:
",
"rinv.openbmc" =>
"OpenPOWER (OpenBMC) server specific:
rinv <noderange> [model|serial|firm|cpu|dimm|all] [-V|--verbose]
PPC specific(with HMC):
",
"rinv.end" =>
"PPC specific(with HMC):
rinv <noderange> [all|bus|config|serial|model|firm]
PPC specific(using Direct FSP Management):
rinv <noderange> [firm]
@@ -142,8 +178,13 @@ my %usage = (
",
"rspconfig.openbmc" =>
"OpenBMC specific:
rspconfig <noderange> [ipsrc|ip|netmask|gateway|hostname|vlan]
rspconfig <noderange> [ipsrc|ip|netmask|gateway|vlan]
rspconfig <noderange> admin_passwd=<currentpasswd,newpasswd>
rspconfig <noderange> dump [-l|--list] [-g|--generate] [-c|--clear {<id>|all}] [-d|--download {<id>|all}]
rspconfig <noderange> gard -c|--clear
rspconfig <noderange> [hostname|ntpservers]
rspconfig <noderange> [hostname=<*|hostname>|ntpservers=<ntpservers>]
rspconfig <noderange> sshcfg
",
"rspconfig.begin" =>
"BMC/MPA Common:
@@ -349,20 +390,26 @@ my %usage = (
"makentp" =>
"Usage: makentp [-h|--help|-v|--version]
makentp [-a|--all] [-V|--verbose]",
"rflash" =>
"Usage:
rflash [ -h|--help|-v|--version]
PPC (with HMC) specific:
rflash <noderange> -p <rpm_directory> [--activate {concurrent | disruptive}] [-V|--verbose]
rflash <noderange> {--commit | --recover} [-V|--verbose]
"rflash" => "",
"rflash.common" =>
"Usage:
Common:
rflash [ -h|--help|-v|--version|-V|--verbose]
",
"rflash.begin" =>
"PPC (with HMC) specific:
rflash <noderange> -p <rpm_directory> [--activate {concurrent | disruptive}]
rflash <noderange> {--commit | --recover}
PPC (using Direct FSP Management) specific:
rflash <noderange> -p <rpm_directory> [--activate {disruptive|deferred}] [-d <data_directory>]
rflash <noderange> [--commit | --recover] [-V|--verbose]
rflash <noderange> [--commit | --recover]
rflash <noderange> [--bpa_acdl]
OpenPOWER BMC specific (using IPMI):
rflash <noderange> [<hpm_file_path>|-d <data_directory>] [-c|--check] [--retry=<count>] [-V]
rflash <noderange> [<hpm_file_path>|-d <data_directory>] [-c|--check] [--retry=<count>]
rflash <noderange> --recover <bmc_file_path>
OpenPOWER OpenBMC specific:
",
"rflash.openbmc" =>
"OpenPOWER OpenBMC specific:
rflash <noderange> {[-c|--check] | [-l|--list]}
rflash <noderange> <tar_file_path> {[-c|--check] | [-a|--activate] | [-u|--upload]}
rflash <noderange> <tar_file_diretory> [-d] [--no-host-reboot]
@@ -556,6 +603,49 @@ $usage{"rspconfig"} = $usage{"rspconfig.common"} .
$usage{"rspconfig.openbmc"} = $usage{"rspconfig.common"} .
$usage{"rspconfig.openbmc"};
$usage{"rinv"} = $usage{"rinv.common"} .
$usage{"rinv.begin"} .
$usage{"rinv.openbmc"} .
" " .
$usage{"rinv.end"};
$usage{"rinv.openbmc"} = $usage{"rinv.common"} .
$usage{"rinv.openbmc"};
$usage{"rbeacon"} = $usage{"rbeacon.common"} .
$usage{"rbeacon.begin"} .
$usage{"rbeacon.openbmc"};
$usage{"rbeacon.openbmc"} = $usage{"rbeacon.common"} .
$usage{"rbeacon.openbmc"};
$usage{"rvitals"} = $usage{"rvitals.common"} .
$usage{"rvitals.begin"} .
$usage{"rvitals.openbmc"} .
" " .
$usage{"rvitals.end"};
$usage{"rvitals.openbmc"} = $usage{"rvitals.common"} .
$usage{"rvitals.openbmc"};
$usage{"rflash"} = $usage{"rflash.common"} .
$usage{"rflash.begin"} .
$usage{"rflash.openbmc"} .
" " .
$usage{"rflash.end"};
$usage{"rflash.openbmc"} = $usage{"rflash.common"} .
$usage{"rflash.openbmc"};
$usage{"rpower"} = $usage{"rpower.common"} .
$usage{"rpower.begin"} .
$usage{"rpower.openbmc"} .
" " .
$usage{"rpower.end"};
$usage{"rpower.openbmc"} = $usage{"rpower.common"} .
$usage{"rpower.openbmc"};
my $vers = xCAT::Utils->Version();
my %version = (
"rnetboot" => "$vers",
+19
View File
@@ -4949,4 +4949,23 @@ sub natural_sort_cmp($$) {
}
}
#--------------------------------------------------------------------------------
=head3 console_sleep
A wrap for sleep subroutine, if goconserver is used, just exit immidiately
as goconserver has its own sleep mechanism.
=cut
#--------------------------------------------------------------------------------
sub console_sleep {
my $time = shift;
my $message = shift;
if($ENV{CONSOLE_TYPE} && $ENV{CONSOLE_TYPE} eq "gocons") {
# sleep time is handled by goconserver itself
exit(1);
}
print $message if $message;
sleep($time);
}
1;
+10
View File
@@ -101,6 +101,8 @@ sub check_pr_format{
my $pr_content = decode_json($pr_url_resp);
my $pr_title = $pr_content->{title};
my $pr_body = $pr_content->{body};
my $pr_milestone = $pr_content->{milestone};
my $pr_labels_len = @{$pr_content->{labels}};
#print "[check_pr_format] Dumper pr_content:\n";
#print Dumper $pr_content;
@@ -115,6 +117,14 @@ sub check_pr_format{
$checkrst.="Miss description.";
}
if(! $pr_milestone){
$checkrst.="Miss milestone.";
}
if(! $pr_labels_len){
$checkrst.="Miss labels.";
}
if(length($checkrst) == 0){
$check_result_str .= "> **PR FORMAT CORRECT**";
send_back_comment("$check_result_str");
+10 -2
View File
@@ -5,11 +5,19 @@ B<rbeacon> - Turns beacon on/off/blink or gives status of a node or noderange.
=head1 SYNOPSIS
B<rbeacon> [B<-h>|B<--help>|B<-v>|B<--version>|B<-V>|B<--verbose>]
=head2 BMC (using IPMI):
B<rbeacon> I<noderange> {B<on>|B<blink>|B<off>|B<stat>}
B<rbeacon> [B<-h>|B<--help>]
=head2 OpenPOWER BMC (using IPMI):
B<rbeacon> {B<-v>|B<--version>}
B<rbeacon> I<noderange> {B<on>|B<blink>|B<off>|B<stat>}
=head2 OpenPOWER OpenBMC:
B<rbeacon> I<noderange> {B<on>|B<off>}
=head1 DESCRIPTION
+4 -4
View File
@@ -4,13 +4,13 @@ B<rflash> - Performs Licensed Internal Code (LIC) update or firmware update on s
=head1 B<Synopsis>
B<rflash> [B<-h>|B<--help> | B<-v>|B<--version>]
B<rflash> [B<-h>|B<--help> | B<-v>|B<--version> | B<-V>|B<--verbose>]
=head2 PPC (with HMC) specific:
B<rflash> I<noderange> B<-p> I<directory> [B<--activate> {B<concurrent>|B<disruptive>}] [B<-V>|B<--verbose>]
B<rflash> I<noderange> B<-p> I<directory> [B<--activate> {B<concurrent>|B<disruptive>}]
B<rflash> I<noderange> {B<--commit>|B<--recover>} [B<-V>|B<--verbose>]
B<rflash> I<noderange> {B<--commit>|B<--recover>}
=head2 PPC (without HMC, using Direct FSP Management) specific:
@@ -24,7 +24,7 @@ B<rflash> I<noderange> I<http_directory>
=head2 OpenPOWER BMC specific (using IPMI):
B<rflash> I<noderange> [I<hpm_file_path> | B<-d> I<data_directory>] [B<-c>|B<--check>] [B<--retry=>I<count>] [B<-V>]
B<rflash> I<noderange> [I<hpm_file_path> | B<-d> I<data_directory>] [B<-c>|B<--check>] [B<--retry=>I<count>]
B<rflash> I<noderange> B<--recover> I<bmc_file_path>
+1 -1
View File
@@ -58,7 +58,7 @@ A set of comma delimited object types.
=item B<-C|--cleanup>
Perform additional cleanup by running B<nodeset offline> and B<makeconservercf -d> on the objects specified in the I<noderange>.
Perform additional cleanup by running B<nodeset offline>, B<makeconservercf -d> and B<makegocons --cleanup> on the objects specified in the I<noderange>.
=item B<-V|--verbose>
+1 -1
View File
@@ -10,7 +10,7 @@ B<rpower> [B<-h>|B<--help>|B<-v>|B<--version>]
=head2 BMC (using IPMI):
B<rpower> I<noderange> [B<on>|B<off>|B<softoff>|B<reset>|B<boot>|B<stat>|B<state>|B<status>|B<wake>|B<suspend> [B<-w> I<timeout>] [B<-o>] [B<-r>]]
B<rpower> I<noderange> [B<on>|B<off>|B<softoff>|B<reset>|B<boot>|B<cycle>|B<stat>|B<state>|B<status>|B<wake>|B<suspend> [B<-w> I<timeout>] [B<-o>] [B<-r>]]
B<rpower> I<noderange> [B<pduon>|B<pduoff>|B<pdustat>|B<pdureset>]
+2 -2
View File
@@ -7,7 +7,7 @@ B<rsetboot> - Sets the boot device to be used for BMC-based servers for the next
B<rsetboot> I<noderange> [B<hd>|B<net>|B<cd>|B<default>|B<stat>] [B<-u>] [B<-p>]
B<rsetboot> [B<-h>|B<--help>|B<-v>|B<--version>]
B<rsetboot> [B<-h>|B<--help>|B<-v>|B<--version>|B<-V>|B<--verbose>]
=head1 DESCRIPTION
@@ -40,7 +40,7 @@ Display the current boot setting.
=item B<-u>
To specify the next boot mode to be "UEFI Mode".
To specify the next boot mode to be "UEFI Mode". (Not supported for OpenBMC)
=item B<-p>
+50 -18
View File
@@ -4,7 +4,7 @@ B<rspconfig> - Configures nodes' service processors
=head1 SYNOPSIS
B<rspconfig> [B<-h>|B<--help>|B<-v>|B<--version>]
B<rspconfig> [B<-h>|B<--help>|B<-v>|B<--version>|B<-V>|B<--verbose>]
=head2 BMC/MPA specific:
@@ -24,10 +24,32 @@ B<rspconfig> I<noderange> B<garp>=I<time>
=head2 OpenBMC specific:
B<rspconfig> I<noderange> {B<ipsrc>|B<ip>|B<netmask>|B<gateway>|B<hostname>|B<vlan>|B<sshcfg>}
B<rspconfig> I<noderange> {B<ipsrc>|B<ip>|B<netmask>|B<gateway>|B<vlan>}
B<rspconfig> I<noderange> B<admin_passwd>={I<currentpasswd,newpasswd>}
B<rspconfig> I<noderange> B<autoreboot>
B<rspconfig> I<noderange> B<autoreboot={0|1}>
B<rspconfig> I<noderange> B<bootmode>
B<rspconfig> I<noderange> B<bootmode={safe|regular|setup}>
B<rspconfig> I<noderange> B<dump> [B<-l>|B<--list>] [B<-g>|B<--generate>] [B<-c>|B<--clear> {I<id> | B<all>}] [B<-d>|B<--download> {I<id> | B<all>}]
B<rspconfig> I<noderange> B<gard -c|--clear>
B<rspconfig> I<noderange> B<ip=dhcp>
B<rspconfig> I<noderange> B<hostname>
B<rspconfig> I<noderange> B<hostname>={* | I<name>}
B<rspconfig> I<noderange> B<ntpservers>
B<rspconfig> I<noderange> B<ntpservers>={I<ntpservers>}
B<rspconfig> I<noderange> B<powerrestorepolicy>
B<rspconfig> I<noderange> B<powerrestorepolicy={always_on|restore|always_off}>
@@ -36,13 +58,11 @@ B<rspconfig> I<noderange> B<powersupplyredundancy>
B<rspconfig> I<noderange> B<powersupplyredundancy={disabled|enabled}>
B<rspconfig> I<noderange> B<autoreboot>
B<rspconfig> I<noderange> B<sshcfg>
B<rspconfig> I<noderange> B<autoreboot={0|1}>
B<rspconfig> I<noderange> B<timesyncmethod>
B<rspconfig> I<noderange> B<bootmode>
B<rspconfig> I<noderange> B<bootmode={safe|regular|setup}>
B<rspconfig> I<noderange> B<timesyncmethod={manual|ntp}>
=head2 MPA specific:
@@ -102,9 +122,9 @@ B<rspconfig> I<noderange> B<HMC_passwd>={I<currentpasswd,newpasswd>}
B<rspconfig> I<noderange> B<admin_passwd>={I<currentpasswd,newpasswd>}
B<rspconfig> I<noderange> B<general_passwd>={B<currentpasswd,newpasswd>}
B<rspconfig> I<noderange> B<general_passwd>={I<currentpasswd,newpasswd>}
B<rspconfig> I<noderange> *B<_passwd>={B<currentpasswd,newpasswd>}
B<rspconfig> I<noderange> *B<_passwd>={I<currentpasswd,newpasswd>}
B<rspconfig> I<noderange> {I<hostname>}
@@ -157,9 +177,9 @@ B<rspconfig> I<noderange> B<HMC_passwd>={I<currentpasswd,newpasswd>}
B<rspconfig> I<noderange> B<admin_passwd>={I<currentpasswd,newpasswd>}
B<rspconfig> I<noderange> B<general_passwd>={B<currentpasswd,newpasswd>}
B<rspconfig> I<noderange> B<general_passwd>={I<currentpasswd,newpasswd>}
B<rspconfig> I<noderange> *B<_passwd>={B<currentpasswd,newpasswd>}
B<rspconfig> I<noderange> *B<_passwd>={I<currentpasswd,newpasswd>}
B<rspconfig> I<noderange> {B<sysname>}
@@ -193,9 +213,9 @@ B<rspconfig> I<noderange> B<HMC_passwd>={I<currentpasswd,newpasswd>}
B<rspconfig> I<noderange> B<admin_passwd>={I<currentpasswd,newpasswd>}
B<rspconfig> I<noderange> B<general_passwd>={B<currentpasswd,newpasswd>}
B<rspconfig> I<noderange> B<general_passwd>={I<currentpasswd,newpasswd>}
B<rspconfig> I<noderange> *B<_passwd>={B<currentpasswd,newpasswd>}
B<rspconfig> I<noderange> *B<_passwd>={I<currentpasswd,newpasswd>}
B<rspconfig> I<noderange> {B<frame>}
@@ -282,6 +302,10 @@ Change the passwords of the userids B<HMC>, B<admin> and B<general> for CEC/Fram
The NTP update frequency (in minutes).
=item B<gard -c|--clear>
Clear gard file. [OpenBMC]
=item B<garp>=I<time>
Get or set Gratuitous ARP generation interval. The unit is number of 1/2 second.
@@ -344,23 +368,23 @@ The subnet mask.
=item B<powerrestorepolicy>
Display or control BMC Power Restore Policy attribute setting.
Display or control BMC Power Restore Policy attribute setting. [OpenBMC]
=item B<powersupplyredundancy>
Display or control BMC Power Supply Redundancy attribute setting.
Display or control BMC Power Supply Redundancy attribute setting. [OpenBMC]
=item B<autoreboot>
Display or control BMC Auto Reboot attribute setting.
Display or control BMC Auto Reboot attribute setting. [OpenBMC]
=item B<bootmode>
Display or control BMC Boot Mode attribute setting.
Display or control BMC Boot Mode attribute setting. [OpenBMC]
=item B<dump>
Manage OpenBMC system dumps. If no sub-option is provided, will generate, wait, and download the dump.
Generate/Manage BMC system dumps. If no sub-option is provided, will generate, wait, and download the dump. [OpenBMC]
=over 4
@@ -378,6 +402,10 @@ B<-d> will download a single dump or all generated dumps from the BMC to /var/lo
=back
=item B<timesyncmethod>
Set the method for time synchronization on the BMC. [OpenBMC]
=item B<network>={[I<ip>],[I<host>],[I<gateway>],[I<netmask>]|*}
For MPA: get or set the MPA network parameters. If '*' is specified, all parameters are read from the xCAT database.
@@ -411,6 +439,10 @@ Enable or disable NTP (enable|disable).
Get or set NTP server IP address or name.
=item B<ntpservers>
Get or set NTP servers name. [OpenBMC]
=item B<pd1>={B<nonred>|B<redwoperf>|B<redwperf>}
Power Domain 1 - determines how an MPA responds to a loss of redundant power.
+24 -6
View File
@@ -4,10 +4,9 @@ B<makegocons> - Register or unregister the node in the goconserver service
=head1 SYNOPSIS
B<makegocons> [B<-V|--verbose>] [B<-d|--delete>] [I<noderange>]
B<makeconservercf> [B<-h|--help|-v|--version>]
B<makegocons> [B<-V|--verbose>] [B<-d|--delete>] [B<-q|--query>] [I<noderange>]
B<makegocons> [B<-V|--verbose>] [B<-C|--cleanup>]
=head1 DESCRIPTION
@@ -28,13 +27,19 @@ In the case of a hierarchical cluster (i.e. one with service nodes) B<makegocons
which nodes will have their consoles accessed from the management node and which from a service node
(based on the nodehm.conserver attribute).
To start goconserver on the specified service node, setup goconserver package on that service node, then set
the B<console> column of B<servicenode> table to B<2>.
To support diskless service node, a new column B<consoleenabled> has been added in B<nodehm> table, it is used by B<makegocons>
command to save the current console state for the node. After reinstalling the service node, the console storage file which maintain
the console nodes by goconserver is lost, xCAT would register the console nodes into goconserver based on B<consoleenabled> attribute
when restarting xcatd service.
For openbmc which uses ssh as the terminal session connection method, goconserver can help save the system
resources as goconserver could handle the ssh connection within goroutine which is more light-weighted than the command process.
B<Note:> goconserver is an experimental feature, it will not be installed with xcat and will only support the systemd based systems.
Download and setup the rpm or deb package manually. Release link:
B<Note:> goconserver only support the systemd based systems. It has been integrated with xCAT as a recommended package.
https://github.com/chenglch/goconserver/releases
=head1 OPTIONS
@@ -44,6 +49,14 @@ Download and setup the rpm or deb package manually. Release link:
Delete rather than add or refresh the nodes specified as a noderange.
=item B<-C|--cleanup>
Remove the entries for the nodes whose definitions have been removed from xCAT db.
=item B<-q|--query>
List the console connection of the nodes. If noderange is not specified, all of the console nodes will be displayed.
=item B<-v|--version>
Display version.
@@ -90,6 +103,11 @@ To remove goconserver configuration for node01.
makegocons -d node01
=item 4.
To list console connection for node01.
makegocons -q node01
=back
=head1 SEE ALSO
+8 -4
View File
@@ -130,10 +130,10 @@ if [ "$HOSTOS" = "mcp" ]; then
# # and some files are in different directories
elif [ $BUILDARCH = "ppc64" ]; then
if [ "$HOSTOS" = "Pegas1.0" ]; then
sed -i 's/ mkreiserfs//' $DRACUTMODDIR/install
sed -i 's/ reiserfstune//' $DRACUTMODDIR/install
sed -i 's/ vconfig//' $DRACUTMODDIR/install
sed -i 's/ ntp-wait//' $DRACUTMODDIR/install
sed -i 's/ mkreiserfs//' $DRACUTMODDIR/install
sed -i 's/ reiserfstune//' $DRACUTMODDIR/install
sed -i 's/ vconfig//' $DRACUTMODDIR/install
sed -i 's/ ntp-wait//' $DRACUTMODDIR/install
fi
sed -i 's/ efibootmgr//' $DRACUTMODDIR/install
sed -i 's/ dmidecode//' $DRACUTMODDIR/install
@@ -141,6 +141,10 @@ elif [ $BUILDARCH = "ppc64" ]; then
sed -i 's/\/lib\/terminfo\/v\/vt100/\/usr\/share\/terminfo\/v\/vt100/g' $DRACUTMODDIR/install
fi
libnss_pkgname=`find /usr/lib64/ -name libnss_dns-2*.so | xargs basename`
sed -i "s/\/lib64\/libnss_dns-2.12.so/\/usr\/lib64\/$libnss_pkgname/g" $DRACUTMODDIR/install
sed -i 's/\/lib64\/libnss_dns.so.2/\/usr\/lib64\/libnss_dns.so.2/' $DRACUTMODDIR/install
mkdir -p /tmp/xcatgenesis.$$/opt/xcat/share/xcat/netboot/genesis/$BUILDARCH/fs
# run dracut
+2
View File
@@ -7,6 +7,7 @@ dracut_install grep ip hostname /usr/bin/awk egrep grep dirname expr
dracut_install mount.nfs sshd vi reboot lspci parted screen mkfs mkfs.ext4 mkfs.xfs xfs_db #mkfs.btrfs removed
#dracut_install libvirtd /usr/share/libvirt/cpu_map.xml /usr/bin/qemu-img /usr/libexec/qemu-kvm
dracut_install mkswap df brctl vconfig ifenslave ssh-keygen scp clear dhclient lldpad
dracut_install /lib64/libnss_dns-2.12.so /lib64/libnss_dns.so.2
dracut_install poweroff ntpq ntpd ntp-wait hwclock date /usr/share/terminfo/x/xterm /usr/share/terminfo/s/screen /etc/nsswitch.conf /etc/services
dracut_install /sbin/rsyslogd /etc/protocols umount /bin/rpm /usr/lib/rpm/rpmrc
dracut_install chmod /sbin/route /sbin/ifconfig /usr/bin/whoami /usr/bin/head /usr/bin/tail basename /etc/redhat-release ping tr lsusb /usr/share/hwdata/usb.ids #ibm fw wrapper requirements
@@ -587,6 +588,7 @@ inst_dir /var/lib/nfs/statd/sm
inst_dir /var/lib/nfs/statd/sm.bak
inst_dir /var/lib/nfs/rpc_pipefs/nfs
inst "/bin/bash" "/bin/sh"
inst "/lib64/libnss_dns-2.12.so"
inst "/lib/terminfo/l/linux" "/lib/terminfo/l/linux"
inst "/lib/terminfo/v/vt100" "/lib/terminfo/v/vt100"
inst_hook cmdline 10 "$moddir/xcat-cmdline.sh"
@@ -4,7 +4,7 @@ Version: %{?version:%{version}}%{!?version:%(cat Version)}
Release: %{?release:%{release}}%{!?release:%(cat Release)}
Epoch: 1
AutoReq: false
Requires: ipmitool screen btrfs-progs lldpad rpm-build mstflint xfsprogs nc rpmdevtools libstdc++-devel pciutils bridge-utils ntp ntp-perl iprutils psmisc mdadm bind-utils dosfstools usbutils libusbx
Requires: ipmitool screen btrfs-progs lldpad rpm-build mstflint xfsprogs nc rpmdevtools libstdc++-devel pciutils bridge-utils ntp ntp-perl iprutils psmisc mdadm bind-utils dosfstools usbutils libusbx bc
Prefix: /opt/xcat
AutoProv: false
+4 -3
View File
@@ -95,7 +95,8 @@ if [ -r /sys/devices/virtual/dmi/id/product_name ]; then #x86
FRU=`ipmitool fru print 0`
if [ $? -eq 0 ]; then
MTM=`echo "$FRU" | awk -F': ' '/Product Manufacturer/ {m=$2} /Product Name|Product Part Number/ {if (n==""||n=="NONE") {n=$2}} END {print m":"n}'`
else
fi
if [ -z "$MTM" -o "$MTM" == ":" ]; then
logger -s -t $log_label -p local4.warning "Couldn't find MTM information in FRU, falling back to DMI (MTMS-based discovery may fail)"
m=`cat /sys/devices/virtual/dmi/id/sys_vendor`
n=`cat /sys/devices/virtual/dmi/id/product_name`
@@ -154,7 +155,7 @@ if [ "$flag_mtm" ] && [ "$MTM" != "unknown" ]; then
echo "<mtm>$MTM</mtm>" >> /tmp/discopacket
fi
flag_serial=`echo "$SERIAL" | sed 's/0//g'`
if [ $flag_serial ] && [ "$SERIAL" != "unknown" ]; then
if [ "$flag_serial" ] && [ "$SERIAL" != "unknown" ]; then
SERIAL=`echo $SERIAL | sed 's/\.//g'`
echo "<serial>$SERIAL</serial>" >> /tmp/discopacket
fi
@@ -162,7 +163,7 @@ if [ "$PLATFORM" != "unknown" ]; then
echo "<platform>$PLATFORM</platform>" >> /tmp/discopacket
fi
LANCHAN=$(ipmitool sol info |awk '/Payload Channel/{print $4}')
LANCHAN=$(ipmitool sol info 2>/dev/null|awk '/Payload Channel/{print $4}')
IsStatic=`ipmitool lan print $LANCHAN | grep 'IP Address Source' | grep 'Static'`
if [ "$IsStatic" ]; then
BMCIPADDR=`ipmitool lan print $LANCHAN | grep 'IP Address' | grep -v 'IP Address Source' | cut -d ":" -f2 | sed 's/ //'`
+1 -1
View File
@@ -247,7 +247,7 @@ else
gripeiter=101
logger -s -t $log_label -p local4.info "Acquiring network addresses.."
while ! ip -4 -o a show dev $bootnic|grep -v 'scope link'|grep -v 'dynamic'|grep -q inet; do
while ! ip -4 -o a show dev $bootnic|grep -v 'scope link'|grep -q inet; do
sleep 0.1
if [ $gripeiter = 1 ]; then
logger -s -t $log_label -p local4.info "It seems to be taking a while to acquire an IPv4 address, you may want to check spanning tree..."
@@ -11,12 +11,16 @@ BEGIN {
quit="yes"
system("echo \"" $0 "\" > /restart")
close(listener)
system("rm -rf /processing")
system("logger -s -t 'xcat.genesis.minixcatd' -p local4.info 'The request is processed by xCAT master successfully.'")
}else if(match($0,"processing")){
print "processing request" |& listener
system("echo \"" $0 "\" > /processing")
system("logger -s -t 'xcat.genesis.minixcatd' -p local4.info 'The request is processing by xCAT master...'")
}else if(match($0,"processed")){
print "finished request process" |& listener
system("rm -rf /processing")
system("logger -s -t 'xcat.genesis.minixcatd' -p local4.warning 'The request is already processed by xCAT master, but not matched.'")
}
}
close(listener)
+6
View File
@@ -0,0 +1,6 @@
xcat-openbmc-py (2.13.11-snap201802080225) UNRELEASED; urgency=medium
-- root <root@c910f03c05k10> Thu, 08 Feb 2018 02:25:50 -0500
+1
View File
@@ -0,0 +1 @@
9
+12
View File
@@ -0,0 +1,12 @@
Source: xcat-openbmc-py
Section: admin
Priority: extra
Maintainer: xCAT <xcat-user@lists.sourceforge.net>
Build-Depends: debhelper (>= 9)
Standards-Version: 3.9.4
Homepage: https://xcat.org/
Package: xcat-openbmc-py
Architecture: all
Depends:
Description: xcat openbmc python
+88
View File
@@ -0,0 +1,88 @@
Eclipse Public License - v 1.0
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
1. DEFINITIONS
"Contribution" means:
a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
b) in the case of each subsequent Contributor:
i) changes to the Program, and
ii) additions to the Program;
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.
"Contributor" means any person or entity that distributes the Program.
"Licensed Patents " 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.
"Program" means the Contributions distributed in accordance with this Agreement.
"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.
2. GRANT OF RIGHTS
a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to 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.
b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, 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.
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.
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.
3. REQUIREMENTS
A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:
a) it complies with the terms and conditions of this Agreement; and
b) its license agreement:
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;
ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and
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.
When the Program is made available in source code form:
a) it must be made available under this Agreement; and
b) a copy of this Agreement must be included with each copy of the Program.
Contributors may not remove or alter any copyright notices contained within the Program.
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.
4. COMMERCIAL DISTRIBUTION
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 ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") 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.
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.
5. NO WARRANTY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" 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.
6. DISCLAIMER OF LIABILITY
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.
7. GENERAL
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.
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.
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.
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.
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.
+5
View File
@@ -0,0 +1,5 @@
opt/xcat/lib/python/agent
opt/xcat/lib/python/agent/xcatagent
opt/xcat/lib/python/agent/common
opt/xcat/lib/python/agent/hwctl
opt/xcat/lib/python/agent/hwctl/executor
View File
+5
View File
@@ -0,0 +1,5 @@
lib/python/agent/*.py /opt/xcat/lib/python/agent
lib/python/agent/xcatagent/*.py /opt/xcat/lib/python/agent/xcatagent
lib/python/agent/common/*.py /opt/xcat/lib/python/agent/common
lib/python/agent/hwctl/*.py /opt/xcat/lib/python/agent/hwctl
lib/python/agent/hwctl/executor/*.py /opt/xcat/lib/python/agent/hwctl/executor
+41
View File
@@ -0,0 +1,41 @@
#!/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
clean:
dh_testdir
dh_testroot
dh_clean -d
install:
pwd
dh_testdir
dh_testroot
dh_installdirs
dh_install -X".svn"
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
+1
View File
@@ -0,0 +1 @@
1.0
+1 -1
View File
@@ -8,7 +8,7 @@ import json
import os
import socket
import sys
from xcatagent import utils
from common import utils
class ClientShell(object):
def get_base_parser(self):
@@ -1,7 +1,10 @@
#!/usr/bin/env python
class SelfServerException(Exception) :
pass
def __init__(self, message, detail_msg= "", host_and_port="") :
super(Exception, self).__init__(message)
self.host_and_port = host_and_port
self.detail_msg = detail_msg
class SelfClientException(Exception) :
def __init__(self, message, code) :
@@ -0,0 +1,129 @@
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
from gevent.subprocess import Popen, PIPE
import requests
import urllib3
urllib3.disable_warnings()
import exceptions as xcat_exception
class RestSession(object):
def __init__(self):
self.session = requests.Session()
self.cookies = None
def request(self, method, url, headers, data=None, timeout=30):
try:
response = self.session.request(method, url,
data=data,
headers=headers,
verify=False,
timeout=timeout)
except requests.exceptions.ConnectionError as e:
# Extract real reason for the exception and host/port from ConnectionError message
# Sometimes e.message is a list, sometimes is a string. Look for different patterns
# to extract the data needed.
causing_error = "n/a"
host_and_port = "n/a"
if "]" in e.message[0]:
causing_error_part1 = e.message[0].split("]")[1]
causing_error = causing_error_part1.split("'")[0]
causing_error = causing_error.strip()
host_and_port = self.extract_server_and_port(e.message[0], "STRING")
if "Connection aborted." in e.message[0]:
causing_error = "Connection reset by peer"
host_and_port = self.extract_server_and_port(url, "URL")
if "connect timeout=" in e.message[0]:
causing_error = "timeout"
host_and_port = self.extract_server_and_port(e.message[0], "STRING")
message = 'Failed to connect to server.'
# message = '\n\n--> {0} \n\n'.format(e.message[0])
raise xcat_exception.SelfServerException(message, '({0})'.format(causing_error), host_and_port)
except requests.exceptions.Timeout as e:
causing_error = "timeout"
host_and_port = self.extract_server_and_port(e.message[0], "STRING")
message = 'Timeout to connect to server'
raise xcat_exception.SelfServerException(message, '({0})'.format(causing_error), host_and_port)
if not self.cookies:
self.cookies = requests.utils.dict_from_cookiejar(self.session.cookies)
return response
def extract_server_and_port(self, message_string, format="STRING"):
# Extract hostip and port number from ConnectionError message
# If format="STRING" look for host='IP' and port=xxxx pattern
# If format="URL" look for https://IP/login pattern
if format == "STRING":
start = "host='"
end = "',"
host_ip = message_string[message_string.find(start)+len(start):message_string.find(end)]
start = "port="
end = "):"
port = message_string[message_string.find(start)+len(start):message_string.find(end)]
host_and_port = host_ip + ":" + port
elif format == "URL":
start = "https://"
end = "/login"
host_ip = message_string[message_string.find(start)+len(start):message_string.find(end)]
host_and_port = host_ip
else:
host_and_port = "n/a"
return host_and_port
def request_download(self, method, url, headers, file_path, using_curl=True):
if using_curl:
response = self._download_by_curl(method, url, headers, file_path)
else:
response = self.session.request('GET', url, headers=headers)
file_handle = open(file_path, "wb")
for chunk in response.iter_content(chunk_size=1024):
if chunk:
file_handle.write(chunk)
return response
def _download_by_curl(self, method, url, headers, file_path):
header_str = ' '.join([ "%s: %s" % (k, v) for k,v in headers.items() ])
request_cmd = 'curl -J -k -b sid=%s -H "%s" -X %s -o %s %s -s' % \
(self.cookies['sid'], header_str, method, file_path, url)
sub = Popen(request_cmd, stdout=PIPE, shell=True)
response, err = sub.communicate()
return response
def request_upload(self, method, url, headers, files, using_curl=True):
if using_curl:
return self._upload_by_curl(method, url, headers, files)
def _upload_by_curl(self, method, url, headers, files):
header_str = ' '.join([ "%s: %s" % (k, v) for k,v in headers.items() ])
request_cmd = 'curl -k -b sid=%s -H "%s" -X %s -T %s %s -s' % \
(self.cookies['sid'], header_str, method, files, url)
sub = Popen(request_cmd, stdout=PIPE, shell=True)
response, err = sub.communicate()
if not response:
error = 'Error: Did not receive response from server after ' \
'running command \'%s\'' % request_cmd
raise SelfServerException(error)
return response
@@ -0,0 +1,96 @@
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
from __future__ import print_function
import gevent
import sys
import traceback
class BaseCommand(object):
def _validate(self, op, *args, **kw):
if hasattr(self, 'validate_%s' % op):
return getattr(self, 'validate_%s' % op)(self, *args, **kw)
def _pre(self, op, *args, **kw):
if hasattr(self, 'pre_%s' % op):
return getattr(self, 'pre_%s' % op)(self, *args, **kw)
def _execute(self, op, *args, **kw):
if hasattr(self, '%s' % op):
return getattr(self, '%s' % op)(self, *args, **kw)
def _post(self, op, *args, **kw):
if hasattr(self, 'post_%s' % op):
return getattr(self, 'post_%s' % op)(self, *args, **kw)
def run(self, op, *args, **kwargs):
#print 'op=%s, args=%s, kwargs=%s' % (op, args, kwargs)
try:
self._validate(op, *args, **kwargs)
self._pre(op, *args, **kwargs)
self._execute(op, *args, **kwargs)
self._post(op, *args, **kwargs)
except Exception, e:
# TODO: put e into log
print(traceback.format_exc(), file=sys.stderr)
return None
return self.result()
def result(self):
"""Assume the result will be set by *_<op>"""
return True
class ParallelNodesCommand(BaseCommand):
def __init__(self, inventory, callback=None, **kwargs):
"""
inventory: {'node1': {k1:v1, k2:v2, ...}, 'node2': ...}
"""
self.inventory = inventory
self.callback = callback
self.debugmode = kwargs.get('debugmode')
self.verbose = kwargs.get('verbose')
def _execute_in_parallel(self, op, *args, **kw):
if not hasattr(self, '%s' % op):
return
assert self.inventory and type(self.inventory) is dict
func = getattr(self, '%s' % op)
if len(self.inventory) == 1:
node = self.inventory.keys()[0]
func(*args, node=node, nodeinfo=self.inventory[node], **kw)
return
pool_size = 1000 # Get it from kw later
gevent_pool = gevent.pool.Pool(pool_size)
for node in self.inventory.keys():
try:
gevent_pool.add( gevent.spawn(func, *args, node=node, nodeinfo=self.inventory[node], **kw))
except Exception, e:
error = '%s: Internel Error occured in gevent' % node
#print(traceback.format_exc(), file=sys.stderr)
self.callback.error(error)
gevent_pool.join()
def run(self, op, *args, **kwargs):
#print 'op=%s, args=%s, kwargs=%s' % (op, args, kwargs)
try:
self._validate(op, *args, **kwargs)
self._pre(op, *args, **kwargs)
self._execute_in_parallel(op, *args, **kwargs)
self._post(op, *args, **kwargs)
except Exception, e:
# TODO: put e into log
print(traceback.format_exc(), file=sys.stderr)
return None
return self.result()
@@ -0,0 +1,105 @@
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
import struct
import sys
import inspect
import re
import logging
from logging.handlers import SysLogHandler
XCAT_LOG_FMT = logging.Formatter("%(asctime)s %(levelname)s " +
"%(name)s %(process)d " +
"(%(filename)s:%(lineno)d) "+
"%(message)s")
XCAT_LOG_FMT.datefmt = '%Y-%m-%d %H:%M:%S'
def getxCATLog(name=None):
xl = logging.getLogger(name)
xl.fmt = XCAT_LOG_FMT
return xl
def enableSyslog(name='xcat'):
h = SysLogHandler(address='/dev/log', facility=SysLogHandler.LOG_LOCAL4)
h.setFormatter(logging.Formatter('%s: ' % name + '%(levelname)s %(message)s'))
logging.getLogger('xcatagent').addHandler(h)
def int2bytes(num):
return struct.pack('i', num)
def bytes2int(buf):
return struct.unpack('i', buf)[0]
def get_classes(module_name):
ret = []
for name, obj in inspect.getmembers(sys.modules[module_name]):
if inspect.isclass(obj):
ret.append(obj)
return ret
def class_func(module_name, class_name):
func = getattr(sys.modules[module_name], class_name)
return func
def recv_all(sock, size):
recv_size = 4096
buf_size = 0
buf_parts = []
while buf_size < size:
tmp_size = recv_size
left_size = size - buf_size
if left_size < recv_size:
tmp_size = left_size
buf_part = sock.recv(tmp_size)
buf_parts.append(buf_part)
buf_size += len(buf_part)
buf = ''.join(buf_parts)
return buf
def update2Ddict(updata_dict, key_a, key_b, value):
if key_a in updata_dict:
updata_dict[key_a].update({key_b: value})
else:
updata_dict.update({key_a: {key_b: value}})
def emb_numbers(string):
re_digits = re.compile(r'(\d+)')
pieces = re_digits.split(string)
pieces[1::2] = map(int,pieces[1::2])
return pieces
def sort_string_with_numbers(origin_list):
new_list = [(emb_numbers(string),string) for string in origin_list]
new_list.sort()
return [string for __,string in new_list]
class Messager(object):
def __init__(self, name=None):
self.logger = logging.getLogger(name or 'xcatagent')
def info(self, msg):
self.logger.info(msg)
def warn(self, msg):
self.logger.warn(msg)
def error(self, msg, node=''):
if node:
self.logger.error('%s: Error: %s' % (node, msg))
else:
self.logger.error('Error: %s' % msg)
def syslog(self, msg):
pass
def update_node_attributes(self, attribute, node, data):
pass
@@ -0,0 +1,26 @@
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
class BeaconInterface(object):
"""Interface for beacon-related actions."""
interface_type = 'beacon'
version = '1.0'
def set_beacon_state(self, task, beacon_state, timeout=None):
"""Set the beacon state of the task's nodes.
:param task: a Task instance containing the nodes to act on.
:param beacon_state: on|off beacon state.
:param timeout: timeout (in seconds) positive integer (> 0) for any
beacon state. ``None`` indicates to use default timeout.
"""
return task.run('set_state', beacon_state, timeout=timeout)
class DefaultBeaconManager(BeaconInterface):
"""Interface for beacon-related actions."""
pass
@@ -0,0 +1,45 @@
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
class BmcConfigInterface(object):
"""Interface for bmc configuration related actions."""
interface_type = 'bmcconfig'
version = '1.0'
def dump_list(self, task):
return task.run('dump_list')
def dump_generate(self, task):
return task.run("dump_generate")
def dump_clear(self, task, clear_arg):
return task.run("dump_clear", clear_arg)
def dump_download(self, task, download_arg):
return task.run("dump_download", download_arg)
def dump_process(self, task):
return task.run("dump_process")
def gard_clear(self, task):
return task.run("gard_clear")
def set_sshcfg(self, task):
return task.run("set_sshcfg")
def set_ipdhcp(self, task):
return task.run("set_ipdhcp")
def get_attributes(self, task, attributes):
return task.run("get_attributes", attributes)
def set_attributes(self, task, attributes):
return task.run("set_attributes", attributes)
class DefaultBmcConfigManager(BmcConfigInterface):
"""Interface for BmcConfig actions."""
pass
@@ -0,0 +1,41 @@
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
class EventlogInterface(object):
"""Interface for eventlog-related actions."""
interface_type = 'eventlog'
version = '1.0'
def get_eventlog_info(self, task, number_of_records="all"):
"""Return the eventlog info of the task's nodes.
:param number_of_records: number of records to display.
:param task: a Task instance containing the nodes to act on.
:return eventlog list
"""
return task.run('get_ev_info', number_of_records)
def clear_all_eventlog_records(self, task):
"""Clear all eventlog records.
:param task: a Task instance containing the nodes to act on.
:return
"""
return task.run('clear_all_ev_records')
def resolve_eventlog_records(self, task, resolve_list="LED"):
"""Return the eventlog info of the task's nodes.
:param resolve: list of eventlog ids to resolve or LED label.
:param task: a Task instance containing the nodes to act on.
:return eventlog list of resolved entries
"""
return task.run('resolve_ev_records', resolve_list)
class DefaultEventlogManager(EventlogInterface):
"""Interface for eventlog-related actions."""
pass
@@ -0,0 +1,34 @@
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
from __future__ import print_function
import gevent
import time
from common.task import ParallelNodesCommand
from common.exceptions import SelfClientException, SelfServerException
from hwctl import openbmc_client as openbmc
import logging
logger = logging.getLogger('xcatagent')
class OpenBMCBeaconTask(ParallelNodesCommand):
"""Executor for beacon-related actions."""
def set_state(self, state, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
try:
obmc.login()
obmc.set_beacon_state(state)
self.callback.info('%s: %s' % (node, state))
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
@@ -0,0 +1,458 @@
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
from __future__ import print_function
import os, stat
import sys
if 'threading' in sys.modules:
del sys.modules['threading']
from gevent import monkey
monkey.patch_all()
from gevent import sleep
import paramiko
from paramiko.ssh_exception import NoValidConnectionsError
import time
from common import utils
from common.task import ParallelNodesCommand
from common.exceptions import SelfClientException, SelfServerException
from hwctl import openbmc_client as openbmc
from scp import SCPClient
import logging
logger = logging.getLogger('xcatagent')
RSPCONFIG_GET_NETINFO=['ip', 'netmask', 'gateway', 'vlan', 'ipsrc', 'hostname', 'ntpservers']
RSPCONFIG_SET_NETINFO=['ip', 'netmask', 'gateway', 'vlan']
XCAT_LOG_DUMP_DIR = "/var/log/xcat/dump/"
class OpenBMCBmcConfigTask(ParallelNodesCommand):
def pre_dump_download(self, task, download_arg, **kw):
if download_arg == 'all':
self.callback.info('Downloading all dumps...')
if not os.path.exists(XCAT_LOG_DUMP_DIR):
os.makedirs(XCAT_LOG_DUMP_DIR)
def pre_dump_process(self, task, **kw):
self.callback.info('Capturing BMC Diagnostic information, this will take some time...')
def _dump_download(self, obmc, node, download_id, flag_dump_process=False):
formatted_time = time.strftime("%Y%m%d-%H%M", time.localtime(time.time()))
dump_log_file = '%s%s_%s_dump_%s.tar.xz' % (XCAT_LOG_DUMP_DIR, formatted_time, node, download_id)
if flag_dump_process:
self.callback.info('%s: Downloading dump %s to %s' % (node, download_id, dump_log_file))
obmc.download_dump(download_id, dump_log_file)
if os.path.exists(dump_log_file):
grep_cmd = '/usr/bin/grep -a'
path_not_found = '"Path not found"'
check_cmd = grep_cmd + ' ' + path_not_found + ' ' + dump_log_file
grep_string = os.popen(check_cmd).readlines()
if grep_string:
self.callback.error('Invalid dump %s was specified. Use -l option to list.' % download_id, node)
else:
self.callback.info('%s: Downloaded dump %s to %s.' % (node, download_id, dump_log_file))
else:
self.callback.error('Failed to download dump %s to %s.' % (download_id, dump_log_file), node)
return
def dump_list(self, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
dump_info = []
try:
obmc.login()
dump_dict = obmc.list_dump_info()
if not dump_dict:
self.callback.info('%s: No attributes returned from the BMC.' % node)
return dump_info
keys = dump_dict.keys()
keys.sort()
for key in keys:
info = '[%d] Generated: %s, Size: %s' % \
(key, dump_dict[key]['Generated'], dump_dict[key]['Size'])
dump_info += info
self.callback.info('%s: %s' % (node, info))
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
return dump_info
def dump_generate(self, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
dump_id = None
try:
obmc.login()
dump_id = obmc.create_dump()
if not dump_id:
self.callback.info('%s: BMC returned 200 OK but no ID was returned. Verify manually on the BMC.' % node)
else:
self.callback.info('%s: [%s] success' % (node, dump_id))
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
return dump_id
def dump_clear(self, clear_arg, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
try:
obmc.login()
obmc.clear_dump(clear_arg)
self.callback.info('%s: [%s] clear' % (node, clear_arg))
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
def dump_download(self, download_arg, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
try:
obmc.login()
if download_arg != 'all':
self._dump_download(obmc, node, download_arg)
return
dump_dict = obmc.list_dump_info()
keys = dump_dict.keys()
keys.sort()
for key in keys:
self._dump_download(obmc, node, str(key))
except SelfServerException as e:
self.callback.error(e.message, node)
def dump_process(self, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
try:
obmc.login()
flag = False
dump_id = obmc.create_dump()
self.callback.info('%s: Dump requested. Target ID is %s, waiting for BMC to generate...' % (node, dump_id))
for i in range(20):
dump_dict = obmc.list_dump_info()
if dump_id in dump_dict:
flag = True
break
if (20-i) % 8 == 0:
self.callback.info('%s: Still waiting for dump %s to be generated... ' % (node, dump_id))
sleep( 15 )
if flag:
self._dump_download(obmc, node, str(dump_id), flag_dump_process=True)
else:
self.callback.error('Could not find dump %s after waiting %d seconds.' % (dump_id, 20 * 15), node)
except SelfServerException as e:
self.callback.error(e.message, node)
def gard_clear(self, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
try:
obmc.login()
obmc.clear_gard()
self.callback.info('%s: GARD cleared' % node)
except SelfServerException as e:
self.callback.error(e.message, node)
def pre_set_sshcfg(self, *arg, **kw):
local_home_dir=os.path.expanduser('~')
self.local_ssh_dir = local_home_dir + "/.ssh/"
self.local_public_key = self.local_ssh_dir + "id_rsa.pub"
self.copy_sh_file = self.local_ssh_dir + "./copy.sh"
f = open(self.copy_sh_file, 'w')
f.write("#!/bin/sh \n\
umask 0077 \n\
userid=$1 \n\
home=`egrep \"^$userid:\" /etc/passwd | cut -f6 -d :` \n\
if [ -n \"$home\" ]; then \n\
dest_dir=\"$home/.ssh\" \n\
else \n\
home=`su - root -c pwd` \n\
dest_dir=\"$home/.ssh\" \n\
fi \n\
mkdir -p $dest_dir \n\
cat /tmp/$userid/.ssh/id_rsa.pub >> $home/.ssh/authorized_keys 2>&1 \n\
rm -f /tmp/$userid/.ssh/* 2>&1 \n\
rmdir \"/tmp/$userid/.ssh\" \n\
rmdir \"/tmp/$userid\" \n")
f.close()
os.chmod(self.copy_sh_file,stat.S_IRWXU)
if self.verbose:
self.callback.info("Prepared %s file done" % self.copy_sh_file)
def set_sshcfg(self, **kw):
node = kw['node']
nodeinfo = kw['nodeinfo']
tmp_remote_dir = "/tmp/%s/.ssh/" % nodeinfo['username']
try:
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.MissingHostKeyPolicy())
ssh_client.connect(nodeinfo['bmcip'], username=nodeinfo['username'], password=nodeinfo['password'])
except (NoValidConnectionsError) as e:
return self.callback.error("Unable to connect to bmc %s" % nodeinfo['bmcip'], node)
if not ssh_client.get_transport().is_active():
return self.callback.error("SSH session to bmc %s is not active" % nodeinfo['bmcip'], node)
if not ssh_client.get_transport().is_authenticated():
return self.callback.error("SSH session to bmc %s is not authenticated" % nodeinfo['bmcip'], node)
ssh_client.exec_command("/bin/mkdir -p %s\n" % tmp_remote_dir)
scp = SCPClient(ssh_client.get_transport())
scp.put(self.copy_sh_file, tmp_remote_dir + "copy.sh")
scp.put(self.local_public_key, tmp_remote_dir + "id_rsa.pub")
ssh_client.exec_command("%s/copy.sh %s" % (tmp_remote_dir, nodeinfo['username']))
ssh_client.close()
return self.callback.info("ssh keys copied to %s" % nodeinfo['bmcip'])
def set_ipdhcp(self, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
try:
obmc.login()
obmc.set_ipdhcp()
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
return
self.callback.info("%s: BMC Setting IP to DHCP..." % (node))
try:
obmc.reboot_bmc()
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
def get_attributes(self, attributes, **kw):
netinfo_dict={}
for attr in attributes:
if attr in RSPCONFIG_GET_NETINFO:
netinfo_dict[attr]=True
getnet=1
elif attr in openbmc.RSPCONFIG_APIS:
self._get_apis_values(attr, **kw)
else:
self.callback.error("get_attributes can not deal with attr %s" % attr, kw['node'])
if len(netinfo_dict):
self._get_netinfo(ip=netinfo_dict.get('ip', False), ipsrc=netinfo_dict.get('ipsrc', False), netmask=netinfo_dict.get('netmask', False),
gateway=netinfo_dict.get('gateway', False),vlan= netinfo_dict.get('vlan', False),
hostname=netinfo_dict.get('hostname', False),
ntpservers=netinfo_dict.get('ntpservers', False), **kw)
def set_attributes(self, attributes, **kw):
netinfo_dict={'vlan':False}
for attr in attributes:
k,v = attr.split('=')
if k in RSPCONFIG_SET_NETINFO:
netinfo_dict[k] = v
elif k == 'hostname':
self._set_hostname(v, **kw)
elif k == 'admin_passwd':
self._set_admin_password(v, **kw)
elif k == 'ntpservers':
self._set_ntp_servers(v, **kw)
elif k in openbmc.RSPCONFIG_APIS:
self._set_apis_values(k, v, **kw)
else:
return self.callback.error("set_attributes unsupported attribute:%s" % k, node)
if len(netinfo_dict) > 1 and ('ip' not in netinfo_dict or 'netmask' not in netinfo_dict or 'gateway' not in netinfo_dict):
self.callback.info("set_attributes miss either ip, netmask or gateway to set network information")
elif len(netinfo_dict) <= 1:
return
else:
self._set_netinfo(netinfo_dict['ip'], netinfo_dict['netmask'],
netinfo_dict['gateway'], netinfo_dict['vlan'])
def _set_hostname(self, hostname, **kw):
node = kw['node']
if hostname == '*':
if kw['nodeinfo']['bmc'] == kw['nodeinfo']['bmcip']:
self.callback.info("%s: set BMC ip as BMC Hostname" % node)
hostname = kw['nodeinfo']['bmc']
self._set_apis_values("hostname", hostname, **kw)
self._get_netinfo(hostname=True, ntpserver=False, **kw)
return
def _set_ntp_servers(self, servers, **kw):
node = kw['node']
node_info = kw['nodeinfo']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=node_info, messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
try:
obmc.login()
netinfo = obmc.get_netinfo()
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
return
if not netinfo:
return self.callback.error('No network information get', node)
bmcip = node_info['bmcip']
nic = self._get_facing_nic(bmcip, netinfo)
if not nic:
return self.callback.error('Can not get facing NIC for %s' % bmcip, node)
try:
obmc.set_ntp_servers(nic, servers)
self.callback.info('%s: BMC Setting NTPServers...' % node)
netinfo = obmc.get_netinfo()
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
return
ntpservers = None
if nic in netinfo:
ntpservers = netinfo[nic]['ntpservers']
self.callback.info('%s: BMC NTP Servers: %s' % (node, ntpservers))
def _get_facing_nic(self, bmcip, netinfo):
for k,v in netinfo.items():
if 'ip' in v and v['ip'] == bmcip:
return k
return None
def _set_admin_password(self, admin_passwd, **kw):
node = kw['node']
node_info = kw['nodeinfo']
origin_passwd, new_passwd = admin_passwd.split(',')
if origin_passwd != node_info['password']:
self.callback.error('Current BMC password is incorrect, cannot set the new password.', node)
return
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=node_info, messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
try:
obmc.login()
obmc.set_admin_passwd(new_passwd)
self.callback.info("%s: BMC Setting Password..." % node)
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
def _set_apis_values(self, key, value, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
try:
obmc.login()
obmc.set_apis_values(key, value)
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
self.callback.info("%s: BMC Setting %s..." % (node, openbmc.RSPCONFIG_APIS[key]['display_name']))
def _get_apis_values(self, key, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
try:
obmc.login()
value = obmc.get_apis_values(key)
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
str_value = '0.'+str(value)
result = '%s: %s: %s' % (node, openbmc.RSPCONFIG_APIS[key]['display_name'], str_value.split('.')[-1])
self.callback.info(result)
def _set_netinfo(self, ip, netmask, gateway, vlan=False, **kw):
if vlan:
result = "set net(%s, %s, %s) for vlan %s" % (ip, netmask, gateway, vlan)
else:
result = "set net(%s, %s, %s) for eth0" % (ip, netmask, gateway)
return self.callback.info("set_netinfo %s" % result)
def _get_netinfo(self, ip=False, ipsrc=False, netmask=False, gateway=False, vlan=False, hostname=False, ntpservers=False, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
try:
obmc.login()
netinfo = obmc.get_netinfo()
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
return
if not netinfo:
return self.callback.error("No network information get", node)
defaultgateway = "n/a"
bmchostname = ""
if 'defaultgateway' in netinfo:
defaultgateway = netinfo["defaultgateway"]
del netinfo["defaultgateway"]
if 'hostname' in netinfo:
bmchostname = netinfo["hostname"]
del netinfo["hostname"]
if hostname:
self.callback.info("%s: BMC Hostname: %s" %(node, bmchostname))
dic_length = len(netinfo)
netinfodict = {'ip':[], 'netmask':[], 'gateway':[],
'vlan':[], 'ipsrc':[], 'ntpservers':[]}
for nic,attrs in netinfo.items():
addon_string = ''
if dic_length > 1:
addon_string = " for %s" % nic
netinfodict['ip'].append("BMC IP"+addon_string+": %s" % attrs["ip"])
netinfodict['netmask'].append("BMC Netmask"+addon_string+": %s" % attrs["netmask"])
netinfodict['gateway'].append("BMC Gateway"+addon_string+": %s (default: %s)" % (attrs["gateway"], defaultgateway))
netinfodict['vlan'].append("BMC VLAN ID"+addon_string+": %s" % attrs["vlanid"])
netinfodict['ipsrc'].append("BMC IP Source"+addon_string+": %s" % attrs["ipsrc"])
netinfodict['ntpservers'].append("BMC NTP Servers"+addon_string+": %s" % attrs["ntpservers"])
if ip:
for i in netinfodict['ip']:
self.callback.info("%s: %s" % (node, i))
if netmask:
for i in netinfodict['netmask']:
self.callback.info("%s: %s" % (node, i))
if gateway:
for i in netinfodict['gateway']:
self.callback.info("%s: %s" % (node, i))
if ipsrc:
for i in netinfodict['ipsrc']:
self.callback.info("%s: %s" % (node, i))
if vlan:
for i in netinfodict['vlan']:
self.callback.info("%s: %s" % (node, i))
if ntpservers:
for i in netinfodict['ntpservers']:
self.callback.info("%s: %s" % (node, i))
return netinfo
@@ -0,0 +1,62 @@
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
from __future__ import print_function
import gevent
import time
from common.task import ParallelNodesCommand
from common.exceptions import SelfClientException, SelfServerException
from hwctl import openbmc_client as openbmc
from common import utils
import logging
logger = logging.getLogger('xcatagent')
class OpenBMCEventlogTask(ParallelNodesCommand):
"""Executor for eventlog-related actions."""
def get_ev_info(self, num_to_display, **kw):
node = kw['node']
number_to_display = 0
try:
# Number of records to display from the end
number_to_display = 0-int(num_to_display[0])
except Exception:
# All records to display
number_to_display = 0
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback, debugmode=self.debugmode, verbose=self.verbose)
eventlog_info = []
try:
obmc.login()
# Get all eventlog records
eventlog_info_dict = obmc.get_eventlog_info()
keys = eventlog_info_dict.keys()
# Sort thy keys in natural order
keys.sort(key=lambda x : int(x[0:]))
# Display all, or specified number of records from the end
for key in list(keys)[number_to_display:]:
self.callback.info('%s: %s' % (node, eventlog_info_dict[key]))
eventlog_info += eventlog_info_dict[key]
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
return eventlog_info
def clear_all_ev_records(self, **kw):
node = kw['node']
def resolve_ev_records(self, resolve_list, **kw):
node = kw['node']
@@ -0,0 +1,122 @@
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
from __future__ import print_function
import gevent
import time
from common.task import ParallelNodesCommand
from common.exceptions import SelfClientException, SelfServerException
from hwctl import openbmc_client as openbmc
from common import utils
import logging
logger = logging.getLogger('xcatagent')
class OpenBMCInventoryTask(ParallelNodesCommand):
"""Executor for inventory-related actions."""
def _get_firm_info(self, firm_info_list):
(has_functional, firm_obj_dict) = firm_info_list
firm_info = []
keys = firm_obj_dict.keys()
keys.sort()
for key in keys:
flag = ''
if firm_obj_dict[key].functional:
flag = '*'
elif firm_obj_dict[key].priority == 0:
if not has_functional:
flag = '*'
else:
flag = '+'
if flag != '*' and not self.verbose:
continue
firm_info.append('%s Firmware Product: %s (%s)%s' %
(firm_obj_dict[key].purpose,
firm_obj_dict[key].version,
firm_obj_dict[key].active,
flag))
if firm_obj_dict[key].extver:
extendeds = firm_obj_dict[key].extver.split(',')
extendeds.sort()
for extended in extendeds:
firm_info.append('%s Firmware Product: ' \
'-- additional info: %s' % \
(firm_obj_dict[key].purpose, extended))
return firm_info
def get_info(self, inventory_type, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
inventory_info = []
try:
obmc.login()
inventory_info_dict = obmc.get_inventory_info()
if inventory_type == 'all' or not inventory_type:
keys = inventory_info_dict.keys()
keys.sort()
for key in keys:
inventory_info += utils.sort_string_with_numbers(inventory_info_dict[key])
firm_dict_list = obmc.list_firmware()
firm_info = self._get_firm_info(firm_dict_list)
inventory_info += firm_info
elif inventory_type == 'model' or inventory_type == 'serial':
key = 'Model' if inventory_type == 'model' else 'SerialNumber'
if 'SYSTEM' in inventory_info_dict:
for system_info in inventory_info_dict['SYSTEM']:
if key in system_info:
inventory_info = [system_info]
break
else:
key = inventory_type.upper()
if key in inventory_info_dict:
inventory_info = utils.sort_string_with_numbers(inventory_info_dict[key])
if not inventory_info:
inventory_info = ['No attributes returned from the BMC.']
for info in inventory_info:
self.callback.info( '%s: %s' % (node, info))
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
return inventory_info
def get_firm_info(self, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
firm_info = []
try:
obmc.login()
firm_dict_list = obmc.list_firmware()
firm_info = self._get_firm_info(firm_dict_list)
for info in firm_info:
self.callback.info( '%s: %s' % (node, info))
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
return firm_info
@@ -0,0 +1,182 @@
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
from __future__ import print_function
import gevent
import time
from common.task import ParallelNodesCommand
from common.exceptions import SelfClientException, SelfServerException
from hwctl import openbmc_client as openbmc
import logging
logger = logging.getLogger('xcatagent')
POWER_STATE_DB = {
"on" : "powering-on",
"off" : "powering-off",
"softoff" : "powering-off",
"boot" : "powering-on",
"reset" : "powering-on",
}
class OpenBMCPowerTask(ParallelNodesCommand):
"""Executor for power-related actions."""
def _determine_state(self, states):
chassis_state = states.get('chassis')
host_state = states.get('host')
state = 'Unknown'
if chassis_state == 'Off':
state = chassis_state
elif chassis_state == 'On':
if host_state == 'Off':
state = 'chassison'
elif host_state in ['Quiesced', 'Running']:
state = host_state
else:
state = 'Unexpected host state=%s' % host_state
else:
state = 'Unexpected chassis state=%s' % chassis_state
return state
def get_state(self, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
state = 'Unknown'
try:
obmc.login()
states = obmc.list_power_states()
state = self._determine_state(states)
result = '%s: %s' % (node, openbmc.RPOWER_STATES.get(state, state))
except SelfServerException as e:
result = '%s: %s' % (node, e.message)
except SelfClientException as e:
result = '%s: %s' % (node, e.message)
self.callback.info(result)
return state
def get_bmcstate(self, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
bmc_not_ready = bmc_state = 'NotReady'
try:
obmc.login()
except SelfServerException as e:
# Special exception handling for login failure
login_message = "Login to BMC failed: Can't connect to {0} {1}.".format(e.host_and_port, e.detail_msg)
self.callback.error(login_message, node)
return bmc_state
try:
state = obmc.get_bmc_state()
bmc_state = state.get('bmc')
if bmc_state != 'Ready':
bmc_state = bmc_not_ready
result = '%s: %s' % (node, openbmc.RPOWER_STATES.get(bmc_state, bmc_state))
except SelfServerException, SelfClientException:
# There is no response when BMC is not ready
result = '%s: %s' % (node, openbmc.RPOWER_STATES[bmc_not_ready])
self.callback.info(result)
return bmc_state
def set_state(self, state, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
try:
obmc.login()
ret = obmc.set_power_state(state)
new_status = POWER_STATE_DB.get(state, '')
result = '%s: %s' % (node, state)
if new_status:
self.callback.update_node_attributes('status', node, new_status)
except (SelfServerException, SelfClientException) as e:
result = '%s: %s' % (node, e.message)
self.callback.info(result)
def reboot(self, optype='boot', **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
try:
obmc.login()
states = obmc.list_power_states()
status = self._determine_state(states)
new_status =''
if optype == 'reset' and status in ['Off', 'chassison']:
status = openbmc.RPOWER_STATES['Off']
result = '%s: %s' % (node, status)
else:
if status not in ['Off', 'off']:
obmc.set_power_state('off')
self.callback.update_node_attributes('status', node, POWER_STATE_DB['off'])
off_flag = False
start_timeStamp = int(time.time())
for i in range (0, 30):
states = obmc.list_power_states()
status = self._determine_state(states)
if openbmc.RPOWER_STATES.get(status) == 'off':
off_flag = True
break
gevent.sleep( 2 )
end_timeStamp = int(time.time())
if not off_flag:
error = 'Error: Sent power-off command but state did not change ' \
'to off after waiting %s seconds. (State= %s).' % (end_timeStamp - start_timeStamp, status)
raise SelfServerException(error)
ret = obmc.set_power_state('on')
self.callback.update_node_attributes('status', node, POWER_STATE_DB['on'])
result = '%s: %s' % (node, 'reset')
except (SelfServerException, SelfClientException) as e:
result = '%s: %s' % (node, e.message)
self.callback.info(result)
def reboot_bmc(self, optype='warm', **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
new_status = ''
try:
obmc.login()
except (SelfServerException, SelfClientException) as e:
result = '%s: %s' % (node, e.message)
else:
try:
obmc.reboot_bmc(optype)
except (SelfServerException, SelfClientException) as e:
result = '%s: %s' % (node, e.message)
else:
result = '%s: %s' % (node, openbmc.RPOWER_STATES['bmcreboot'])
self.callback.info(result)
@@ -0,0 +1,118 @@
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
from __future__ import print_function
import gevent
import time
from common.task import ParallelNodesCommand
from common.exceptions import SelfClientException, SelfServerException
from hwctl import openbmc_client as openbmc
from common import utils
import logging
logger = logging.getLogger('xcatagent')
SENSOR_TYPE_UNIT = {
"altitude" : "Meters",
"fanspeed" : "RPMS",
"temp" : "DegreesC",
"voltage" : "Volts",
"wattage" : "Watts",
}
SENSOR_POWER_UNITS = ("Amperes", "Joules", "Watts")
class OpenBMCSensorTask(ParallelNodesCommand):
"""Executor for sensor-related actions."""
def _get_beacon_info(self, beacon_dict):
info_list = []
info_list.append('Front . . . . . : Power:%s Fault:%s Identify:%s' %
(beacon_dict.get('front_power', 'N/A'),
beacon_dict.get('front_fault', 'N/A'),
beacon_dict.get('front_id', 'N/A')))
if (beacon_dict.get('fan0', 'N/A') == 'Off' and beacon_dict.get('fan1', 'N/A') == 'Off' and
beacon_dict.get('fan2', 'N/A') == 'Off' and beacon_dict.get('fan3', 'N/A') == 'Off'):
info_list.append('Front Fans . . : No LEDs On')
else:
info_list.append('Front Fans . . : fan0:%s fan1:%s fan2:%s fan3:%s' %
(beacon_dict.get('fan0', 'N/A'), beacon_dict.get('fan1', 'N/A'),
beacon_dict.get('fan2', 'N/A'), beacon_dict.get('fan3', 'N/A')))
info_list.append('Rear . . . . . : Power:%s Fault:%s Identify:%s' %
(beacon_dict.get('rear_power', 'N/A'),
beacon_dict.get('rear_fault', 'N/A'),
beacon_dict.get('rear_id', 'N/A')))
return info_list
def get_sensor_info(self, sensor_type, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
sensor_info = []
try:
obmc.login()
sensor_info_dict = obmc.get_sensor_info()
if sensor_type == 'all' or not sensor_type:
for sensor_key in sensor_info_dict:
sensor_info += sensor_info_dict[sensor_key]
sensor_info = utils.sort_string_with_numbers(sensor_info)
beacon_dict = obmc.get_beacon_info()
sensor_info += self._get_beacon_info(beacon_dict)
elif sensor_type == 'power':
for sensor_key in sensor_info_dict:
if sensor_key in SENSOR_POWER_UNITS:
sensor_info += sensor_info_dict[sensor_key]
sensor_info = utils.sort_string_with_numbers(sensor_info)
else:
sensor_unit = SENSOR_TYPE_UNIT[sensor_type]
if sensor_unit in sensor_info_dict:
sensor_info += sensor_info_dict[sensor_unit]
sensor_info = utils.sort_string_with_numbers(sensor_info)
if not sensor_info:
sensor_info = ['No attributes returned from the BMC.']
for info in sensor_info:
self.callback.info( '%s: %s' % (node, info))
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
return sensor_info
def get_beacon_info(self, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
beacon_info = []
try:
obmc.login()
beacon_dict = obmc.get_beacon_info()
beacon_info = self._get_beacon_info(beacon_dict)
if not beacon_info:
beacon_info = ['No attributes returned from the BMC.']
for info in beacon_info:
self.callback.info( '%s: %s' % (node, info))
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
return beacon_info
@@ -0,0 +1,62 @@
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
from __future__ import print_function
import gevent
import time
from common.task import ParallelNodesCommand
from common.exceptions import SelfClientException, SelfServerException
from hwctl import openbmc_client as openbmc
import logging
logger = logging.getLogger('xcatagent')
class OpenBMCBootTask(ParallelNodesCommand):
"""Executor for setboot-related actions."""
def get_state(self, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
state = 'Unknown'
try:
obmc.login()
state = obmc.get_boot_state()
self.callback.info('%s: %s' % (node, state))
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
return state
def set_state(self, state, persistant, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
try:
obmc.login()
if persistant:
obmc.set_one_time_boot_enable(0)
obmc.set_boot_state(state)
else:
obmc.set_one_time_boot_enable(1)
obmc.set_one_time_boot_state(state)
state = obmc.get_boot_state()
self.callback.info('%s: %s' % (node, state))
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
@@ -0,0 +1,32 @@
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
class InventoryInterface(object):
"""Interface for inventory-related actions."""
interface_type = 'inventory'
version = '1.0'
def get_inventory_info(self, task, inventory_type=None):
"""Return the inventory info of the task's nodes.
:param inventory_type: type of inventory info want to get.
:param task: a Task instance containing the nodes to act on.
:return inventory info list
"""
return task.run('get_info', inventory_type)
def get_firm_info(self, task):
"""Return the firm info of the task's nodes.
:param task: a Task instance containing the nodes to act on.
:return firm info list
"""
return task.run('get_firm_info')
class DefaultInventoryManager(InventoryInterface):
"""Interface for inventory-related actions."""
pass
@@ -0,0 +1,804 @@
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
import os
import requests
import json
import time
from common import utils, rest
from common.exceptions import SelfClientException, SelfServerException
import logging
logger = logging.getLogger('xcatagent')
HTTP_PROTOCOL = "https://"
PROJECT_URL = "/xyz/openbmc_project"
PROJECT_PAYLOAD = "xyz.openbmc_project."
RBEACON_URLS = {
"path" : "/led/groups/enclosure_identify/attr/Asserted",
"on" : {
"field" : True,
},
"off" : {
"field" : False,
},
}
DUMP_URLS = {
"clear" : {
"path" : "/dump/entry/#ID#/action/Delete",
"field" : [],
},
"clear_all" : {
"path" : "/dump/action/DeleteAll",
"field" : [],
},
"create" : {
"path" : "/dump/action/CreateDump",
"field" : [],
},
"download" : "download/dump/#ID#",
"list" : "/dump/enumerate",
}
GARD_CLEAR_URL = "/org/open_power/control/gard/action/Reset"
INVENTORY_URL = "/inventory/enumerate"
LEDS_URL = "/led/physical/enumerate"
LEDS_KEY_LIST = ("fan0", "fan1", "fan2", "fan3",
"front_id", "front_fault", "front_power",
"rear_id", "rear_fault", "rear_power")
SENSOR_URL = "/sensors/enumerate"
SENSOR_UNITS = {
"Amperes" : "Amps",
"DegreesC" : "C",
"Joules" : "Joules",
"Meters" : "Meters",
"RPMS" : "RPMS",
"Volts" : "Volts",
"Watts" : "Watts",
}
RPOWER_STATES = {
"on" : "on",
"off" : "off",
"Off" : "off",
"softoff" : "softoff",
"boot" : "reset",
"reset" : "reset",
"bmcreboot" : "BMC reboot",
"Ready" : "BMC Ready",
"NotReady" : "BMC NotReady",
"chassison" : "on (Chassis)",
"Running" : "on",
"Quiesced" : "quiesced",
}
RPOWER_URLS = {
"on" : {
"path" : "/state/host0/attr/RequestedHostTransition",
"field" : "State.Host.Transition.On",
},
"off" : {
"path" : "/state/chassis0/attr/RequestedPowerTransition",
"field" : "State.Chassis.Transition.Off",
},
"softoff" : {
"path" : "/state/host0/attr/RequestedHostTransition",
"field" : "State.Host.Transition.Off",
},
"state" : {
"path" : "/state/enumerate",
},
}
BMC_URLS = {
"reboot" : {
"path" : "/state/bmc0/attr/RequestedBMCTransition",
"field" : "State.BMC.Transition.Reboot",
},
"state" : {
"path" : "/state/bmc0/attr/CurrentBMCState",
},
}
BOOTSOURCE_URLS = {
"enable" : {
"path" : "/control/host0/boot/one_time/attr/Enabled",
},
"get" : {
"path" : "/control/host0/enumerate",
},
"set_one_time" : {
"path" : "/control/host0/boot/one_time/attr/BootSource",
},
"set" : {
"path" : "/control/host0/boot/attr/BootSource",
},
"field" : "xyz.openbmc_project.Control.Boot.Source.Sources.",
}
BOOTSOURCE_GET_STATE = {
"Default" : "Default",
"Disk" : "Hard Drive",
"ExternalMedia" : "CD/DVD",
"Network" : "Network",
}
BOOTSOURCE_SET_STATE = {
"cd" : "ExternalMedia",
"def" : "Default",
"default" : "Default",
"hd" : "Disk",
"net" : "Network",
}
FIRM_URLS = {
"activate" : {
"path" : "/software/%(id)s/attr/RequestedActivation",
"field" : "Software.Activation.RequestedActivations.Active",
},
"delete" : {
"path" : "/software/%(id)s/action/Delete",
"field" : [],
},
"priority" : {
"path" : "/software/%(id)s/attr/Priority",
"field" : False,
},
"list" : {
"path" : "/software/enumerate",
}
}
RSPCONFIG_NETINFO_URL = {
'get_netinfo': "/network/enumerate",
'nic_ip': "/network/#NIC#/action/IP",
'vlan': "/network/action/VLAN",
'ipdhcp': "/network/action/Reset",
'ntpservers': "/network/#NIC#/attr/NTPServers",
}
PASSWD_URL = '/user/root/action/SetPassword'
RSPCONFIG_APIS = {
'hostname': {
'baseurl': "/network/config/",
'set_url': "attr/HostName",
'display_name': "BMC Hostname",
},
'autoreboot' : {
'baseurl': "/control/host0/auto_reboot/",
'set_url': "attr/AutoReboot",
'get_url': "attr/AutoReboot",
'display_name': "BMC AutoReboot",
},
'powersupplyredundancy':{
'baseurl': "/sensors/chassis/PowerSupplyRedundancy/",
'set_url': "/action/setValue",
'get_url': "/action/getValue",
'get_method': 'POST',
'get_data': '[]',
'display_name': "BMC PowerSupplyRedundancy",
'attr_values': {
'disabled': "Disables",
'enabled': "Enabled",
},
},
'powerrestorepolicy': {
'baseurl': "/control/host0/power_restore_policy/",
'set_url': "attr/PowerRestorePolicy",
'get_url': "attr/PowerRestorePolicy",
'display_name': "BMC PowerRestorePolicy",
'attr_values': {
'restore': "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore",
'always_on': "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn",
'always_off': "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff",
},
},
'bootmode': {
'baseurl': "/control/host0/boot/",
'set_url': "attr/BootMode",
'get_url': "attr/BootMode",
'display_name':"BMC BootMode",
'attr_values': {
'regular': "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular",
'safe': "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe",
'setup': "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup",
},
},
}
EVENTLOG_URL = "/logging/enumerate"
RAS_POLICY_TABLE = "/opt/ibm/ras/lib/policyTable.json"
RAS_POLICY_MSG = "Install the OpenBMC RAS package to obtain more details logging messages."
RAS_NOT_FOUND_MSG = " Not found in policy table: "
RESULT_OK = 'ok'
RESULT_FAIL = 'fail'
class OpenBMCRest(object):
headers = {'Content-Type': 'application/json'}
def __init__(self, name, **kwargs):
#set default user/passwd
self.name = name
self.username, self.password = ('root', '0penBmc')
if 'nodeinfo' in kwargs:
for key, value in kwargs['nodeinfo'].items():
setattr(self, key, value)
if not hasattr(self, 'bmcip'):
self.bmcip = self.name
self.verbose = kwargs.get('debugmode')
# print back to xcatd or just stdout
self.messager = kwargs.get('messager')
self.session = rest.RestSession()
self.root_url = HTTP_PROTOCOL + self.bmcip + PROJECT_URL
self.download_root_url = HTTP_PROTOCOL + self.bmcip + '/'
def _print_record_log (self, msg, cmd):
if self.verbose :
localtime = time.asctime( time.localtime(time.time()) )
log = self.name + ': [openbmc_debug] ' + cmd + ' ' + msg
self.messager.info(localtime + ' ' + log)
logger.debug(log)
def _log_request (self, method, url, headers, data=None, files=None, file_path=None, cmd=''):
header_str = ' '.join([ "%s: %s" % (k, v) for k,v in headers.items() ])
msg = 'curl -k -c cjar -b cjar -X %s -H \"%s\" ' % (method, header_str)
if files:
msg += '-T \'%s\' %s -s' % (files, url)
elif file_path:
msg = 'curl -J -k -c cjar -b cjar -X %s -H \"%s\" %s -o %s' % \
(method, header_str, url, file_path)
elif data:
if cmd == 'login':
data = data.replace(self.password, "xxxxxx")
msg += '%s -d \'%s\'' % (url, data)
else:
msg += url
self._print_record_log(msg, cmd)
return msg
def handle_response (self, resp, cmd=''):
data = resp.json() # it will raise ValueError
code = resp.status_code
if code != requests.codes.ok:
description = ''.join(data['data']['description'])
error = 'Error: [%d] %s' % (code, description)
self._print_record_log(error, cmd)
raise SelfClientException(error, code)
self._print_record_log(data['message'], cmd)
return data['data']
def request (self, method, resource, headers=None, payload=None, timeout=30, cmd=''):
httpheaders = headers or OpenBMCRest.headers
url = resource
if not url.startswith(HTTP_PROTOCOL):
url = self.root_url + resource
data = None
if payload:
data=json.dumps(payload)
self._log_request(method, url, httpheaders, data=data, cmd=cmd)
try:
response = self.session.request(method, url, httpheaders, data=data)
return self.handle_response(response, cmd=cmd)
except SelfServerException as e:
e.message = 'Error: BMC did not respond. ' \
'Validate BMC configuration and retry the command.'
self._print_record_log(e.message, cmd)
raise
except ValueError:
error = 'Error: Received wrong format response: %s' % response
self._print_record_log(error, cmd)
raise SelfServerException(error)
def download(self, method, resource, file_path, headers=None, cmd=''):
httpheaders = headers or OpenBMCRest.headers
url = resource
if not url.startswith(HTTP_PROTOCOL):
url = self.download_root_url + resource
request_cmd = self._log_request(method, url, httpheaders, file_path=file_path, cmd=cmd)
try:
response = self.session.request_download(method, url, httpheaders, file_path)
except SelfServerException as e:
self._print_record_log(e.message, cmd=cmd)
raise
except SelfClientException as e:
error = e.message
self._print_record_log(error, cmd=cmd)
raise
if not response:
self._print_record_log('No response received for command %s' % request_cmd, cmd=cmd)
return True
self._print_record_log(str(response.status_code), cmd=cmd)
return True
def upload (self, method, resource, files, headers=None, cmd=''):
httpheaders = headers or OpenBMCRest.headers
url = resource
if not url.startswith(HTTP_PROTOCOL):
url = self.root_url + resource
request_cmd = self._log_request(method, url, httpheaders, files=files, cmd=cmd)
try:
response = self.session.request_upload(method, url, httpheaders, files)
except SelfServerException:
self._print_record_log(error, cmd=cmd)
raise
try:
data = json.loads(response)
except ValueError:
error = 'Error: Received wrong format response when running command \'%s\': %s' % \
(request_cmd, response)
self._print_record_log(error, cmd=cmd)
raise SelfServerException(error)
if data['message'] != '200 OK':
error = 'Error: Failed to upload update file %s : %s-%s' % \
(files, data['message'], \
''.join(data['data']['description']))
self._print_record_log(error, cmd=cmd)
raise SelfClientException(error, code)
self._print_record_log(data['message'], cmd=cmd)
return True
def login(self):
payload = { "data": [ self.username, self.password ] }
url = HTTP_PROTOCOL + self.bmcip + '/login'
self.request('POST', url, payload=payload, timeout=20, cmd='login')
def list_power_states(self):
states = self.request('GET', RPOWER_URLS['state']['path'], cmd='list_power_states')
#filter non used states
try:
host_stat = states[PROJECT_URL + '/state/host0']['CurrentHostState']
chassis_stat = states[PROJECT_URL + '/state/chassis0']['CurrentPowerState']
return {'host': host_stat.split('.')[-1], 'chassis': chassis_stat.split('.')[-1]}
except KeyError:
error = 'Error: Received wrong format response: %s' % states
raise SelfServerException(error)
def set_power_state(self, state):
payload = { "data": PROJECT_PAYLOAD + RPOWER_URLS[state]['field'] }
return self.request('PUT', RPOWER_URLS[state]['path'], payload=payload, cmd='set_power_state')
def get_bmc_state(self):
state = self.request('GET', BMC_URLS['state']['path'], cmd='get_bmc_state')
try:
return {'bmc': state.split('.')[-1]}
except KeyError:
error = 'Error: Received wrong format response: %s' % state
raise SelfServerException(error)
def reboot_bmc(self, optype='warm'):
payload = { "data": PROJECT_PAYLOAD + BMC_URLS['reboot']['field'] }
try:
self.request('PUT', BMC_URLS['reboot']['path'], payload=payload, cmd='bmc_reset')
except SelfServerException,SelfClientException:
# TODO: Need special handling for bmc reset, as it is normal bmc may return error
pass
def set_one_time_boot_enable(self, enabled):
payload = { "data": enabled }
self.request('PUT', BOOTSOURCE_URLS['enable']['path'], payload=payload, cmd='set_one_time_boot_enable')
def set_boot_state(self, state):
payload = { "data": BOOTSOURCE_URLS['field'] + BOOTSOURCE_SET_STATE[state] }
self.request('PUT', BOOTSOURCE_URLS['set']['path'], payload=payload, cmd='set_boot_state')
def set_one_time_boot_state(self, state):
payload = { "data": BOOTSOURCE_URLS['field'] + BOOTSOURCE_SET_STATE[state] }
self.request('PUT', BOOTSOURCE_URLS['set_one_time']['path'], payload=payload, cmd='set_one_time_boot_state')
def get_boot_state(self):
state = self.request('GET', BOOTSOURCE_URLS['get']['path'], cmd='get_boot_state')
try:
one_time_path = PROJECT_URL + '/control/host0/boot/one_time'
one_time_enabled = state[one_time_path]['Enabled']
if one_time_enabled:
boot_source = state[one_time_path]['BootSource'].split('.')[-1]
else:
boot_source = state[PROJECT_URL + '/control/host0/boot']['BootSource'].split('.')[-1]
error = 'Can not get valid rsetboot status, the data is %s' % boot_source
boot_state = BOOTSOURCE_GET_STATE.get(boot_source.split('.')[-1], error)
return boot_state
except KeyError:
error = 'Error: Received wrong format response: %s' % states
raise SelfServerException(error)
def get_beacon_info(self):
beacon_data = self.request('GET', LEDS_URL, cmd='get_beacon_info')
try:
beacon_dict = {}
for key, value in beacon_data.items():
key_id = key.split('/')[-1]
if key_id in LEDS_KEY_LIST:
beacon_dict[key_id] = value['State'].split('.')[-1]
return beacon_dict
except KeyError:
error = 'Error: Received wrong format response: %s' % beacon_data
raise SelfServerException(error)
def set_beacon_state(self, state):
payload = { "data": RBEACON_URLS[state]['field'] }
self.request('PUT', RBEACON_URLS['path'], payload=payload, cmd='set_beacon_state')
def get_sensor_info(self):
sensor_data = self.request('GET', SENSOR_URL, cmd='get_sensor_info')
try:
sensor_dict = {}
for k, v in sensor_data.items():
if 'Unit' in v:
unit = v['Unit'].split('.')[-1]
if unit in SENSOR_UNITS:
label = k.split('/')[-1].replace('_', ' ').title()
value = v['Value']
scale = v['Scale']
value = value * pow(10, scale)
value = '{:g}'.format(value)
if unit not in sensor_dict:
sensor_dict[unit] = []
sensor_dict[unit].append('%s: %s %s' % (label, value, SENSOR_UNITS[unit]))
elif 'units' in v and 'value' in v:
label = k.split('/')[-1]
value = v['value']
sensor_dict[label] = ['%s: %s' % (label, value)]
return sensor_dict
except KeyError:
error = 'Error: Received wrong format response: %s' % sensor_data
raise SelfServerException(error)
def get_inventory_info(self):
inventory_data = self.request('GET', INVENTORY_URL, cmd='get_inventory_info')
try:
inverntory_dict = {}
for key, value in inventory_data.items():
if 'Present' not in value:
logger.debug('Not "Present" for %s' % key)
continue
key_list = key.split('/')
try:
key_id = key_list[-1]
key_tmp = key_list[-2]
except IndexError:
logger.debug('IndexError (-2) for %s' % key)
continue
key_type = filter(lambda x:x not in '0123456789', key_id).upper()
if key_type == 'CORE':
key_type = 'CPU'
source = '%s %s' % (key_tmp, key_id)
else:
source = key_id
if key_type not in inverntory_dict:
inverntory_dict[key_type] = []
for (sub_key, v) in value.items():
inverntory_dict[key_type].append('%s %s : %s' % (source.upper(), sub_key, v))
return inverntory_dict
except KeyError:
error = 'Error: Received wrong format response: %s' % inventory_data
raise SelfServerException(error)
def list_firmware(self):
data = self.request('GET', FIRM_URLS['list']['path'], cmd='list_firmware')
try:
func_list = data.pop('/xyz/openbmc_project/software/functional')['endpoints']
except:
logger.debug('Not found functional firmwares')
func_list = []
fw_dict={}
for key, swinfo in data.items():
if 'Version' not in swinfo:
logger.debug('Not found version information for %s' % key)
continue
fw = OpenBMCImage(key, swinfo)
if func_list:
fw.functional = key in func_list
fw_dict[str(fw)]=fw
return bool(func_list), fw_dict
# Extract all eventlog info and parse it
def get_eventlog_info(self):
eventlog_data = self.request('GET', EVENTLOG_URL, cmd='get_eventlog_info')
return self.parse_eventlog_data(eventlog_data)
# Parse eventlog data and build a dictionary with eventid as a key
def parse_eventlog_data(self, eventlog_data):
# Check if policy table file is there
ras_event_mapping = {}
if os.path.isfile(RAS_POLICY_TABLE):
with open(RAS_POLICY_TABLE, "r") as data_file:
policy_hash = json.load(data_file)
if policy_hash:
ras_event_mapping = policy_hash['events']
else:
self.messager.info(RAS_POLICY_MSG)
data_file.close()
else:
self.messager.info(RAS_POLICY_MSG)
try:
eventlog_dict = {}
for key, value in sorted(eventlog_data.items()):
id, event_log_line = self.parse_eventlog_data_record(value, ras_event_mapping)
if int(id) != 0:
eventlog_dict[str(id)] = event_log_line
return eventlog_dict
except KeyError:
error = 'Error: Received wrong format response: %s' % eventlog_data
raise SelfServerException(error)
# Parse a single eventlog entry and return data in formatted string
def parse_eventlog_data_record(self, event_log_entry, ras_event_mapping):
formatted_line = ""
callout_data = ""
LED_tag = " [LED]"
timestamp_str = ""
message_str = ""
pid_str = ""
resolved_str = ""
id_str = "0"
callout = False
for (sub_key, v) in event_log_entry.items():
if sub_key == 'AdditionalData':
for (data_key) in v:
additional_data = data_key.split("=");
if additional_data[0] == 'ESEL':
esel = additional_data[1]
# Placeholder, not currently used
elif additional_data[0] == '_PID':
pid_str = "PID: " + str(additional_data[1]) + "),"
elif 'CALLOUT_DEVICE_PATH' in additional_data[0]:
callout = True
callout_data = "I2C"
elif 'CALLOUT_INVENTORY_PATH' in additional_data[0]:
callout = True
callout_data = additional_data[1]
elif 'CALLOUT' in additional_data[0]:
callout = True
elif 'GPU' in additional_data[0]:
callout_data="/xyz/openbmc_project/inventory/system/chassis/motherboard/gpu"
elif 'PROCEDURE' in additional_data[0]:
callout_data = '{:x}'.format(int(additional_data[1])) #Convert to hext
elif sub_key == 'Timestamp':
timestamp = time.localtime(v / 1000)
timestamp_str = time.strftime("%m/%d/%Y %T", timestamp)
elif sub_key == 'Id':
id_str = str(v)
elif sub_key == 'Resolved':
resolved_str = " Resolved: " + str(v)
elif sub_key == 'Message':
message_str = v
if callout_data:
message_str += "||" + callout_data
# If event data mapping was read in from RAS policy table, display a more detailed message
if ras_event_mapping:
if message_str in ras_event_mapping:
event_type = ras_event_mapping[message_str]['EventType']
event_message = ras_event_mapping[message_str]['Message']
severity = ras_event_mapping[message_str]['Severity']
affect = ras_event_mapping[message_str]['AffectedSubsystem']
formatted_line = timestamp_str + " [" + id_str +"]" + ": " + event_type + ", " + "(" + severity + ") " + event_message + " (AffectedSubsystem: " + affect + ", " + pid_str + resolved_str
else:
formatted_line = timestamp_str + " [" + id_str +"]" + ":" + RAS_NOT_FOUND_MSG + message_str + " (" + pid_str + resolved_str
else:
formatted_line = timestamp_str + " [" + id_str +"]" + ": " + message_str + " (" + pid_str + resolved_str
if callout:
formatted_line += LED_tag
return id_str, formatted_line
def set_apis_values(self, key, value):
attr_info = RSPCONFIG_APIS[key]
if 'set_url' not in attr_info:
raise SelfServerException("config %s failed, not url available" % key)
set_url = attr_info['baseurl']+attr_info['set_url']
if 'attr_values' in attr_info and value in attr_info['attr_values']:
data = attr_info['attr_values'][value]
else:
data = value
self.request('PUT', set_url, payload={"data": data}, cmd="set_%s" % key)
def get_apis_values(self, key):
attr_info = RSPCONFIG_APIS[key]
if 'get_url' not in attr_info:
raise SelfServerException("Reading %s failed, not url available" % key)
get_url = attr_info['baseurl']+attr_info['get_url']
method = 'GET'
if 'get_method' in attr_info:
method = attr_info['get_method']
data = None
if 'get_data' in attr_info:
data={"data": attr_info['get_data']}
return self.request(method, get_url, payload=data, cmd="get_%s" % key)
def set_admin_passwd(self, passwd):
payload = { "data": [passwd] }
self.request('POST', PASSWD_URL, payload=payload, cmd='set_admin_password')
def set_ntp_servers(self, nic, servers):
payload = { "data": [servers] }
url = RSPCONFIG_NETINFO_URL['ntpservers'].replace('#NIC#', nic)
self.request('PUT', url, payload=payload, cmd='set_ntp_servers')
def clear_dump(self, clear_arg):
if clear_arg == 'all':
payload = { "data": DUMP_URLS['clear_all']['field'] }
self.request('POST', DUMP_URLS['clear_all']['path'], payload=payload, cmd='clear_dump_all')
else:
path = DUMP_URLS['clear']['path'].replace('#ID#', clear_arg)
payload = { "data": DUMP_URLS['clear']['field'] }
self.request('POST', path, payload=payload, cmd='clear_dump')
def create_dump(self):
payload = { "data": DUMP_URLS['create']['field'] }
return self.request('POST', DUMP_URLS['create']['path'], payload=payload, cmd='create_dump')
def list_dump_info(self):
dump_data = self.request('GET', DUMP_URLS['list'], cmd='list_dump_info')
try:
dump_dict = {}
for key, value in dump_data.items():
if 'Size' not in value or 'Elapsed' not in value:
continue
key_id = int(key.split('/')[-1])
timestamp = value['Elapsed']
gen_time = time.strftime("%m/%d/%Y %H:%M:%S", time.localtime(timestamp))
dump_dict.update({key_id: {'Size': value['Size'], 'Generated': gen_time}})
return dump_dict
except KeyError:
error = 'Error: Received wrong format response: %s' % dump_data
raise SelfServerException(error)
def download_dump(self, download_id, file_path):
headers = {'Content-Type': 'application/octet-stream'}
path = DUMP_URLS['download'].replace('#ID#', download_id)
self.download('GET', path, file_path, headers=headers, cmd='download_dump')
def clear_gard(self):
payload = { "data": [] }
url = HTTP_PROTOCOL + self.bmcip + GARD_CLEAR_URL
return self.request('POST', url, payload=payload, cmd='clear_gard')
def get_netinfo(self):
data = self.request('GET', RSPCONFIG_NETINFO_URL['get_netinfo'], cmd="get_netinfo")
try:
netinfo = {}
for k, v in data.items():
if 'network/config' in k:
if 'HostName' in v:
netinfo["hostname"] = v["HostName"]
if 'DefaultGateway' in v:
netinfo["defaultgateway"] = v["DefaultGateway"]
continue
dev,match,netid = k.partition("/ipv4/")
if netid:
if 'LinkLocal' in v["Origin"] or v["Address"].startswith("169.254"):
msg = "Found LinkLocal address %s for interface %s, Ignoring..." % (v["Address"], dev)
self._print_record_log(msg, 'get_netinfo')
continue
nicid = dev.split('/')[-1]
if nicid not in netinfo:
netinfo[nicid] = {}
if 'ip' in netinfo[nicid]:
msg = "%s: Another valid ip %s found." % (node, v["Address"])
self._print_record_log(msg, 'get_netinfo')
continue
utils.update2Ddict(netinfo, nicid, "ipsrc", v["Origin"].split('.')[-1])
utils.update2Ddict(netinfo, nicid, "netmask", v["PrefixLength"])
utils.update2Ddict(netinfo, nicid, "gateway", v["Gateway"])
utils.update2Ddict(netinfo, nicid, "ip", v["Address"])
if dev in data:
info = data[dev]
utils.update2Ddict(netinfo, nicid, "vlanid", info.get("Id", "Disable"))
utils.update2Ddict(netinfo, nicid, "mac", info["MACAddress"])
ntpservers = None
tmp_ntpservers = ''.join(info["NTPServers"])
if tmp_ntpservers:
ntpservers = tmp_ntpservers
utils.update2Ddict(netinfo, nicid, "ntpservers", ntpservers)
return netinfo
except KeyError:
error = 'Error: Received wrong format response: %s' % data
raise SelfServerException(error)
def set_ipdhcp(self):
payload = { "data": [] }
return self.request('PUT', RSPCONFIG_NETINFO_URL['ipdhcp'], payload=payload, cmd="set_bmcip_dhcp")
class OpenBMCImage(object):
def __init__(self, rawid, data=None):
self.id = rawid.split('/')[-1]
self.extver = None
self.functional = False
self.priority = None
self.progress = None
self.purpose = 'Unknown'
if data:
self.version = data.get('Version')
self.purpose = data.get('Purpose', self.purpose).split('.')[-1]
self.priority = data.get('Priority')
self.extver = data.get('ExtendedVersion')
self.progress = data.get('Progress')
self.active = data.get('Activation')
if self.active:
self.active = self.active.split('.')[-1]
def __str__(self):
return '%s-%s' % (self.purpose, self.id)
@@ -0,0 +1,59 @@
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
class PowerInterface(object):
"""Interface for power-related actions."""
interface_type = 'power'
version = '1.0'
def get_power_state(self, task):
"""Return the power state of the task's nodes.
:param task: a Task instance containing the nodes to act on.
:returns: a power state.
"""
return task.run('get_state')
def set_power_state(self, task, power_state, timeout=None):
"""Set the power state of the task's nodes.
:param task: a Task instance containing the nodes to act on.
:param power_state: Any supported power state.
:param timeout: timeout (in seconds) positive integer (> 0) for any
power state. ``None`` indicates to use default timeout.
"""
return task.run('set_state', power_state, timeout=timeout)
def reboot(self, task, optype='boot', timeout=None):
"""Perform a hard reboot of the task's nodes.
:param task: a Task instance containing the node to act on.
:param timeout: timeout (in seconds) positive integer (> 0) for any
power state. ``None`` indicates to use default timeout.
"""
return task.run('reboot', optype, timeout=timeout)
def get_bmc_state(self, task):
"""Return the bmc state of the task's nodes.
:param task: a Task instance containing the nodes to act on.
:returns: a bmc state.
"""
return task.run('get_bmcstate')
def reboot_bmc(self, task, optype='warm'):
"""Set the BMC state of the task's nodes.
:param task: a Task instance containing the nodes to act on.
:returns: a power state.
"""
return task.run('reboot_bmc', optype)
class DefaultPowerManager(PowerInterface):
"""Interface for power-related actions."""
pass
@@ -0,0 +1,32 @@
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
class SensorInterface(object):
"""Interface for sensor-related actions."""
interface_type = 'sensor'
version = '1.0'
def get_sensor_info(self, task, sensor_type=None):
"""Return the sensor info of the task's nodes.
:param sensor_type: type of sensor info want to get.
:param task: a Task instance containing the nodes to act on.
:return: sensor info list
"""
return task.run('get_sensor_info', sensor_type)
def get_beacon_info(self, task):
"""Return the beacon info of the task's nodes.
:param task: a Task instance containing the nodes to act on.
:return: beacon info list
"""
return task.run('get_beacon_info')
class DefaultSensorManager(SensorInterface):
"""Interface for sensor-related actions."""
pass
@@ -0,0 +1,34 @@
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
class BootInterface(object):
"""Interface for setboot-related actions."""
interface_type = 'setboot'
version = '1.0'
def get_boot_state(self, task):
"""Return the setboot state of the task's nodes.
:param task: a Task instance containing the nodes to act on.
:returns: a setboot state.
"""
return task.run('get_state')
def set_boot_state(self, task, setboot_state, persistant=False, timeout=None):
"""Set the setboot state of the task's nodes.
:param task: a Task instance containing the nodes to act on.
:param setboot_state: Any boot state allowed.
:param persistant: whether set boot state persistant
:param timeout: timeout (in seconds) positive integer (> 0) for any
setboot state. ``None`` indicates to use default timeout.
"""
return task.run('set_state', setboot_state, persistant, timeout=timeout)
class DefaultBootManager(BootInterface):
"""Interface for setboot-related actions."""
pass
@@ -1,10 +1,9 @@
from xcatagent import utils
from common import utils
import gevent
from gevent.pool import Pool
MODULE_MAP = {"openbmc": "OpenBMCManager"}
class BaseManager(object):
def __init__(self, messager, cwd):
self.messager = messager
@@ -15,8 +14,8 @@ class BaseManager(object):
module_name = 'xcatagent.%s' % name
try:
__import__(module_name)
except ImportError:
return None
except ImportError as err:
raise ImportError(err)
class_name = MODULE_MAP[name]
return utils.class_func(module_name, class_name)
@@ -1,12 +1,40 @@
from xcatagent import base
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
import os
import time
import sys
import gevent
import re
from docopt import docopt,DocoptExit
import utils
import xcat_exception
from common import utils
from common import exceptions as xcat_exception
from hwctl.executor.openbmc_beacon import OpenBMCBeaconTask
from hwctl.executor.openbmc_setboot import OpenBMCBootTask
from hwctl.executor.openbmc_inventory import OpenBMCInventoryTask
from hwctl.executor.openbmc_power import OpenBMCPowerTask
from hwctl.executor.openbmc_sensor import OpenBMCSensorTask
from hwctl.executor.openbmc_bmcconfig import OpenBMCBmcConfigTask
from hwctl.executor.openbmc_eventlog import OpenBMCEventlogTask
from hwctl.beacon import DefaultBeaconManager
from hwctl.setboot import DefaultBootManager
from hwctl.inventory import DefaultInventoryManager
from hwctl.power import DefaultPowerManager
from hwctl.sensor import DefaultSensorManager
from hwctl.bmcconfig import DefaultBmcConfigManager
from hwctl.eventlog import DefaultEventlogManager
from xcatagent import base
import openbmc_rest
import logging
logger = logging.getLogger('xcatagent')
if not logger.handlers:
utils.enableSyslog('xcat.agent')
HTTP_PROTOCOL = "https://"
PROJECT_URL = "/xyz/openbmc_project"
@@ -19,6 +47,9 @@ VERBOSE = False
all_nodes_result = {}
# global variables of rbeacon
BEACON_SET_OPTIONS = ('on', 'off')
# global variables of rflash
RFLASH_OPTIONS = {
"-a" : "activate",
@@ -51,60 +82,74 @@ RFLASH_URLS = {
}
}
RSPCONFIG_GET_OPTIONS = ['ip','ipsrc','netmask','gateway','vlan','ntpservers','hostname','bootmode','autoreboot','powersupplyredundancy','powerrestorepolicy']
RSPCONFIG_SET_OPTIONS = {
'ip':'.*',
'netmask':'.*',
'gateway':'.*',
'vlan':'\d+',
'hostname':"\*|.*",
'ntpservers':'.*',
'autoreboot':"^0|1$",
'powersupplyredundancy':"^enabled$|^disabled$",
'powerrestorepolicy':"^always_on$|^always_off$|^restore$",
'bootmode':"^regular$|^safe$|^setup$",
'admin_passwd':'.*,.*',
}
RSPCONFIG_USAGE = """
Handle rspconfig operations.
Usage:
rspconfig -h|--help
rspconfig dump [[-l|--list] | [-g|--generate] | [-c|--clear --id <arg>] | [-d|--download --id <arg>]] [-V|--verbose]
rspconfig gard -c|--clear [-V|--verbose]
rspconfig sshcfg [-V|--verbose]
rspconfig ip=dhcp [-V|--verbose]
rspconfig get [<args>...] [-V|--verbose]
rspconfig set [<args>...] [-V|--verbose]
Options:
-V,--verbose Show verbose message
-l,--list List are dump files
-g,--generate Trigger a new dump file
-c,--clear To clear the specified dump file
-d,--download To download specified dump file
--id <arg> The dump file id or 'all'
The supported attributes to get are: %s
The supported attributes and its values to set are:
ip=<ip address> netmask=<mask> gateway=<gateway> [vlan=<vlanid>]
hostname=*|<string>
autoreboot={0|1}
powersupplyredundancy={enabled|disabled}
powerrestorepolicy={always_on|always_off|restore}
""" % RSPCONFIG_GET_OPTIONS
XCAT_LOG_DIR = "/var/log/xcat"
XCAT_LOG_RFLASH_DIR = XCAT_LOG_DIR + "/rflash/"
# global variable of firmware information
FIRM_URL = PROJECT_URL + "/software/enumerate"
#global variables of rinv
INVENTORY_OPTIONS = ('all', 'cpu', 'dimm', 'firm', 'model', 'serial')
# global variables of rpower
POWER_REBOOT_OPTIONS = ('boot', 'reset')
POWER_SET_OPTIONS = ('on', 'off', 'bmcreboot', 'softoff')
POWER_GET_OPTIONS = ('bmcstate', 'state', 'stat', 'status')
RPOWER_URLS = {
"on" : {
"url" : PROJECT_URL + "/state/host0/attr/RequestedHostTransition",
"field" : "xyz.openbmc_project.State.Host.Transition.On",
},
"off" : {
"url" : PROJECT_URL + "/state/chassis0/attr/RequestedPowerTransition",
"field" : "xyz.openbmc_project.State.Chassis.Transition.Off",
},
"softoff" : {
"url" : PROJECT_URL + "/state/host0/attr/RequestedHostTransition",
"field" : "xyz.openbmc_project.State.Host.Transition.Off",
},
"bmcreboot" : {
"url" : PROJECT_URL + "/state/bmc0/attr/RequestedBMCTransition",
"field" : "xyz.openbmc_project.State.BMC.Transition.Reboot",
},
"state" : {
"url" : PROJECT_URL + "/state/enumerate",
},
}
# global variables of rsetboot
SETBOOT_GET_OPTIONS = ('stat', '')
SETBOOT_SET_OPTIONS = ('cd', 'def', 'default', 'hd', 'net')
RPOWER_STATE = {
"on" : "on",
"off" : "off",
"Off" : "off",
"softoff" : "softoff",
"boot" : "reset",
"reset" : "reset",
"bmcreboot" : "BMC reboot",
"Ready" : "BMC Ready",
"NotReady" : "BMC NotReady",
"chassison" : "on (Chassis)",
"Running" : "on",
"Quiesced" : "quiesced",
}
# global variables of rvitals
VITALS_OPTIONS = ('all', 'altitude', 'fanspeed', 'leds', 'power',
'temp', 'voltage', 'wattage')
POWER_STATE_DB = {
"on" : "powering-on",
"off" : "powering-off",
"softoff" : "powering-off",
"boot" : "powering-on",
"reset" : "powering-on",
}
# global variables of reventlog
EVENTLOG_OPTIONS = ('list', 'clear', 'resolved')
class OpenBMC(base.BaseDriver):
@@ -489,107 +534,6 @@ class OpenBMC(base.BaseDriver):
return RESULT_OK
def _set_power_onoff(self, subcommand):
""" Set power on/off/softoff/bmcreboot
:param subcommand: subcommand for rpower
:returns: ok if success
:raise: error message if failed
"""
url = HTTP_PROTOCOL + self.bmcip + RPOWER_URLS[subcommand]['url']
data = { "data": RPOWER_URLS[subcommand]['field'] }
try:
response = self.client.request('PUT', url, OpenBMC.headers,
data, 'rpower_' + subcommand)
except (xcat_exception.SelfServerException,
xcat_exception.SelfClientException) as e:
if subcommand != 'bmcreboot':
result = e.message
return result
return RESULT_OK
def _get_power_state(self, subcommand):
""" Get power current state
:param subcommand: state/stat/status/bmcstate
:returns: current state if success
:raise: error message if failed
"""
result = ''
bmc_not_ready = 'NotReady'
url = HTTP_PROTOCOL + self.bmcip + RPOWER_URLS['state']['url']
try:
response = self.client.request('GET', url, OpenBMC.headers,
'', 'rpower_' + subcommand)
except xcat_exception.SelfServerException, e:
if subcommand == 'bmcstate':
result = bmc_not_ready
else:
result = e.message
except xcat_exception.SelfClientException, e:
result = e.message
if result:
return result
for key in response['data']:
key_type = key.split('/')[-1]
if key_type == 'bmc0':
bmc_current_state = response['data'][key]['CurrentBMCState'].split('.')[-1]
if key_type == 'chassis0':
chassis_current_state = response['data'][key]['CurrentPowerState'].split('.')[-1]
if key_type == 'host0':
host_current_state = response['data'][key]['CurrentHostState'].split('.')[-1]
if subcommand == 'bmcstate':
if bmc_current_state == 'Ready':
return bmc_current_state
else:
return bmc_not_ready
if chassis_current_state == 'Off':
return chassis_current_state
elif chassis_current_state == 'On':
if host_current_state == 'Off':
return 'chassison'
elif host_current_state == 'Quiesced':
return host_current_state
elif host_current_state == 'Running':
return host_current_state
else:
return 'Unexpected chassis state=' + host_current_state
else:
return 'Unexpected chassis state=' + chassis_current_state
def _rpower_boot(self):
"""Power boot
:returns: 'reset' if success
:raise: error message if failed
"""
result = self._set_power_onoff('off')
if result != RESULT_OK:
return result
self.messager.update_node_attributes('status', self.node, POWER_STATE_DB['off'])
start_timeStamp = int(time.time())
for i in range (0,30):
status = self._get_power_state('state')
if status in RPOWER_STATE and RPOWER_STATE[status] == 'off':
break
gevent.sleep( 2 )
end_timeStamp = int(time.time())
if status not in RPOWER_STATE or RPOWER_STATE[status] != 'off':
wait_time = str(end_timeStamp - start_timeStamp)
result = 'Error: Sent power-off command but state did not change ' \
'to off after waiting %s seconds. (State= %s).' % (wait_time, status)
return result
result = self._set_power_onoff('on')
return result
def rflash(self, args):
"""handle rflash command
:param args: subcommands and parameters for rflash
@@ -653,65 +597,293 @@ class OpenBMC(base.BaseDriver):
self.rflash_log_handle.close()
def rpower(self, args):
"""handle rpower command
:param args: subcommands for rpower
"""
subcommand = args[0]
try:
result = self._login()
except xcat_exception.SelfServerException as e:
if subcommand == 'bmcstate':
result = '%s: %s' % (self.node, RPOWER_STATE['NotReady'])
else:
result = '%s: %s' % (self.node, e.message)
except xcat_exception.SelfClientException as e:
result = '%s: %s' % (self.node, e.message)
if result != RESULT_OK:
self.messager.info(result)
return
new_status = ''
if subcommand in POWER_SET_OPTIONS:
result = self._set_power_onoff(subcommand)
if result == RESULT_OK:
result = RPOWER_STATE[subcommand]
new_status = POWER_STATE_DB.get(subcommand, '')
if subcommand in POWER_GET_OPTIONS:
tmp_result = self._get_power_state(subcommand)
result = RPOWER_STATE.get(tmp_result, tmp_result)
if subcommand == 'boot':
result = self._rpower_boot()
if result == RESULT_OK:
result = RPOWER_STATE[subcommand]
new_status = POWER_STATE_DB.get(subcommand, '')
if subcommand == 'reset':
status = self._get_power_state('state')
if status == 'Off' or status == 'chassison':
result = RPOWER_STATE['Off']
else:
result = self._rpower_boot()
if result == RESULT_OK:
result = RPOWER_STATE[subcommand]
new_status = POWER_STATE_DB.get(subcommand, '')
message = '%s: %s' % (self.node, result)
self.messager.info(message)
if new_status:
self.messager.update_node_attributes('status', self.node, new_status)
class OpenBMCManager(base.BaseManager):
def __init__(self, messager, cwd, nodes, envs):
def __init__(self, messager, cwd, nodes=None, envs=None):
super(OpenBMCManager, self).__init__(messager, cwd)
self.nodes = nodes
self.debugmode = (envs and envs.get('debugmode')) or None
#TODO, remove the global variable DEBUGMODE
global DEBUGMODE
DEBUGMODE = envs['debugmode']
if self.debugmode:
logger.setLevel(logging.DEBUG)
def rbeacon(self, nodesinfo, args):
# 1, parse args
rbeacon_usage = """
Usage:
rbeacon [-V|--verbose] [on|off]
Options:
-V --verbose rbeacon verbose mode.
"""
try:
opts = docopt(rbeacon_usage, argv=args)
self.verbose = opts.pop('--verbose')
action = [k for k,v in opts.items() if v][0]
except Exception as e:
self.messager.error("Failed to parse arguments for rbeacon: %s" % args)
return
# 2, validate the args
if action is None:
self.messager.error("Not specify the subcommand for rbeacon")
return
if action not in BEACON_SET_OPTIONS:
self.messager.error("Not supported subcommand for rbeacon: %s" % action)
return
# 3, run the subcommands
runner = OpenBMCBeaconTask(nodesinfo, callback=self.messager, debugmode=self.debugmode, verbose=self.verbose)
DefaultBeaconManager().set_beacon_state(runner, beacon_state=action)
def rinv(self, nodesinfo, args):
# 1, parse agrs
if not args:
args = ['all']
rinv_usage = """
Usage:
rinv [-V|--verbose] [all|cpu|dimm|firm|model|serial]
Options:
-V --verbose rinv verbose mode.
"""
try:
opts = docopt(rinv_usage, argv=args)
self.verbose = opts.pop('--verbose')
action = [k for k,v in opts.items() if v][0]
except Exception as e:
self.messager.error("Failed to parse arguments for rinv: %s" % args)
return
# 2, validate the args
if action not in INVENTORY_OPTIONS:
self.messager.error("Not supported subcommand for rinv: %s" % action)
return
# 3, run the subcommands
runner = OpenBMCInventoryTask(nodesinfo, callback=self.messager, debugmode=self.debugmode, verbose=self.verbose)
if action == 'firm':
DefaultInventoryManager().get_firm_info(runner)
else:
DefaultInventoryManager().get_inventory_info(runner, action)
def rpower(self, nodesinfo, args):
# 1, parse args
rpower_usage = """
Usage:
rpower [-V|--verbose] [on|off|softoff|reset|boot|bmcreboot|bmcstate|stat|state|status]
Options:
-V --verbose rpower verbose mode.
"""
try:
opts=docopt(rpower_usage, argv=args)
self.verbose=opts.pop('--verbose')
action=[k for k,v in opts.items() if v][0]
except Exception as e:
# It will not be here as perl has validation for args
self.messager.error("Failed to parse arguments for rpower: %s" % args)
return
# 2, validate the args
if action not in (POWER_GET_OPTIONS + POWER_SET_OPTIONS + POWER_REBOOT_OPTIONS):
self.messager.error("Not supported subcommand for rpower: %s" % action)
return
# 3, run the subcommands
runner = OpenBMCPowerTask(nodesinfo, callback=self.messager, debugmode=self.debugmode, verbose=self.verbose)
if action == 'bmcstate':
DefaultPowerManager().get_bmc_state(runner)
elif action == 'bmcreboot':
DefaultPowerManager().reboot_bmc(runner)
elif action in POWER_GET_OPTIONS:
DefaultPowerManager().get_power_state(runner)
elif action in POWER_REBOOT_OPTIONS:
DefaultPowerManager().reboot(runner, optype=action)
else:
DefaultPowerManager().set_power_state(runner, power_state=action)
def rspconfig(self, nodesinfo, args):
try:
opts=docopt(RSPCONFIG_USAGE, argv=args)
except DocoptExit as e:
self.messager.error("Failed to parse args by docopt: %s" % e)
return
except Exception as e:
self.messager.error("Failed to parse arguments for rspconfig: %s" % args)
return
self.verbose=opts.pop('--verbose')
runner = OpenBMCBmcConfigTask(nodesinfo, callback=self.messager, debugmode=self.debugmode, verbose=self.verbose)
if opts['dump']:
if opts['--list']:
DefaultBmcConfigManager().dump_list(runner)
elif opts['--generate']:
DefaultBmcConfigManager().dump_generate(runner)
elif opts['--clear']:
DefaultBmcConfigManager().dump_clear(runner, opts['--id'])
elif opts['--download']:
DefaultBmcConfigManager().dump_download(runner, opts['--id'])
else:
DefaultBmcConfigManager().dump_process(runner)
elif opts['gard']:
if opts['--clear']:
DefaultBmcConfigManager().gard_clear(runner)
elif opts['sshcfg']:
DefaultBmcConfigManager().set_sshcfg(runner)
elif opts['ip=dhcp']:
DefaultBmcConfigManager().set_ipdhcp(runner)
elif opts['get']:
unsupport_list=list(set(opts['<args>']) - set(RSPCONFIG_GET_OPTIONS))
if len(unsupport_list) > 0:
self.messager.error("Have unsupported option: %s" % unsupport_list)
return
else:
DefaultBmcConfigManager().get_attributes(runner, opts['<args>'])
elif opts['set']:
rc=0
for attr in opts['<args>']:
k,v = attr.split('=')
if k not in RSPCONFIG_SET_OPTIONS:
self.messager.error("The attribute %s is not support to set" % k)
rc=1
elif not re.match(RSPCONFIG_SET_OPTIONS[k], v):
self.messager.error("The value %s is invalid for %s" %(v, k))
rc=1
if rc:
return
else:
DefaultBmcConfigManager().set_attributes(runner, opts['<args>'])
else:
self.messager.error("Failed to deal with rspconfig: %s" % args)
def rsetboot(self, nodesinfo, args):
# 1, parse args
if not args:
args = ['stat']
rsetboot_usage = """
Usage:
rsetboot [-V|--verbose] [cd|def|default|hd|net|stat] [-p]
Options:
-V --verbose rsetboot verbose mode.
-p persistant boot source.
"""
try:
opts = docopt(rsetboot_usage, argv=args)
self.verbose = opts.pop('--verbose')
action_type = opts.pop('-p')
action = [k for k,v in opts.items() if v][0]
except Exception as e:
self.messager.error("Failed to parse arguments for rsetboot: %s" % args)
return
# 2, validate the args
if action not in (SETBOOT_GET_OPTIONS + SETBOOT_SET_OPTIONS):
self.messager.error("Not supported subcommand for rsetboot: %s" % action)
return
# 3, run the subcommands
runner = OpenBMCBootTask(nodesinfo, callback=self.messager, debugmode=self.debugmode, verbose=self.verbose)
if action in SETBOOT_GET_OPTIONS:
DefaultBootManager().get_boot_state(runner)
else:
DefaultBootManager().set_boot_state(runner, setboot_state=action, persistant=action_type)
def rvitals(self, nodesinfo, args):
# 1, parse agrs
if not args:
args = ['all']
rvitals_usage = """
Usage:
rvitals [-V|--verbose] [all|altitude|fanspeed|leds|power|temp|voltage|wattage]
Options:
-V --verbose rvitals verbose mode.
"""
try:
opts = docopt(rvitals_usage, argv=args)
self.verbose = opts.pop('--verbose')
action = [k for k,v in opts.items() if v][0]
except Exception as e:
self.messager.error("Failed to parse arguments for rvitals: %s" % args)
return
# 2, validate the args
if action not in VITALS_OPTIONS:
self.messager.error("Not supported subcommand for rvitals: %s" % action)
return
# 3, run the subcommands
runner = OpenBMCSensorTask(nodesinfo, callback=self.messager, debugmode=self.debugmode, verbose=self.verbose)
if action == 'leds':
DefaultSensorManager().get_beacon_info(runner)
else:
DefaultSensorManager().get_sensor_info(runner, action)
def reventlog(self, nodesinfo, args):
# 1, parse agrs
if not args:
args = ['all']
reventlog_usage = """
Usage:
reventlog [-V|--verbose] resolved <id_list>
reventlog [-V|--verbose] clear
reventlog [-V|--verbose] list <number_of_records>
Options:
-V --verbose eventlog verbose mode.
"""
try:
opts = docopt(reventlog_usage, argv=args)
self.verbose = opts.pop('--verbose')
action = [k for k,v in opts.items() if v][0]
except Exception as e:
self.messager.error("Failed to parse arguments for reventlog: %s" % args)
return
# 2, validate the args
if action not in EVENTLOG_OPTIONS:
self.messager.error("Not supported subcommand for reventlog: %s" % action)
return
# 3, run the subcommands
runner = OpenBMCEventlogTask(nodesinfo, callback=self.messager, debugmode=self.debugmode, verbose=self.verbose)
self.messager.info('revetlog.py processing action=%s args=%s' % (action, args))
if action == 'clear':
DefaultEventlogManager().clear_all_eventlog_records(runner)
elif action == 'resolved':
eventlog_id_list = opts.pop('<id_list>')
DefaultEventlogManager().resolve_eventlog_records(runner, eventlog_id_list)
elif action == 'list':
eventlog_number_of_records = opts.pop('<number_of_records>')
DefaultEventlogManager().get_eventlog_info(runner, eventlog_number_of_records)
else:
DefaultEventlogManager().get_eventlog_info(runner, "all")
def _get_full_path(self,file_path):
if type(self.cwd) == 'unicode':
dir_path = self.cwd
@@ -807,6 +979,3 @@ class OpenBMCManager(base.BaseManager):
self.nodes, nodeinfo, 'rflash', args)
self._summary(nodes_num, 'Firmware update')
def rpower(self, nodeinfo, args):
super(OpenBMCManager, self).process_nodes_worker('openbmc', 'OpenBMC',
self.nodes, nodeinfo, 'rpower', args)
@@ -3,8 +3,8 @@ import requests
import json
import time
import rest
import xcat_exception
from common import rest
from common import exceptions as xcat_exception
class OpenBMCRest:
@@ -1,41 +0,0 @@
#!/usr/bin/env python
import requests
from gevent.subprocess import Popen, PIPE
import urllib3
urllib3.disable_warnings()
import xcat_exception
class RestSession :
def __init__(self):
self.session = requests.Session()
self.cookies = None
def request (self, method, url, headers, data):
try:
response = self.session.request(method, url,
data=data,
headers=headers,
verify=False,
timeout=30)
except requests.exceptions.ConnectionError:
raise xcat_exception.SelfServerException(
'Error: BMC did not respond. ' \
'Validate BMC configuration and retry the command.')
except requests.exceptions.Timeout:
raise xcat_exception.SelfServerException('Error: Timeout to connect to server')
if not self.cookies:
self.cookies = requests.utils.dict_from_cookiejar(self.session.cookies)
return response
def request_upload (self, method, url, headers, files):
request_cmd = 'curl -k -b sid=%s -H "%s" -X %s -T %s %s -s' % \
(self.cookies['sid'], headers, method, files, url)
sub = Popen(request_cmd, stdout=PIPE, shell=True)
response, err = sub.communicate()
return response
@@ -9,7 +9,7 @@ import traceback
from gevent import socket
from gevent.server import StreamServer
from gevent.lock import BoundedSemaphore
from xcatagent import utils
from common import utils
from xcatagent import base as xcat_manager
MSG_TYPE = 'message'
@@ -17,7 +17,7 @@ DB_TYPE = 'db'
LOCK_FILE = '/var/lock/xcat/agent.lock'
class Messager(object):
class XCATMessager(utils.Messager):
def __init__(self, sock):
self.sock = sock
self.sem = BoundedSemaphore(1)
@@ -36,8 +36,8 @@ class Messager(object):
d = {'type': MSG_TYPE, 'msg': {'type': 'warning', 'data': msg}}
self._send(d)
def error(self, msg):
d = {'type': MSG_TYPE, 'msg': {'type': 'error', 'data': msg}}
def error(self, msg, node=''):
d = {'type': MSG_TYPE, 'msg': {'type': 'error', 'node': node, 'data': msg}}
self._send(d)
def syslog(self, msg):
@@ -68,7 +68,7 @@ class Server(object):
def _handle(self, sock, address):
try:
messager = Messager(sock)
messager = XCATMessager(sock)
buf = sock.recv(4)
sz = utils.bytes2int(buf)
buf = utils.recv_all(sock, sz)
@@ -92,14 +92,24 @@ class Server(object):
if not hasattr(manager, req['command']):
messager.error("command %s is not supported" % req['command'])
func = getattr(manager, req['command'])
# translate unicode string to normal string to avoid docopt error
new_args=[]
if req['args']:
for a in req['args']:
new_args.append(a.encode('utf-8'))
# call the function in the specified manager
func(req['nodeinfo'], req['args'])
func(req['nodeinfo'], new_args)
# after the method returns, the request should be handled
# completely, close the socket for client
if not self.standalone:
sock.close()
self.server.stop()
os._exit(0)
except ImportError:
messager.error("xCAT mgt=openbmc is using a Python based framework and there are some dependencies that are not met.")
print(traceback.format_exc(), file=sys.stderr)
self.server.stop()
os._exit(1)
except Exception:
print(traceback.format_exc(), file=sys.stderr)
self.server.stop()
@@ -1,49 +0,0 @@
import struct
import sys
import inspect
def int2bytes(num):
return struct.pack('i', num)
def bytes2int(buf):
return struct.unpack('i', buf)[0]
def get_classes(module_name):
ret = []
for name, obj in inspect.getmembers(sys.modules[module_name]):
if inspect.isclass(obj):
ret.append(obj)
return ret
def class_func(module_name, class_name):
func = getattr(sys.modules[module_name], class_name)
return func
def recv_all(sock, size):
recv_size = 4096
buf_size = 0
buf_parts = []
while buf_size < size:
tmp_size = recv_size
left_size = size - buf_size
if left_size < recv_size:
tmp_size = left_size
buf_part = sock.recv(tmp_size)
buf_parts.append(buf_part)
buf_size += len(buf_part)
buf = ''.join(buf_parts)
return buf
def update2Ddict(updata_dict, key_a, key_b, value):
if key_a in updata_dict:
updata_dict[key_a].update({key_b: value})
else:
updata_dict.update({key_a: {key_b: value}})
+7 -1
View File
@@ -30,11 +30,17 @@ xCAT-openbmc-py provides openbmc related functions.
rm -rf $RPM_BUILD_ROOT
install -d $RPM_BUILD_ROOT/%{prefix}/lib/python/agent
install -d $RPM_BUILD_ROOT/%{prefix}/lib/python/agent/xcatagent
install -d $RPM_BUILD_ROOT/%{prefix}/lib/python/agent/common
install -d $RPM_BUILD_ROOT/%{prefix}/lib/python/agent/hwctl
install -d $RPM_BUILD_ROOT/%{prefix}/lib/python/agent/hwctl/executor
install -m755 lib/python/agent/*.py $RPM_BUILD_ROOT/%{prefix}/lib/python/agent
install -m644 lib/python/agent/xcatagent/*.py $RPM_BUILD_ROOT/%{prefix}/lib/python/agent/xcatagent
install -m644 lib/python/agent/common/*.py $RPM_BUILD_ROOT/%{prefix}/lib/python/agent/common
install -m644 lib/python/agent/hwctl/*.py $RPM_BUILD_ROOT/%{prefix}/lib/python/agent/hwctl
install -m644 lib/python/agent/hwctl/executor/*.py $RPM_BUILD_ROOT/%{prefix}/lib/python/agent/hwctl/executor
%ifnos linux
rm -rf $RPM_BUILD_ROOT/%{prefix}/lib/python
rm -rf $RPM_BUILD_ROOT/%{prefix}/lib/python/agent
%endif
%clean
+375 -13
View File
@@ -10,6 +10,7 @@ BEGIN
use lib "$::XCATROOT/lib/perl";
use strict;
use warnings "all";
use File::Copy qw(move);
use HTTP::Request;
use HTTP::Headers;
@@ -20,8 +21,11 @@ use IO::Socket::SSL qw( SSL_VERIFY_PEER );
my $go_api_port = 12429;
my $go_cons_port = 12430;
my $bmc_cons_port = "2200";
my $isSN = xCAT::Utils->isServiceNode();
use constant CONSOLE_LOG_DIR => "/var/log/consoles";
use constant PRINT_FORMAT => "%-32s %-32s %s";
unless (-d CONSOLE_LOG_DIR) {
mkpath(CONSOLE_LOG_DIR, 0, 0755);
}
@@ -54,11 +58,210 @@ sub http_request {
return "";
}
sub gen_request_data {
my ($cons_map, $siteondemand, $callback) = @_;
my (@openbmc_nodes, $data);
while (my ($k, $v) = each %{$cons_map}) {
my $ondemand;
if ($siteondemand) {
$ondemand = \1;
} else {
$ondemand = \0;
}
my $cmd;
my $cmeth = $v->{cons};
if ($cmeth eq "openbmc") {
push @openbmc_nodes, $k;
} else {
$cmd = $::XCATROOT . "/share/xcat/cons/$cmeth"." ".$k;
if (!(!$isSN && $v->{conserver} && xCAT::NetworkUtils->thishostisnot($v->{conserver}))) {
my $env;
my $locerror = $isSN ? "PERL_BADLANG=0 " : '';
if (defined($ENV{'XCATSSLVER'})) {
$env = "XCATSSLVER=$ENV{'XCATSSLVER'} ";
}
$cmd = $locerror.$env.$cmd;
}
$data->{$k}->{driver} = "cmd";
$data->{$k}->{params}->{cmd} = $cmd;
$data->{$k}->{name} = $k;
}
if (defined($v->{consoleondemand})) {
# consoleondemand attribute for node can be "1", "yes", "0" and "no"
if (($v->{consoleondemand} eq "1") || lc($v->{consoleondemand}) eq "yes") {
$ondemand = \1;
}
elsif (($v->{consoleondemand} eq "0") || lc($v->{consoleondemand}) eq "no") {
$ondemand = \0;
}
}
$data->{$k}->{ondemand} = $ondemand;
}
if (@openbmc_nodes) {
my $passwd_table = xCAT::Table->new('passwd');
my $passwd_hash = $passwd_table->getAttribs({ 'key' => 'openbmc' }, qw(username password));
$passwd_table->close();
my $openbmc_table = xCAT::Table->new('openbmc');
my $openbmc_hash = $openbmc_table->getNodesAttribs(\@openbmc_nodes, ['bmc','consport', 'username', 'password']);
$openbmc_table->close();
foreach my $node (@openbmc_nodes) {
if (defined($openbmc_hash->{$node}->[0])) {
if (!$openbmc_hash->{$node}->[0]->{'bmc'}) {
if($callback) {
xCAT::SvrUtils::sendmsg("Error: Unable to get attribute bmc", $callback, $node);
} else {
xCAT::MsgUtils->message("S", "$node: Error: Unable to get attribute bmc");
}
delete $data->{$node};
next;
}
$data->{$node}->{params}->{host} = $openbmc_hash->{$node}->[0]->{'bmc'};
if ($openbmc_hash->{$node}->[0]->{'username'}) {
$data->{$node}->{params}->{user} = $openbmc_hash->{$node}->[0]->{'username'};
} elsif ($passwd_hash and $passwd_hash->{username}) {
$data->{$node}->{params}->{user} = $passwd_hash->{username};
} else {
if ($callback) {
xCAT::SvrUtils::sendmsg("Error: Unable to get attribute username", $callback, $node)
} else {
xCAT::MsgUtils->message("S", "$node: Error: Unable to get attribute username");
}
delete $data->{$node};
next;
}
if ($openbmc_hash->{$node}->[0]->{'password'}) {
$data->{$node}->{params}->{password} = $openbmc_hash->{$node}->[0]->{'password'};
} elsif ($passwd_hash and $passwd_hash->{password}) {
$data->{$node}->{params}->{password} = $passwd_hash->{password};
} else {
if ($callback) {
xCAT::SvrUtils::sendmsg("Error: Unable to get attribute password", $callback, $node)
} else {
xCAT::MsgUtils->message("S", "$node: Error: Unable to get attribute password");
}
delete $data->{$node};
next;
}
if ($openbmc_hash->{$node}->[0]->{'consport'}) {
$data->{$node}->{params}->{consport} = $openbmc_hash->{$node}->[0]->{'consport'};
} else {
$data->{$node}->{params}->{port} = $bmc_cons_port;
}
$data->{$node}->{name} = $node;
$data->{$node}->{driver} = "ssh";
}
}
}
return $data;
}
#-------------------------------------------------------------------------------
=head3 init_local_console
Init console nodes on service node locally.
Globals:
none
Example:
my $ready=(xCAT::Goconserver::init_local_console()
Comments:
none
=cut
#-------------------------------------------------------------------------------
sub init_local_console {
my @hostinfo = xCAT::NetworkUtils->determinehostname();
my %iphash = ();
my %cons_map;
my $ret;
my $host = $hostinfo[-1];
foreach (@hostinfo) {
$iphash{$_} = 1;
}
my $retry = 0;
my $api_url = "https://$host:". get_api_port();
my $response = http_request("GET", $api_url."/nodes");
while(!defined($response) && $retry < 3) {
$response = http_request("GET", $api_url."/nodes");
$retry ++;
sleep 1;
}
if (!defined($response)) {
xCAT::MsgUtils->message("S", "Could not connect to goconserver after trying 3 times.");
return;
}
if ($response->{nodes}->[0]) {
# node data exist, maybe this is not diskless sn.
return;
}
my $nodehmtab = xCAT::Table->new('nodehm', -create => 1);
if (!$nodehmtab) {
return;
}
my @cons_nodes = $nodehmtab->getAllNodeAttribs([ 'node', 'cons', 'serialport', 'mgt', 'conserver', 'consoleondemand', 'consoleenabled' ]);
$nodehmtab->close();
my @nodes = ();
foreach (@cons_nodes) {
if ($_->{consoleenabled} && ($_->{cons} or defined($_->{'serialport'}))) {
unless ($_->{cons}) {
$_->{cons} = $_->{mgt};
}
if ($_->{conserver} && exists($iphash{ $_->{conserver} })) {
$cons_map{ $_->{node} } = $_;
}
}
}
my @entries = xCAT::TableUtils->get_site_attribute("consoleondemand");
my $site_entry = $entries[0];
my $siteondemand = 0;
if (defined($site_entry)) {
if (lc($site_entry) eq "yes") {
$siteondemand = 1;
}
elsif (lc($site_entry) ne "no") {
xCAT::MsgUtils->message("S", $host.": Unexpected value $site_entry for consoleondemand attribute in site table");
}
}
my $data = gen_request_data(\%cons_map, $siteondemand, 1, undef);
if (! $data) {
xCAT::MsgUtils->message("S", $host.": Could not generate the request data");
return;
}
if (create_nodes($api_url, $data, undef)) {
xCAT::MsgUtils->message("S", $host.": Failed to create console entry in goconserver. ");
}
}
sub disable_nodes_in_db {
my $nodes = shift;
my $nodehmtab = xCAT::Table->new('nodehm', -create => 1);
if (!$nodehmtab) {
return 1;
}
my $updateattribs->{consoleenabled} = undef;
$nodehmtab->setNodesAttribs($nodes, $updateattribs);
$nodehmtab->close();
return 0;
}
sub enable_nodes_in_db {
my $nodes = shift;
my $nodehmtab = xCAT::Table->new('nodehm', -create => 1);
if (!$nodehmtab) {
return 1;
}
my $updateattribs->{consoleenabled} = '1';
$nodehmtab->setNodesAttribs($nodes, $updateattribs);
$nodehmtab->close();
return 0;
}
sub delete_nodes {
my ($api_url, $node_map, $delmode, $callback) = @_;
my $url = "$api_url/bulk/nodes";
my @a = ();
my ($data, $rsp, $ret);
my ($data, $rsp, $ret, @update_nodes);
$data->{nodes} = \@a;
foreach my $node (keys %{$node_map}) {
my $temp;
@@ -68,18 +271,39 @@ sub delete_nodes {
$ret = 0;
my $response = http_request("DELETE", $url, $data);
if (!defined($response)) {
$rsp->{data}->[0] = "Failed to send delete request.";
xCAT::MsgUtils->message("E", $rsp, $callback);
if ($callback) {
$rsp->{data}->[0] = "Failed to send delete request.";
xCAT::MsgUtils->message("E", $rsp, $callback)
} else {
xCAT::MsgUtils->message("S", "Failed to send delete request.");
}
return 1;
} elsif ($delmode) {
while (my ($k, $v) = each %{$response}) {
if ($v ne "Deleted") {
$rsp->{data}->[0] = "$k: Failed to delete entry in goconserver: $v";
xCAT::MsgUtils->message("E", $rsp, $callback);
if ($callback) {
$rsp->{data}->[0] = "$k: Failed to delete entry in goconserver: $v";
xCAT::MsgUtils->message("E", $rsp, $callback)
} else {
xCAT::MsgUtils->message("S", "$k: Failed to delete entry in goconserver: $v");
}
$ret = 1;
} else {
$rsp->{data}->[0] = "$k: $v";
xCAT::MsgUtils->message("I", $rsp, $callback);
if ($callback) {
$rsp->{data}->[0] = "$k: $v";
xCAT::MsgUtils->message("I", $rsp, $callback);
}
push(@update_nodes, $k);
}
}
}
if (@update_nodes) {
if (disable_nodes_in_db(\@update_nodes)) {
if ($callback) {
$rsp->{data}->[0] = "Failed to update consoleenabled status in db.";
xCAT::MsgUtils->message("E", $rsp, $callback);
} else {
xCAT::MsgUtils->message("S", "Failed to update consoleenabled status in db.");
}
}
}
@@ -89,7 +313,7 @@ sub delete_nodes {
sub create_nodes {
my ($api_url, $node_map, $callback) = @_;
my $url = "$api_url/bulk/nodes";
my ($data, $rsp, @a, $ret);
my ($data, $rsp, @a, $ret, @update_nodes);
$data->{nodes} = \@a;
while (my ($k, $v) = each %{$node_map}) {
push @a, $v;
@@ -97,24 +321,158 @@ sub create_nodes {
$ret = 0;
my $response = http_request("POST", $url, $data);
if (!defined($response)) {
$rsp->{data}->[0] = "Failed to send create request.";
xCAT::MsgUtils->message("E", $rsp, $callback);
if ($callback) {
$rsp->{data}->[0] = "Failed to send create request.";
xCAT::MsgUtils->message("E", $rsp, $callback)
} else {
xCAT::MsgUtils->message("S", "Failed to send create request.");
}
return 1;
} elsif ($response) {
while (my ($k, $v) = each %{$response}) {
if ($v ne "Created") {
$rsp->{data}->[0] = "$k: Failed to create console entry in goconserver: $v";
xCAT::MsgUtils->message("E", $rsp, $::callback);
if ($callback) {
$rsp->{data}->[0] = "$k: Failed to create console entry in goconserver: $v";
xCAT::MsgUtils->message("E", $rsp, $callback);
} else {
xCAT::MsgUtils->message("S", "$k: Failed to create console entry in goconserver: $v");
}
$ret = 1;
} else {
$rsp->{data}->[0] = "$k: $v";
xCAT::MsgUtils->message("I", $rsp, $::callback);
xCAT::MsgUtils->message("I", $rsp, $callback) if $callback;
push(@update_nodes, $k);
}
}
}
if (@update_nodes) {
if (enable_nodes_in_db(\@update_nodes)) {
if ($callback) {
$rsp->{data}->[0] = "Failed to update consoleenabled status in db.";
xCAT::MsgUtils->message("E", $rsp, $callback);
} else {
CAT::MsgUtils->message("S", "Failed to update consoleenabled status in db.");
}
}
}
return $ret;
}
sub list_nodes {
my ($api_url, $node_map, $callback) = @_;
my $url = "$api_url/nodes";
my $rsp;
my $response = http_request("GET", $url);
if (!defined($response)) {
$rsp->{data}->[0] = "Failed to send list request.";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 1;
}
if (!$response->{nodes}) {
$rsp->{data}->[0] = "Could not find any node.";
xCAT::MsgUtils->message("I", $rsp, $callback);
return 0;
}
$rsp->{data}->[0] = sprintf("\n".PRINT_FORMAT, "NODE", "SERVER", "STATE");
xCAT::MsgUtils->message("I", $rsp, $callback);
foreach my $node (sort {$a->{name} cmp $b->{name}} @{$response->{nodes}}) {
if (!$node_map->{$node->{name}}) {
next;
}
$node_map->{$node->{name}}->{vis} = 1;
if (!$node->{host} || !$node->{state}) {
$rsp->{data}->[0] = sprintf(PRINT_FORMAT, $node->{name}, "", "Unable to parse the response message");
xCAT::MsgUtils->message("E", $rsp, $callback);
next;
}
$rsp->{data}->[0] = sprintf(PRINT_FORMAT, $node->{name}, $node->{host}, substr($node->{state}, 0, 16));
xCAT::MsgUtils->message("I", $rsp, $callback);
}
my %node_hash = %{$node_map};
for my $node (sort keys %node_hash) {
if(!$node_hash{$node}->{vis}) {
$rsp->{data}->[0] = sprintf(PRINT_FORMAT, $node, "", "unregistered");
xCAT::MsgUtils->message("I", $rsp, $callback);
}
}
return 0;
}
sub cleanup_nodes {
my $callback = shift;
my @hostinfo = xCAT::NetworkUtils->determinehostname();
my $host = $hostinfo[-1];
my $api_url = "https://$host:". get_api_port();
my $rsp;
my $response = http_request("GET", "$api_url/nodes");
if (!defined($response)) {
if ($callback) {
$rsp->{data}->[0] = "Failed to send list request.";
xCAT::MsgUtils->message("E", $rsp, $callback);
} else {
xCAT::MsgUtils->message("S", "Failed to send list request.");
}
return 1;
}
if (!$response->{nodes}) {
return 0;
}
my %delete_map;
my %cons_map = get_cons_map(undef);
foreach my $node (@{$response->{nodes}}) {
# not in xcatdb but exist in goconserver
$delete_map{$node->{name}} = 1 if !exists($cons_map{$node->{name}});
}
return delete_nodes($api_url, \%delete_map, 1, $callback);
}
sub get_cons_map {
my $req = shift;
my %iphash = ();
my %cons_map;
my $hmtab = xCAT::Table->new('nodehm');
my @cons_nodes;
my @hostinfo = xCAT::NetworkUtils->determinehostname();
foreach (@hostinfo) {
$iphash{$_} = 1;
}
if (defined($req) && (($req->{node} and @{$req->{node}} > 0) or $req->{noderange}->[0])) {
# Note: do not consider terminal server currently
@cons_nodes = $hmtab->getNodesAttribs($req->{node}, [ 'node', 'cons', 'serialport', 'mgt', 'conserver', 'consoleondemand' ]);
# Adjust the data structure to make the result consistent with the getAllNodeAttribs() call we make if a noderange was not specified
my @tmpcons_nodes;
foreach my $ent (@cons_nodes)
{
foreach my $nodeent (keys %$ent)
{
push @tmpcons_nodes, $ent->{$nodeent}->[0];
}
}
@cons_nodes = @tmpcons_nodes
} else {
@cons_nodes = $hmtab->getAllNodeAttribs([ 'cons', 'serialport', 'mgt', 'conserver', 'consoleondemand' ]);
}
$hmtab->close();
my $rsp;
foreach (@cons_nodes) {
if ($_->{cons} or defined($_->{'serialport'})) {
unless ($_->{cons}) { $_->{cons} = $_->{mgt}; } #populate with fallback
if ($isSN && $_->{conserver} && exists($iphash{ $_->{conserver} }) || !$isSN) {
$cons_map{ $_->{node} } = $_; # also put the ref to the entry in a hash for quick look up
} else {
$rsp->{data}->[0] = $_->{node} .": ignore, the host for conserver could not be determined.";
xCAT::MsgUtils->message("I", $rsp, $::callback);
}
} else {
$rsp->{data}->[0] = $_->{node} .": ignore, cons attribute or serialport attribute is not specified.";
xCAT::MsgUtils->message("I", $rsp, $::callback);
}
}
return %cons_map;
}
#-------------------------------------------------------------------------------
=head3 is_xcat_conf_ready
@@ -218,6 +576,8 @@ sub is_conserver_running {
#-------------------------------------------------------------------------------
sub build_conf {
# try to backup the original configuration file, no matter sunccess or not
move('/etc/goconserver/server.conf', '/etc/goconserver/server.conf.bak');
my $config = "#generated by xcat ".xCAT::Utils->Version()."\n".
"global:\n".
" host: 0.0.0.0\n".
@@ -231,6 +591,8 @@ sub build_conf {
" datadir: /var/lib/goconserver/ # the data file to save the hosts\n".
" port: $go_cons_port # the port for console\n".
" log_timestamp: true # log the timestamp at the beginning of line\n".
" # time precison for tcp or udp logger, precison for file logger is always second\n".
" time_precision: microsecond # Valid options: second, millisecond, microsecond, nanosecond\n".
" reconnect_interval: 10 # retry interval in second if console could not be connected\n".
" logger: # multiple logger targets could be specified\n".
" file: # file logger, valid fields: name,logdir. Accept array in yaml format\n".
+74 -10
View File
@@ -22,6 +22,7 @@ use File::Path;
use Fcntl ":flock";
use IO::Socket::UNIX qw( SOCK_STREAM );
use xCAT_monitoring::monitorctrl;
use xCAT::TableUtils;
my $LOCK_DIR = "/var/lock/xcat/";
my $LOCK_PATH = "/var/lock/xcat/agent.lock";
@@ -70,19 +71,19 @@ sub acquire_lock {
}
sub start_python_agent {
if (! -e $PYTHON_AGENT_FILE) {
xCAT::MsgUtils->message("S", "'$PYTHON_AGENT_FILE' does not exist");
xCAT::MsgUtils->message("S", "start_python_agent() Error: '$PYTHON_AGENT_FILE' does not exist");
return undef;
}
if (!defined(acquire_lock())) {
xCAT::MsgUtils->message("S", "Error: Faild to require lock");
xCAT::MsgUtils->message("S", "start_python_agent() Error: Failed to acquire lock");
return undef;
}
my $fd;
open($fd, '>', $AGENT_SOCK_PATH) && close($fd);
my $pid = fork;
if (!defined $pid) {
xCAT::MsgUtils->message("S", "Error: Unable to fork process");
xCAT::MsgUtils->message("S", "start_python_agent() Error: Unable to fork process");
return undef;
}
$SIG{CHLD} = 'DEFAULT';
@@ -93,7 +94,7 @@ sub start_python_agent {
open(STDERR, '>>&', \*STDOUT) or die("open: $!");
my $ret = exec ($PYTHON_AGENT_FILE);
if (!defined($ret)) {
xCAT::MsgUtils->message("S", "Error: Failed to start python agent");
xCAT::MsgUtils->message("S", "start_python_agent() Error: Failed to start the xCAT Python agent.");
exit(1);
}
}
@@ -109,7 +110,7 @@ sub handle_message {
} elsif ($msg->{type} eq 'warning') {
xCAT::MsgUtils->message("W", { data => [$msg->{data}] }, $callback);
} elsif ($msg->{type} eq 'error'){
xCAT::MsgUtils->message("E", { data => [$msg->{data}] }, $callback);
xCAT::SvrUtils::sendmsg([ 1, $msg->{data} ], $callback, $msg->{node});
} elsif ($msg->{type} eq 'syslog'){
xCAT::MsgUtils->message("S", $msg->{data});
}
@@ -194,14 +195,20 @@ sub wait_agent {
my ($pid, $callback) = @_;
waitpid($pid, 0);
if ($? >> 8 != 0) {
xCAT::MsgUtils->message("E", { data => ["python agent exited unexpectedly"] }, $callback);
xCAT::MsgUtils->message("E", { data => ["python agent exited unexpectedly. See $PYTHON_LOG_PATH for more details."] }, $callback);
}
}
sub is_openbmc_python {
my $environment = shift;
$environment = shift if (($environment) && ($environment =~ /OPENBMC/));
# If XCAT_OPENBMC_PYTHON is YES, will run openbmc2.pm. If not, run openbmc.pm
# If XCAT_OPENBMC_PYTHON is YES,
# will return "ALL" and caller will run openbmc2.pm.
# If XCAT_OPENBMC_PYTHON is not set or is set to NO, return "NO" and caller
# will run openbmc.pm
# If XCAT_OPENBMC_PYTHON is a list of commands, return that list and caller
# will run openbmc2.pm if the command is on the list, caller will run
# openbmc.pm if command is not on the list
if (ref($environment) eq 'ARRAY' and ref($environment->[0]->{XCAT_OPENBMC_PYTHON}) eq 'ARRAY') {
$::OPENBMC_PYTHON = $environment->[0]->{XCAT_OPENBMC_PYTHON}->[0];
} elsif (ref($environment) eq 'ARRAY') {
@@ -209,11 +216,68 @@ sub is_openbmc_python {
} else {
$::OPENBMC_PYTHON = $environment->{XCAT_OPENBMC_PYTHON};
}
if (defined($::OPENBMC_PYTHON) and $::OPENBMC_PYTHON eq "YES") {
return 1;
if (defined($::OPENBMC_PYTHON)) {
if ($::OPENBMC_PYTHON eq "YES") {
return "ALL";
}
elsif ($::OPENBMC_PYTHON eq "NO") {
return "NO";
}
else {
return $::OPENBMC_PYTHON;
}
}
return 0;
return "NO";
}
#--------------------------------------------------------------------------------
=head3 is_support_in_perl
check if specified command is included in site attribute openbmcperl
The policy is:
Get value from `openbmcperl`, `XCAT_OPENBMC_DEVEL`, agent.py:
1. If agent.py not exist: ==>Go Perl
2. If `openbmcperl` not set or not include a command:
if `XCAT_OPENBMC_DEVEL` set to `NO`: ==> Go Perl
else if set to `YES` or not set: ==> Go Python
3. If `openbmcperl` set and include a command
if `XCAT_OPENBMC_DEVEL` set to `YES`: == >Go Python
else ==> Go Perl
=cut
#--------------------------------------------------------------------------------
sub is_support_in_perl {
my ($class, $command, $env) = @_;
if (! -e $PYTHON_AGENT_FILE) {
return (1, '');
}
my @entries = xCAT::TableUtils->get_site_attribute("openbmcperl");
my $site_entry = $entries[0];
my $support_obmc = undef;
if (ref($env) eq 'ARRAY' and ref($env->[0]->{XCAT_OPENBMC_DEVEL}) eq 'ARRAY') {
$support_obmc = $env->[0]->{XCAT_OPENBMC_DEVEL}->[0];
} elsif (ref($env) eq 'ARRAY') {
$support_obmc = $env->[0]->{XCAT_OPENBMC_DEVEL};
} else {
$support_obmc = $env->{XCAT_OPENBMC_DEVEL};
}
if ($support_obmc and $support_obmc ne 'YES' and $support_obmc ne 'NO') {
return (-1, "Value $support_obmc is invalid for XCAT_OPENBMC_DEVEL, only support 'YES' and 'NO'");
}
if ($site_entry and $site_entry =~ $command) {
if ($support_obmc and $support_obmc eq 'YES') {
return (0, '');
} else {
return (1, '');
}
} else {
if ($support_obmc and $support_obmc eq 'NO') {
return (1, '');
} else {
return (0, '');
}
}
}
1;
+18 -6
View File
@@ -469,13 +469,25 @@ sub get_file_name {
elsif (($genos) && (-r "$searchpath/$profile.$genos.$extension")) {
return "$searchpath/$profile.$genos.$extension";
}
elsif (-r "$searchpath/$profile.$osbase.$arch.$extension") {
return "$searchpath/$profile.$osbase.$arch.$extension";
# If the osimge name was specified with -n, the name might contain multiple "."
# Chop them off one at a time until filename match is found
else {
while ($dotpos > 0) {
if (-r "$searchpath/$profile.$osbase.$arch.$extension") {
return "$searchpath/$profile.$osbase.$arch.$extension";
}
elsif (-r "$searchpath/$profile.$osbase.$extension") {
return "$searchpath/$profile.$osbase.$extension";
}
# Chop off "." from the end and try again
$dotpos = rindex($osbase, ".");
$osbase = substr($osbase, 0, $dotpos);
}
}
elsif (-r "$searchpath/$profile.$osbase.$extension") {
return "$searchpath/$profile.$osbase.$extension";
}
elsif (-r "$searchpath/$profile.$arch.$extension") {
# No file matching OS name was found, next try just arch, if still nothing -> default to just profile
if (-r "$searchpath/$profile.$arch.$extension") {
return "$searchpath/$profile.$arch.$extension";
}
elsif (-r "$searchpath/$profile.$extension") {
+1
View File
@@ -587,6 +587,7 @@ sub setup_GOCONS
xCAT::MsgUtils->message("S", "Error: failed to start goconserver service.");
return 1;
}
xCAT::Goconserver::init_local_console();
return 0;
}
@@ -4423,6 +4423,12 @@ sub defrm
command => ['makeconservercf'],
node => [@allnodes],
arg => ['-d'],}, $doreq, 0, 1);
if (-x "/usr/bin/goconserver") {
require xCAT::Goconserver;
if (xCAT::Goconserver::is_goconserver_running()) {
xCAT::Goconserver::cleanup_nodes(undef);
}
}
}
}
+5 -1
View File
@@ -36,13 +36,17 @@ sub process_request {
$arptable = `/sbin/arp -n`;
}
my @arpents = split /\n/, $arptable;
my $mac = "$req->{mtm}->[0]*$req->{serial}->[0]";
my $mac;
foreach (@arpents) {
if (m/^($client_ip)\s+\S+\s+(\S+)\s/) {
$mac = $2;
last;
}
}
unless ($mac) {
xCAT::MsgUtils->message("S", "xcat.discovery.aaadiscovery: Failed to get MAC address for $client_ip in arp cache.");
$mac = "$req->{mtm}->[0]*$req->{serial}->[0]";
}
xCAT::MsgUtils->message("S", "xcat.discovery.aaadiscovery: ($mac) Got a discovery request, attempting to discover the node...");
$req->{discoverymethod}->[0] = 'undef';
+1 -2
View File
@@ -1130,8 +1130,6 @@ sub bmcdiscovery_ipmi {
}
display_output($opz,$opw,$mtms_node,$mac_node,$node_data,"ipmi",$request_command);
} else {
store_fd({data=>0}, $fd);
}
}
@@ -1156,6 +1154,7 @@ sub bmcdiscovery_openbmc{
my $mtms_node = "";
my $mac_node = "";
store_fd({data=>1}, $fd);
print "$ip: Detected openbmc, attempting to obtain system information...\n";
my $http_protocol="https";
my $openbmc_project_url = "xyz/openbmc_project";
+14 -3
View File
@@ -59,6 +59,7 @@ my $dhcpconffile = $^O eq 'aix' ? '/etc/dhcpsd.cnf' : '/etc/dhcpd.conf';
my %dynamicranges; #track dynamic ranges defined to see if a host that resolves is actually a dynamic address
my %netcfgs;
my $distro = xCAT::Utils->osver();
my $checkdomain=0;
# dhcp 4.x will use /etc/dhcp/dhcpd.conf as the config file
my $dhcp6conffile;
@@ -1931,6 +1932,14 @@ sub process_request
addnet($line[0], $line[2]);
}
}
if ($checkdomain)
{
$callback->({ error => [ "above error fail to generate new dhcp configuration file, restore dhcp configuration file $dhcpconffile" ], errorcode => [1] });
my $backupfile = $dhcpconffile.".xcatbak";
rename("$backupfile", $dhcpconffile);
xCAT::MsgUtils->trace($verbose_on_off, "d", "dhcp: Restore dhcp configuration file to $dhcpconffile");
exit 1;
}
foreach (@nrn6) { #do the ipv6 networks
addnet6($_); #already did all the filtering before putting into nrn6
}
@@ -2440,10 +2449,12 @@ sub addnet
} else {
$callback->(
{
warning => [
"No $net specific entry for domain, and no domain defined in site table."
]
error => [
"No domain defined for $net entry in networks table, and no domain defined in site table."
],
errorcode => [1]
});
$checkdomain=1;
}
if ($ent and $ent->{nameservers})
+27 -140
View File
@@ -17,10 +17,11 @@ use Data::Dumper;
my $isSN;
my $host;
my $bmc_cons_port = "2200";
my $usage_string =" makegocons [-V|--verbose] [-d|--delete] noderange
-h|--help Display this usage statement.
-v|--version Display the version number.";
-h|--help Display this usage statement.
-v|--version Display the version number.
-C|--cleanup Remove the entries for the nodes whose definitions have been removed from xCAT db.
-q|--query [noderange] Display the console connection status.";
my $version_string = xCAT::Utils->Version();
@@ -86,13 +87,17 @@ sub preprocess_request {
my $hmcache = $hmtab->getNodesAttribs($noderange, [ 'node', 'serialport', 'cons', 'conserver' ]);
foreach my $node (@$noderange) {
my $ent = $hmcache->{$node}->[0]; #$hmtab->getNodeAttribs($node,['node', 'serialport','cons', 'conserver']);
push @items, $ent;
if ($ent) {
push (@items, $ent);
} else {
my $rsp->{data}->[0] = $node .": ignore, cons attribute or serialport attribute is not specified.";
xCAT::MsgUtils->message("I", $rsp, $::callback);
}
}
} else {
$allnodes = 1;
@items = $hmtab->getAllNodeAttribs([ 'node', 'serialport', 'cons', 'conserver' ]);
}
my @nodes = ();
foreach (@items) {
if (((!defined($_->{cons})) || ($_->{cons} eq "")) and !defined($_->{serialport})) {
@@ -134,135 +139,6 @@ sub process_request {
}
}
sub get_cons_map {
my ($req, $iphashref) = @_;
my %cons_map;
my %iphash = %{$iphashref};
my $hmtab = xCAT::Table->new('nodehm');
my @cons_nodes;
if (($req->{node} and @{$req->{node}} > 0) or $req->{noderange}->[0]) {
# Note: do not consider terminal server currently
@cons_nodes = $hmtab->getNodesAttribs($req->{node}, [ 'node', 'cons', 'serialport', 'mgt', 'conserver', 'consoleondemand' ]);
# Adjust the data structure to make the result consistent with the getAllNodeAttribs() call we make if a noderange was not specified
my @tmpcons_nodes;
foreach my $ent (@cons_nodes)
{
foreach my $nodeent (keys %$ent)
{
push @tmpcons_nodes, $ent->{$nodeent}->[0];
}
}
@cons_nodes = @tmpcons_nodes
} else {
@cons_nodes = $hmtab->getAllNodeAttribs([ 'cons', 'serialport', 'mgt', 'conserver', 'consoleondemand' ]);
}
$hmtab->close();
my $rsp;
foreach (@cons_nodes) {
if ($_->{cons} or defined($_->{'serialport'})) {
unless ($_->{cons}) { $_->{cons} = $_->{mgt}; } #populate with fallback
if ($isSN && $_->{conserver} && exists($iphash{ $_->{conserver} }) || !$isSN) {
$cons_map{ $_->{node} } = $_; # also put the ref to the entry in a hash for quick look up
} else {
$rsp->{data}->[0] = $_->{node} .": ignore, the host for conserver could not be determined.";
xCAT::MsgUtils->message("I", $rsp, $::callback);
}
} else {
$rsp->{data}->[0] = $_->{node} .": ignore, cons attribute or serialport attribute is not specified.";
xCAT::MsgUtils->message("I", $rsp, $::callback);
}
}
return %cons_map;
}
sub gen_request_data {
my ($cons_map, $siteondemand) = @_;
my (@openbmc_nodes, $data);
while (my ($k, $v) = each %{$cons_map}) {
my $ondemand;
if ($siteondemand) {
$ondemand = \1;
} else {
$ondemand = \0;
}
my $cmd;
my $cmeth = $v->{cons};
if ($cmeth eq "openbmc") {
push @openbmc_nodes, $k;
} else {
$cmd = $::XCATROOT . "/share/xcat/cons/$cmeth"." ".$k;
if (!(!$isSN && $v->{conserver} && xCAT::NetworkUtils->thishostisnot($v->{conserver}))) {
my $env;
my $locerror = $isSN ? "PERL_BADLANG=0 " : '';
if (defined($ENV{'XCATSSLVER'})) {
$env = "XCATSSLVER=$ENV{'XCATSSLVER'} ";
}
$cmd = $locerror.$env.$cmd;
}
$data->{$k}->{driver} = "cmd";
$data->{$k}->{params}->{cmd} = $cmd;
$data->{$k}->{name} = $k;
}
if (defined($v->{consoleondemand})) {
# consoleondemand attribute for node can be "1", "yes", "0" and "no"
if (($v->{consoleondemand} eq "1") || lc($v->{consoleondemand}) eq "yes") {
$ondemand = \1;
}
elsif (($v->{consoleondemand} eq "0") || lc($v->{consoleondemand}) eq "no") {
$ondemand = \0;
}
}
$data->{$k}->{ondemand} = $ondemand;
}
if (@openbmc_nodes) {
my $passwd_table = xCAT::Table->new('passwd');
my $passwd_hash = $passwd_table->getAttribs({ 'key' => 'openbmc' }, qw(username password));
$passwd_table->close();
my $openbmc_table = xCAT::Table->new('openbmc');
my $openbmc_hash = $openbmc_table->getNodesAttribs(\@openbmc_nodes, ['bmc','consport', 'username', 'password']);
$openbmc_table->close();
foreach my $node (@openbmc_nodes) {
if (defined($openbmc_hash->{$node}->[0])) {
if (!$openbmc_hash->{$node}->[0]->{'bmc'}) {
xCAT::SvrUtils::sendmsg("Error: Unable to get attribute bmc", $::callback, $node);
delete $data->{$node};
next;
}
$data->{$node}->{params}->{host} = $openbmc_hash->{$node}->[0]->{'bmc'};
if ($openbmc_hash->{$node}->[0]->{'username'}) {
$data->{$node}->{params}->{user} = $openbmc_hash->{$node}->[0]->{'username'};
} elsif ($passwd_hash and $passwd_hash->{username}) {
$data->{$node}->{params}->{user} = $passwd_hash->{username};
} else {
xCAT::SvrUtils::sendmsg("Error: Unable to get attribute username", $::callback, $node);
delete $data->{$node};
next;
}
if ($openbmc_hash->{$node}->[0]->{'password'}) {
$data->{$node}->{params}->{password} = $openbmc_hash->{$node}->[0]->{'password'};
} elsif ($passwd_hash and $passwd_hash->{password}) {
$data->{$node}->{params}->{password} = $passwd_hash->{password};
} else {
xCAT::SvrUtils::sendmsg("Error: Unable to get attribute password", $::callback, $node);
delete $data->{$node};
next;
}
if ($openbmc_hash->{$node}->[0]->{'consport'}) {
$data->{$node}->{params}->{consport} = $openbmc_hash->{$node}->[0]->{'consport'};
} else {
$data->{$node}->{params}->{port} = $bmc_cons_port;
}
$data->{$node}->{name} = $node;
$data->{$node}->{driver} = "ssh";
}
}
}
return $data;
}
sub start_goconserver {
my ($rsp, $running, $ready, $ret);
unless (-x "/usr/bin/goconserver") {
@@ -314,21 +190,33 @@ sub makegocons {
}
@ARGV = @exargs;
$Getopt::Long::ignorecase = 0;
my $delmode;
my ($delmode, $querymode, $cleanupmode);
GetOptions('d|delete' => \$delmode,
'q|query' => \$querymode,
'C|cleanup' => \$cleanupmode,
);
my $svboot = 0;
if (exists($req->{svboot})) {
$svboot = 1;
}
my %iphash = ();
foreach (@$hostinfo) { $iphash{$_} = 1; }
my %cons_map = get_cons_map($req, \%iphash);
if ($cleanupmode) {
if (exists($req->{_allnodes}) && $req->{_allnodes}->[0] != 1) {
xCAT::SvrUtils::sendmsg([ 1, "Can not specify noderange together with -C|--cleanup." ], $::callback);
return 1;
}
return xCAT::Goconserver::cleanup_nodes($::callback);
}
my %cons_map = xCAT::Goconserver::get_cons_map($req);
if (! %cons_map) {
xCAT::SvrUtils::sendmsg([ 1, "Could not get any console request entry" ], $::callback);
return 1;
}
my $api_url = "https://$host:". xCAT::Goconserver::get_api_port();
if ($querymode) {
return xCAT::Goconserver::list_nodes($api_url, \%cons_map, $::callback)
}
my $ret = start_goconserver();
if ($ret != 0) {
return 1;
@@ -346,12 +234,11 @@ sub makegocons {
}
}
my (@nodes);
my $data = gen_request_data(\%cons_map, $siteondemand);
my $data = xCAT::Goconserver::gen_request_data(\%cons_map, $siteondemand, $::callback);
if (! $data) {
xCAT::SvrUtils::sendmsg([ 1, "Could not generate the request data" ], $::callback);
return 1;
}
my $api_url = "https://$host:". xCAT::Goconserver::get_api_port();
$ret = xCAT::Goconserver::delete_nodes($api_url, $data, $delmode, $::callback);
if ($delmode) {
return $ret;
+2 -1
View File
@@ -2849,7 +2849,8 @@ sub power_with_context {
"off" => 0,
"softoff" => 5,
"reset" => 3,
"nmi" => 4
"nmi" => 4,
"cycle" => 2,
);
if ($subcommand eq "on") {
if ($sessdata->{powerstatus} eq "on") {
+2 -2
View File
@@ -459,7 +459,7 @@ sub process_request {
if (defined($request->{bmcinband})) {
if (defined($request->{bmc_node}) and defined($request->{bmc_node}->[0])) {
my $bmc_node = $request->{bmc_node}->[0];
xCAT::MsgUtils->message("S", "xcat.discovery.nodediscover: Removing discovered node definition: $bmc_node...");
xCAT::MsgUtils->message("S", "xcat.discovery.nodediscover: Removing discovered BMC nodes definition: $bmc_node...");
my $rmcmd = "rmdef $bmc_node";
xCAT::Utils->runcmd($rmcmd, 0);
if ($::RUNCMD_RC != 0)
@@ -495,7 +495,7 @@ sub process_request {
Timeout => '1',
Proto => 'tcp'
);
unless ($sock) { xCAT::MsgUtils->message("S", "xcat.discovery.nodediscover: Failed to notify $clientip that it's actually $node."); return; }
unless ($sock) { xCAT::MsgUtils->message("S", "xcat.discovery.nodediscover: Failed to notify $clientip that it's actually $node. $node has not been discovered."); return; }
print $sock $restartstring;
close($sock);
+52 -22
View File
@@ -638,6 +638,19 @@ my %api_config_info = (
always_off => "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff",
},
},
RSPCONFIG_TIME_SYNC_METHOD => {
command => "rspconfig",
url => "/time/sync_method",
attr_url => "TimeSyncMethod",
display_name => "BMC TimeSyncMethod",
instruct_msg => "",
type => "attribute",
subcommand => "timesyncmethod",
attr_value => {
ntp => "xyz.openbmc_project.Time.Synchronization.Method.NTP",
manual => "xyz.openbmc_project.Time.Synchronization.Method.Manual",
},
},
);
$::RESPONSE_OK = "200 OK";
@@ -743,20 +756,22 @@ sub preprocess_request {
}
##############################################
if (xCAT::OPENBMC->is_openbmc_python($request->{environment})) {
$callback = shift;
my $command = $request->{command}->[0];
my ($rc, $msg) = xCAT::OPENBMC->is_support_in_perl($command, $request->{environment});
if ($rc == 0) { $request = {}; return;}
if ($rc < 0) {
$request = {};
$callback->({ errorcode => [1], data => [$msg] });
return;
}
$callback = shift;
if ($::XCATSITEVALS{xcatdebugmode}) { $xcatdebugmode = $::XCATSITEVALS{xcatdebugmode} }
if ($xcatdebugmode) {
process_debug_info("OpenBMC");
}
my $command = $request->{command}->[0];
my $noderange = $request->{node};
my $extrargs = $request->{arg};
my @exargs = ($request->{arg});
@@ -1186,6 +1201,7 @@ sub parse_args {
foreach $subcommand (@ARGV) {
$::RSPCONFIG_CONFIGURED_API_KEY = &is_valid_config_api($subcommand, $callback);
if ($::RSPCONFIG_CONFIGURED_API_KEY ne -1) {
return ([ 1, "Can not query $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{subcommand} information with other options at the same time" ]) if ($#ARGV > 1);
# subcommand defined in the configured API hash, return from here, the RSPCONFIG_CONFIGURED_API_KEY is the key into the hash
return;
}
@@ -1556,7 +1572,7 @@ sub parse_command_status {
if ($subcommand eq "clear") {
$next_status{LOGIN_RESPONSE} = "REVENTLOG_CLEAR_REQUEST";
$next_status{REVENTLOG_CLEAR_REQUEST} = "REVENTLOG_CLEAR_RESPONSE";
} elsif ($subcommand =~ /resolved=LED/) {
} elsif (uc($subcommand) =~ /RESOLVED=LED/) {
$next_status{LOGIN_RESPONSE} = "REVENTLOG_REQUEST";
$next_status{REVENTLOG_REQUEST} = "REVENTLOG_RESOLVED_RESPONSE_LED";
} elsif ($subcommand =~ /resolved=(.+)/) {
@@ -1588,8 +1604,9 @@ sub parse_command_status {
my @options = ();
my $num_subcommand = @$subcommands;
#Setup chain to process the configured command
$subcommand = $$subcommands[0];
$::RSPCONFIG_CONFIGURED_API_KEY = &is_valid_config_api($subcommand, $callback);
if ($::RSPCONFIG_CONFIGURED_API_KEY ne -1) {
$subcommand = $$subcommands[0];
# Check if setting or quering
if ($subcommand =~ /^(\w+)=(.*)/) {
# setting
@@ -1850,23 +1867,23 @@ sub parse_command_status {
my $nohost_reboot = 0;
foreach $subcommand (@$subcommands) {
if ($subcommand =~ /-c|--check/) {
if ($subcommand =~ /^-c|^--check/) {
$check_version = 1;
} elsif ($subcommand =~ /-l|--list/) {
} elsif ($subcommand =~ /^-l|^--list/) {
$list = 1;
} elsif ($subcommand =~ /--delete/) {
} elsif ($subcommand =~ /^--delete/) {
$delete = 1;
} elsif ($subcommand =~ /-u|--upload/) {
} elsif ($subcommand =~ /^-u|^--upload/) {
$upload = 1;
} elsif ($subcommand =~ /-a|--activate/) {
} elsif ($subcommand =~ /^-a|^--activate/) {
$activate = 1;
} elsif ($subcommand =~ /-d/) {
} elsif ($subcommand =~ /^-d/) {
my $check = unsupported($callback); if (ref($check) eq "ARRAY") {
xCAT::SvrUtils::sendmsg($check, $callback);
return 1;
}
$streamline = 1;
} elsif ($subcommand =~ /--no-host-reboot/) {
} elsif ($subcommand =~ /^--no-host-reboot/) {
$nohost_reboot = 1;
} else {
$update_file = $subcommand;
@@ -3926,12 +3943,7 @@ sub dump_download_process {
return 1;
}
if ($h->{message} eq $::RESPONSE_OK) {
if ($::RSPCONFIG_DUMP_DOWNLOAD_ALL_REQUESTED) {
# Slightly different message if downloading dumps as part of "download all" processing
xCAT::SvrUtils::sendmsg("Downloading dump $dump_id to $file_name", $callback, $node);
} else {
xCAT::SvrUtils::sendmsg("Dump $dump_id generated. Downloading to $file_name", $callback, $node);
}
xCAT::SvrUtils::sendmsg("Downloading dump $dump_id to $file_name", $callback, $node);
my $curl_dwld_result = `$curl_dwld_cmd -s`;
if (!$curl_dwld_result) {
if ($xcatdebugmode) {
@@ -3941,7 +3953,17 @@ sub dump_download_process {
`$curl_logout_cmd -s`;
# Verify the file actually got downloaded
if (-e $file_name) {
xCAT::SvrUtils::sendmsg("Downloaded dump $dump_id to $file_name", $callback, $node) if ($::VERBOSE);
# Check inside downloaded file, if there is a "Path not found" -> invalid ID
my $grep_cmd = "/usr/bin/grep -a";
my $path_not_found = "Path not found";
my $grep_for_path = `$grep_cmd $path_not_found $file_name`;
if ($grep_for_path) {
xCAT::SvrUtils::sendmsg([1, "Invalid dump $dump_id was specified. Use -l option to list."], $callback, $node);
# Remove downloaded file, nothing useful inside of it
unlink $file_name;
} else {
xCAT::SvrUtils::sendmsg("Downloaded dump $dump_id to $file_name", $callback, $node) if ($::VERBOSE);
}
}
else {
xCAT::SvrUtils::sendmsg([1, "Failed to download dump $dump_id to $file_name. Verify destination directory exists and has correct access permissions."], $callback, $node);
@@ -4063,11 +4085,19 @@ sub rvitals_response {
# Calculate the adjusted value based on the scale attribute
#
$calc_value = $content{Value};
if ( $content{Scale} != 0 ) {
if (!defined($calc_value)) {
# Handle the bug where the keyword in the API is lower case value
$calc_value = $content{value};
}
if (defined $content{Scale} and $content{Scale} != 0) {
$calc_value = ($content{Value} * (10 ** $content{Scale}));
}
$content_info = $label . ": " . $calc_value . " " . $sensor_units{ $content{Unit} };
$content_info = $label . ": " . $calc_value;
if (defined($content{Unit})) {
$content_info = $content_info . " " . $sensor_units{ $content{Unit} };
}
push (@sorted_output, $content_info); #Save output in array
}
}
+137 -17
View File
@@ -13,10 +13,10 @@ use warnings "all";
use JSON;
use Getopt::Long;
use xCAT::Utils;
use xCAT::Usage;
use xCAT::SvrUtils;
use xCAT::OPENBMC;
use xCAT_plugin::openbmc;
#-------------------------------------------------------
@@ -30,11 +30,21 @@ use xCAT::OPENBMC;
sub handled_commands {
return {
rbeacon => 'nodehm:mgt=openbmc',
rflash => 'nodehm:mgt=openbmc',
rinv => 'nodehm:mgt=openbmc',
rpower => 'nodehm:mgt=openbmc',
rsetboot => 'nodehm:mgt=openbmc',
rvitals => 'nodehm:mgt=openbmc',
rspconfig => 'nodehm:mgt=openbmc',
reventlog => 'nodehm:mgt=openbmc',
};
}
# Common logging messages:
my $usage_errormsg = "Usage error.";
my $reventlog_no_id_resolved_errormsg = "Provide a comma separated list of IDs to be resolved. Example: 'resolved=x,y,z'";
my %node_info = ();
my $callback;
@@ -51,12 +61,10 @@ sub preprocess_request {
my $request = shift;
$callback = shift;
if (!xCAT::OPENBMC->is_openbmc_python($request->{environment})) {
$request = {};
return;
}
my $command = $request->{command}->[0];
my ($rc, $msg) = xCAT::OPENBMC->is_support_in_perl($command, $request->{environment});
if ($rc != 0) { $request = {}; return;}
my $noderange = $request->{node};
my $extrargs = $request->{arg};
my @exargs = ($request->{arg});
@@ -108,16 +116,23 @@ sub preprocess_request {
sub process_request {
my $request = shift;
$callback = shift;
my $noderange = $request->{node};
my $check = parse_node_info($noderange);
$callback->({ errorcode => [$check] }) if ($check);
return unless(%node_info);
# If we can't start the python agent, exit immediately
my $pid = xCAT::OPENBMC::start_python_agent();
if (!defined($pid)) {
xCAT::MsgUtils->message("E", { data => ["Failed to start python agent"] }, $callback);
xCAT::MsgUtils->message("E", { data => ["Failed to start the xCAT Python agent. Check /var/log/xcat/cluster.log for more information."] }, $callback);
return;
}
my $noderange = $request->{node};
my $check = parse_node_info($noderange);
if (&refactor_args($request)) {
xCAT::MsgUtils->message("E", { data => ["Failed to refactor arguments"] }, $callback);
return;
}
$callback->({ errorcode => [$check] }) if ($check);
return unless(%node_info);
xCAT::OPENBMC::submit_agent_request($pid, $request, \%node_info, $callback);
xCAT::OPENBMC::wait_agent($pid, $callback);
}
@@ -137,16 +152,26 @@ sub parse_args {
my $noderange = shift;
my $subcommand = undef;
if (scalar(@ARGV) >= 2 and ($command =~ /rpower/)) {
my $verbose;
unless (GetOptions(
'V|verbose' => \$verbose,
)) {
return ([ 1, "Error parsing arguments." ]);
}
if (scalar(@ARGV) >= 2 and ($command =~ /rbeacon|rinv|rpower|rvitals/)) {
return ([ 1, "Only one option is supported at the same time for $command" ]);
} elsif (scalar(@ARGV) == 0 and $command =~ /rpower|rflash/) {
} elsif (scalar(@ARGV) == 0 and $command =~ /rbeacon|rpower|rflash/) {
return ([ 1, "No option specified for $command" ]);
} else {
$subcommand = $ARGV[0];
}
if ($command eq "rflash") {
my $verbose;
if ($command eq "rbeacon") {
unless ($subcommand =~ /^on$|^off$/) {
return ([ 1, "Only 'on' or 'off' is supported for OpenBMC managed nodes."]);
}
} elsif ($command eq "rflash") {
my ($activate, $check, $delete, $directory, $list, $upload) = (0) x 6;
my $no_host_reboot;
GetOptions(
@@ -156,14 +181,18 @@ sub parse_args {
'd' => \$directory,
'l|list' => \$list,
'u|upload' => \$upload,
'V|verbose' => \$verbose,
'no-host-reboot' => \$no_host_reboot,
);
my $option_num = $activate+$check+$delete+$directory+$list+$upload;
if ($option_num >= 2) {
return ([ 1, "Multiple options are not supported."]);
} elsif ($option_num == 0) {
return ([ 1, "No options specified."]);
for my $arg (@ARGV) {
if ($arg =~ /^-/) {
return ([ 1, "Unsupported command: $command $arg" ]);
}
}
return ([ 1, "No options specified." ]);
}
if ($activate or $check or $delete or $upload) {
return ([ 1, "More than one firmware specified is not supported."]) if ($#ARGV >= 1);
@@ -191,10 +220,50 @@ sub parse_args {
if ($list) {
return ([ 1, "Invalid option specified with '-l|--list'."]) if (@ARGV);
}
} elsif ($command eq "rinv") {
$subcommand = "all" if (!defined($ARGV[0]));
unless ($subcommand =~ /^all$|^cpu$|^dimm$|^firm$|^model$|^serial$/) {
return ([ 1, "Unsupported command: $command $subcommand" ]);
}
} elsif ($command eq "rpower") {
unless ($subcommand =~ /^on$|^off$|^softoff$|^reset$|^boot$|^bmcreboot$|^bmcstate$|^status$|^stat$|^state$/) {
return ([ 1, "Unsupported command: $command $subcommand" ]);
}
} elsif ($command eq "rsetboot") {
my $persistant;
GetOptions('p' => \$persistant);
return ([ 1, "Only one option is supported at the same time for $command" ]) if (@ARGV > 1);
$subcommand = "stat" if (!defined($ARGV[0]));
unless ($subcommand =~ /^net$|^hd$|^cd$|^def$|^default$|^stat$/) {
return ([ 1, "Unsupported command: $command $subcommand" ]);
}
} elsif ($command eq "rvitals") {
$subcommand = "all" if (!defined($ARGV[0]));
unless ($subcommand =~ /^all$|^altitude$|^fanspeed$|^leds$|^power$|^temp$|^voltage$|^wattage$/) {
return ([ 1, "Unsupported command: $command $subcommand" ]);
}
} elsif ($command eq 'rspconfig') {
xCAT_plugin::openbmc::parse_args('rspconfig', $extrargs, $noderange);
} elsif ($command eq "reventlog") {
$subcommand = "all" if (!defined($ARGV[0]));
if ($subcommand =~ /^resolved=(.*)/) {
my $value = $1;
if (not $value) {
return ([ 1, "$usage_errormsg $reventlog_no_id_resolved_errormsg" ]);
}
my $nodes_num = @$noderange;
if (@$noderange > 1) {
return ([ 1, "Resolving faults over a xCAT noderange is not recommended." ]);
}
xCAT::SvrUtils::sendmsg("Attempting to resolve the following log entries: $value...", $callback);
} elsif ($subcommand !~ /^\d+$|^all$|^clear$/) {
if ($subcommand =~ "resolved") {
return ([ 1, "$usage_errormsg $reventlog_no_id_resolved_errormsg" ]);
}
return ([ 1, "Unsupported command: $command $subcommand" ]);
}
} else {
return ([ 1, "Unsupported command: $command" ]);
}
@@ -268,4 +337,55 @@ sub parse_node_info {
return $rst;
}
#-------------------------------------------------------
=head3 refactor_args
refractor args to be easily dealt by python client
=cut
#-------------------------------------------------------
sub refactor_args {
my $request = shift;
my $command = $request->{command}->[0];
my $extrargs = $request->{arg};
my $subcommand;
if ($command eq "rspconfig") {
$subcommand = $extrargs->[0];
if ($subcommand !~ /^dump$|^sshcfg$|^ip=dhcp$|^gard$/) {
if (grep /=/, @$extrargs) {
unshift @$extrargs, "set";
} else {
unshift @$extrargs, "get";
}
}
if ($subcommand eq "dump") {
if (defined($extrargs->[1]) and $extrargs->[1] =~ /-c|--clear|-d|--download/){
splice(@$extrargs, 2, 0, "--id");
}
}
}
if ($command eq "reventlog") {
if (!defined($extrargs->[0])) {
# If no parameters are passed, default to list all records
$request->{arg} = ["list","all"];
}
else {
$subcommand = $extrargs->[0];
}
if ($subcommand =~ /^\d+$/) {
unshift @$extrargs, "list";
}
elsif ($subcommand =~/^resolved=(.*)/) {
unshift @$extrargs, "resolved";
}
elsif ($subcommand =~/^all$/) {
unshift @$extrargs, "list";
}
}
return 0;
}
1;
+243 -60
View File
@@ -44,9 +44,7 @@ my $VERBOSE = 0;
my %allerrornodes = ();
my $callback;
my $pdutab;
my @pduents;
my $pdunodes;
my $pduhash;
#-------------------------------------------------------
@@ -76,20 +74,21 @@ sub pdu_usage
my ($callback, $command) = @_;
my $usagemsg =
"Usage:
The following commands support both type of PDUs :
pdudiscover [<noderange>|--range ipranges] [-r|-x|-z] [-w] [-V|--verbose] [--setup]
rpower pdunodes [off|on|stat|reset]
rinv pdunodes
rvitals pdunodes
The following command supports IR PDU with pdutype=irpdu :
rpower CN [pduoff|pduon|pdustat|pdustatus|pdureset]
The following commands support IR PDU with pdutype=irpdu :
rpower computenodes [pduoff|pduon|pdustat|pdustatus|pdureset]
rspconfig irpdunode [hostname=<NAME>|ip=<IP>|gateway=<GATEWAY>|mask=<MASK>]
The following commands support CR PDU with pdutype=crpdu :
rpower pdunodes relay=[1|2|3] [on|off]
rinv pdunodes
rvitals pdunodes
rspconfig pdunodes sshcfg
rspconfig pdunodes snmpcfg
rspconfig pdunode [hostname=<NAME>|ip=<IP>|mask=<MASK>]
\n";
if ($callback)
@@ -169,6 +168,19 @@ sub process_request
@exargs = @$extrargs;
}
# get all entries from pdu table
my @attrs=();
my $schema = xCAT::Table->getTableSchema('pdu');
my $desc = $schema->{descriptions};
foreach my $c (@{ $schema->{cols} }) {
push @attrs, $c;
}
$pdutab = xCAT::Table->new('pdu');
if ($pdutab) {
$pduhash = $pdutab->getAllNodeAttribs(\@attrs, 1);
}
if( $command eq "rinv") {
#for higher performance, handle node in batch
return showMFR($noderange, $callback);
@@ -214,7 +226,7 @@ sub process_request
process_sshcfg($noderange, $subcmd, $callback);
}elsif ($subcmd eq 'snmpcfg') {
process_snmpcfg($noderange, $subcmd, $callback);
}elsif ($subcmd =~ /ip|netmask|hostname/) {
}elsif ($subcmd =~ /ip|gateway|netmask|hostname/) {
process_netcfg($request, $subreq, $subcmd, $callback);
} else {
$callback->({ errorcode => [1],error => "The input $command $subcmd is not support for pdu"});
@@ -278,9 +290,6 @@ sub powerpdu {
return powerstat($noderange, $callback);
}
my $pdutab = xCAT::Table->new('pdu');
my $pduhash = $pdutab->getNodesAttribs($noderange, ['pdutype','outlet']);
foreach my $node (@$noderange) {
if ($pduhash->{$node}->[0]->{pdutype} eq 'crpdu') {
process_relay($node,$subcmd,$callback,1,3);
@@ -345,8 +354,6 @@ sub powerpduoutlet {
my $nodetab = xCAT::Table->new('pduoutlet');
my $nodepdu = $nodetab->getNodesAttribs($noderange,['pdu']);
my $pdutab = xCAT::Table->new('pdu');
my $pduhash = $pdutab->getNodesAttribs($noderange, ['pdutype','outlet']);
foreach my $node (@$noderange) {
# the pdu attribute needs to be set
@@ -443,12 +450,10 @@ sub powerstat {
my $callback = shift;
my $output;
my $pdutab = xCAT::Table->new('pdu');
my $pduhash = $pdutab->getNodesAttribs($noderange, ['pdutype','outlet','snmpversion','snmpuser','authtype','authkey','privtype','privkey','seclevel']);
foreach my $pdu (@$noderange) {
if ($pduhash->{$pdu}->[0]->{pdutype} eq 'crpdu') {
my $snmpversion = $pduhash->{$pdu}->[0]->{snmpversion};
my $snmpcmd;
if ($snmpversion =~ /3/) {
my $snmpuser = $pduhash->{$pdu}->[0]->{snmpuser};
my $seclevel = $pduhash->{$pdu}->[0]->{seclevel};
@@ -468,7 +473,6 @@ sub powerstat {
$privkey=$authkey;
}
}
my $snmpcmd;
if ($seclevel eq "authNoPriv") {
$snmpcmd = "snmpwalk -v3 -u $snmpuser -a $authtype -A $authkey -l $seclevel";
} elsif ($seclevel eq "authPriv") {
@@ -476,16 +480,20 @@ sub powerstat {
} else { #default to notAuthNoPriv
$snmpcmd = "snmpwalk -v3 -u $snmpuser -l $seclevel";
}
for (my $relay = 1; $relay <= 3; $relay++) {
relaystat($pdu, $relay, $snmpcmd, $callback);
}
} else {
xCAT::SvrUtils::sendmsg("ERROR: No snmpuser or Security level defined for snmpV3 configuration", $callback,$pdu);
xCAT::SvrUtils::sendmsg(" use chdef command to add pdu snmpV3 attributes to pdu table", $callback,$pdu);
xCAT::SvrUtils::sendmsg(" ex: chdef coral-pdu snmpversion=3, snmpuser=admin, authtype=MD5 authkey=password1 privtype=DES privkey=password2 seclevel=authPriv", $callback,$pdu);
xCAT::SvrUtils::sendmsg(" then run 'rspconfig $pdu snmpcfg' command ", $callback,$pdu);
next;
}
}
xCAT::SvrUtils::sendmsg("please config snmpv3 to be able to query pdu relay status", $callback,$pdu);
xCAT::SvrUtils::sendmsg(" use chdef command to add pdu snmpv3 attributes to pdu table", $callback);
xCAT::SvrUtils::sendmsg(" then run 'rspconfig $pdu snmpcfg' command ", $callback);
} else {
# use default value
$snmpcmd = "snmpwalk -v3 -u admin -a MD5 -A password1 -l authPriv -x DES -X password2";
}
for (my $relay = 1; $relay <= 3; $relay++) {
relaystat($pdu, $relay, $snmpcmd, $callback);
}
next;
}
my $session = connectTopdu($pdu,$callback);
@@ -550,8 +558,16 @@ sub connectTopdu {
my $pdu = shift;
my $callback = shift;
#get community string from pdu table if defined,
#otherwise, use default
my $community;
if ($pduhash->{$pdu}->[0]->{community}) {
$community = $pduhash->{$pdu}->[0]->{community};
} else {
$community = "public";
}
my $snmpver = "1";
my $community = "public";
my $session;
my $msg = "connectTopdu";
my $versionoid = ".1.3.6.1.4.1.2.6.223.7.3.0";
@@ -626,20 +642,20 @@ sub process_netcfg {
my $pdu = @$nodes[0];
my $rsp = {};
my $pdutab = xCAT::Table->new('pdu');
my $pduhash = $pdutab->getNodesAttribs($nodes, ['pdutype']);
my $nodetab = xCAT::Table->new('hosts');
my $nodehash = $nodetab->getNodesAttribs($nodes,['ip','otherinterfaces']);
my $static_ip = $nodehash->{$pdu}->[0]->{ip};
my $discover_ip = $nodehash->{$pdu}->[0]->{otherinterfaces};
unless ($pduhash->{$pdu}->[0]->{pdutype} eq "crpdu") {
xCAT::SvrUtils::sendmsg("This command only supports CONSTELLATION PDU with pdutype=crpdu", $callback,$pdu);
netcfg_for_irpdu($pdu, $static_ip, $discover_ip, $request, $subreq, $callback);
return;
}
my $nodetab = xCAT::Table->new('hosts');
my $nodehash = $nodetab->getNodesAttribs($nodes,['ip','otherinterfaces']);
# connect to PDU
my $static_ip = $nodehash->{$pdu}->[0]->{ip};
my $discover_ip = $nodehash->{$pdu}->[0]->{otherinterfaces};
($exp, $errstr) = session_connect($static_ip, $discover_ip);
my $username = $pduhash->{$pdu}->[0]->{username};
my $password = $pduhash->{$pdu}->[0]->{password};
($exp, $errstr) = session_connect($static_ip, $discover_ip,$username,$password);
if (defined $errstr) {
xCAT::SvrUtils::sendmsg("Failed to connect", $callback,$pdu);
return;
@@ -708,10 +724,6 @@ sub process_sshcfg {
my $subcmd = shift;
my $callback = shift;
#this is default password for CoralPDU
my $password = "password8";
my $userid = "root";
my $timeout = 30;
my $keyfile = "/root/.ssh/id_rsa.pub";
my $rootkey = `cat /root/.ssh/id_rsa.pub`;
my $cmd;
@@ -719,9 +731,6 @@ sub process_sshcfg {
my $nodetab = xCAT::Table->new('hosts');
my $nodehash = $nodetab->getNodesAttribs($noderange,['ip','otherinterfaces']);
my $pdutab = xCAT::Table->new('pdu');
my $pduhash = $pdutab->getNodesAttribs($noderange, ['pdutype']);
foreach my $pdu (@$noderange) {
unless ($pduhash->{$pdu}->[0]->{pdutype} eq "crpdu") {
xCAT::SvrUtils::sendmsg("This command only supports CONSTELLATION PDU with pdutype=crpdu", $callback,$pdu);
@@ -737,7 +746,10 @@ sub process_sshcfg {
my $static_ip = $nodehash->{$pdu}->[0]->{ip};
my $discover_ip = $nodehash->{$pdu}->[0]->{otherinterfaces};
my ($exp, $errstr) = session_connect($static_ip, $discover_ip);
my $username = $pduhash->{$pdu}->[0]->{username};
my $password = $pduhash->{$pdu}->[0]->{password};
my ($exp, $errstr) = session_connect($static_ip, $discover_ip,$username,$password);
if (!defined $exp) {
$msg = " Failed to connect $errstr";
xCAT::SvrUtils::sendmsg($msg, $callback, $pdu, %allerrornodes);
@@ -770,10 +782,17 @@ sub process_sshcfg {
sub session_connect {
my $static_ip = shift;
my $discover_ip = shift;
my $userid = shift;
my $password = shift;
#default password for coral pdu
my $password = "password8";
my $userid = "root";
if (!defined $userid) {
$userid = "root";
}
if (!defined $password) {
$password = "password8";
}
my $timeout = 30;
my $ssh_ip;
@@ -910,9 +929,6 @@ sub showMFR {
my $nodetab = xCAT::Table->new('hosts');
my $nodehash = $nodetab->getNodesAttribs($noderange,['ip','otherinterfaces']);
my $pdutab = xCAT::Table->new('pdu');
my $pduhash = $pdutab->getNodesAttribs($noderange, ['pdutype']);
foreach my $pdu (@$noderange) {
unless ($pduhash->{$pdu}->[0]->{pdutype} eq "crpdu") {
rinv_for_irpdu($pdu, $callback);
@@ -922,7 +938,10 @@ sub showMFR {
# connect to PDU
my $static_ip = $nodehash->{$pdu}->[0]->{ip};
my $discover_ip = $nodehash->{$pdu}->[0]->{otherinterfaces};
my ($exp, $errstr) = session_connect($static_ip, $discover_ip);
my $username = $pduhash->{$pdu}->[0]->{username};
my $password = $pduhash->{$pdu}->[0]->{password};
my ($exp, $errstr) = session_connect($static_ip, $discover_ip,$username,$password);
if (defined $errstr) {
xCAT::SvrUtils::sendmsg("Failed to connect: $errstr", $callback);
}
@@ -1017,9 +1036,6 @@ sub showMonitorData {
my $nodetab = xCAT::Table->new('hosts');
my $nodehash = $nodetab->getNodesAttribs($noderange,['ip','otherinterfaces']);
my $pdutab = xCAT::Table->new('pdu');
my $pduhash = $pdutab->getNodesAttribs($noderange, ['pdutype']);
foreach my $pdu (@$noderange) {
unless ($pduhash->{$pdu}->[0]->{pdutype} eq "crpdu") {
my $session = connectTopdu($pdu,$callback);
@@ -1040,7 +1056,10 @@ sub showMonitorData {
# connect to PDU
my $static_ip = $nodehash->{$pdu}->[0]->{ip};
my $discover_ip = $nodehash->{$pdu}->[0]->{otherinterfaces};
my ($exp, $errstr) = session_connect($static_ip, $discover_ip);
my $username = $pduhash->{$pdu}->[0]->{username};
my $password = $pduhash->{$pdu}->[0]->{password};
my ($exp, $errstr) = session_connect($static_ip, $discover_ip,$username,$password);
my $ret;
my $err;
@@ -1134,7 +1153,7 @@ sub relaystat {
} elsif ( $stat eq "0" ) {
xCAT::SvrUtils::sendmsg(" relay $relay is off", $callback, $pdu, %allerrornodes);
} else {
xCAT::SvrUtils::sendmsg(" relay $relay is unknown", $callback, $pdu, %allerrornodes);
xCAT::SvrUtils::sendmsg(" relay $relay is $stat=unknown", $callback, $pdu, %allerrornodes);
}
return;
@@ -1208,11 +1227,13 @@ sub process_relay {
my $nodetab = xCAT::Table->new('hosts');
my $nodehash = $nodetab->getNodeAttribs($pdu,['ip','otherinterfaces']);
my $username = $pduhash->{$pdu}->[0]->{username};
my $passwd = $pduhash->{$pdu}->[0]->{password};
# connect to PDU
my $static_ip = $nodehash->{$pdu}->[0]->{ip};
my $discover_ip = $nodehash->{$pdu}->[0]->{otherinterfaces};
my ($session, $errstr) = session_connect($static_ip, $discover_ip);
my ($session, $errstr) = session_connect($static_ip, $discover_ip,$username,$passwd);
my $ret;
my $err;
@@ -1285,9 +1306,6 @@ sub process_snmpcfg {
my $nodetab = xCAT::Table->new('hosts');
my $nodehash = $nodetab->getNodesAttribs($noderange,['ip','otherinterfaces']);
my $pdutab = xCAT::Table->new('pdu');
my $pduhash = $pdutab->getNodesAttribs($noderange, ['pdutype','community','snmpversion','snmpuser','authtype','authkey','privtype','privkey','seclevel']);
foreach my $pdu (@$noderange) {
unless ($pduhash->{$pdu}->[0]->{pdutype} eq "crpdu") {
xCAT::SvrUtils::sendmsg("This command only supports CONSTELLATION PDU with pdutype=crpdu", $callback,$pdu);
@@ -1317,7 +1335,10 @@ sub process_snmpcfg {
# connect to PDU
my $static_ip = $nodehash->{$pdu}->[0]->{ip};
my $discover_ip = $nodehash->{$pdu}->[0]->{otherinterfaces};
my ($exp, $errstr) = session_connect($static_ip, $discover_ip);
my $username = $pduhash->{$pdu}->[0]->{username};
my $password = $pduhash->{$pdu}->[0]->{password};
my ($exp, $errstr) = session_connect($static_ip, $discover_ip,$username,$password);
my $ret;
my $err;
@@ -1361,6 +1382,168 @@ sub process_snmpcfg {
}
}
#-------------------------------------------------------
=head3 netcfg_for_irpdu
change hostname and network setting for IR PDU.
=cut
#-------------------------------------------------------
sub netcfg_for_irpdu {
my $pdu = shift;
my $static_ip = shift;
my $discover_ip = shift;
my $request = shift;
my $subreq = shift;
my $callback = shift;
my $hostname;
my $ip;
my $gateway;
my $netmask;
my $extrargs = $request->{arg};
my @exargs = ($request->{arg});
if (ref($extrargs)) {
@exargs = @$extrargs;
}
#get user/password from pdu table if defined
#default password for irpdu
my $passwd = "1001";
my $username = "ADMIN";
if ($pduhash->{$pdu}->[0]->{username}) {
$username = $pduhash->{$pdu}->[0]->{username};
}
if ($pduhash->{$pdu}->[0]->{password}) {
$passwd = $pduhash->{$pdu}->[0]->{password};
}
my $timeout = 10;
my $send_change = "N";
my $login_ip;
# somehow, only system command works for checking if irpdu is pingable
# Net::Ping Module and xCAT::NetworkUtils::isPingable both are not working
if (system("ping -c 2 $static_ip") == 0 ) {
$login_ip = $static_ip;
} elsif (system("ping -c 2 $discover_ip") == 0) {
$login_ip = $discover_ip;
} else {
xCAT::SvrUtils::sendmsg(" is not reachable", $callback,$pdu);
return;
}
foreach my $cmd (@exargs) {
my ($key, $value) = split(/=/, $cmd);
if ($key =~ /hostname/) {
$hostname = $value;
xCAT::SvrUtils::sendmsg("change pdu hostname to $hostname", $callback);
}
if ($key =~ /ip/) {
$ip = $value;
$send_change = "Y";
xCAT::SvrUtils::sendmsg("change ip address for $pdu to $ip", $callback);
}
if ($key =~ /gateway/) {
$gateway = $value;
$send_change = "Y";
xCAT::SvrUtils::sendmsg("change gateway for $pdu to $gateway", $callback);
}
if ($key =~ /netmask/) {
$netmask = $value;
$send_change = "Y";
xCAT::SvrUtils::sendmsg("change netmask for $pdu to $netmask", $callback);
}
}
my $login_cmd = "telnet $login_ip\r";
my $user_prompt = " Login: ";
my $pwd_prompt = "Password: ";
my $pdu_prompt = "Please Enter Your Selection => ";
my $send_zero = 0;
my $send_one = 1;
my $send_two = 2;
my $mypdu = new Expect;
$mypdu->log_stdout(1); # suppress stdout output..
$mypdu->slave->stty(qw(sane -echo));
unless ($mypdu->spawn($login_cmd))
{
$mypdu->soft_close();
xCAT::SvrUtils::sendmsg("Unable to run $login_cmd", $callback);
return;
}
my @result = $mypdu->expect(
$timeout,
[
$user_prompt,
sub {
$mypdu->clear_accum();
$mypdu->send("$username\r");
$mypdu->clear_accum();
$mypdu->exp_continue();
}
],
[
$pwd_prompt,
sub {
$mypdu->clear_accum();
$mypdu->send("$passwd\r");
$mypdu->clear_accum();
$mypdu->exp_continue();
}
],
[
$pdu_prompt,
sub {
$mypdu->clear_accum();
$mypdu->send("$send_one\r");
$mypdu->send("$send_one\r");
#change hostname
$mypdu->send("$send_one\r");
$mypdu->send("$hostname\r");
$mypdu->send("$send_zero\r");
#change network setting
$mypdu->send("$send_two\r");
$mypdu->send("$send_one\r");
$mypdu->send("$ip\r");
$mypdu->send("$gateway\r");
$mypdu->send("$netmask\r");
$mypdu->send("$send_change\r");
# go back Previous Menu
$mypdu->send("$send_zero\r");
$mypdu->send("$send_zero\r");
}
],
);
if (defined($result[1]))
{
my $errmsg = $result[1];
$mypdu->soft_close();
xCAT::SvrUtils::sendmsg("Failed expect command: $errmsg", $callback,$pdu);
return;
}
$mypdu->soft_close();
xCAT::SvrUtils::sendmsg("hostname or network setting changed, update node definition ", $callback);
xCAT::Utils->runxcmd({ command => ['chdef'], arg => ['-t','node','-o',$pdu,"otherinterfaces="] }, $subreq, 0, 1);
if ( (defined $ip) and ($static_ip ne $ip) ) {
xCAT::Utils->runxcmd({ command => ['chdef'], arg => ['-t','node','-o',$pdu,"ip=$ip",'status=configured'] }, $subreq, 0, 1);
xCAT::Utils->runxcmd({ command => ['makehosts'], node => [$pdu] }, $subreq, 0, 1);
}
return;
}
1;
+1 -1
View File
@@ -371,7 +371,7 @@ sub process_request {
my $request = {%$req};
$request->{command} = ['discovered'];
$request->{noderange} = [$node];
$request->{bmc_node} = [$bmc_node];
$request->{bmc_node} = [$bmc_node] if $bmc_node;
$doreq->($request);
if (defined($request->{error})) {
$req->{error}->[0] = '1';
+43 -27
View File
@@ -1194,9 +1194,9 @@ sub xCATdB {
# it's attribute
##################################################
if (exists($globalopt{pdu})) {
$ret = xCAT::Utils->runxcmd({ command => ['chdef'], arg => ['-t','node','-o',$host,"groups=$device","ip=$ip","mac=$mac","nodetype=$device","mgt=$device","usercomment=$vendor","pdutype=$stype"] }, $sub_req, 0, 1);
$ret = xCAT::Utils->runxcmd({ command => ['chdef'], arg => ['-t','node','-o',$host,"groups=$device","ip=$ip","mac=$mac","nodetype=$device","mgt=$device","usercomment=$vendor","pdutype=$stype","community=$community"] }, $sub_req, 0, 1);
} else {
$ret = xCAT::Utils->runxcmd({ command => ['chdef'], arg => ['-t','node','-o',$host,"groups=$device","ip=$ip","mac=$mac","nodetype=$device","mgt=$device","usercomment=$vendor","switchtype=$stype"] }, $sub_req, 0, 1);
$ret = xCAT::Utils->runxcmd({ command => ['chdef'], arg => ['-t','node','-o',$host,"groups=$device","ip=$ip","mac=$mac","nodetype=$device","mgt=$device","usercomment=$vendor","switchtype=$stype","community=$community"] }, $sub_req, 0, 1);
}
}
}
@@ -1407,9 +1407,9 @@ sub matchPredefineSwitch {
# only write to xcatdb if -w or --setup option specified
if ( (exists($globalopt{w})) || (exists($globalopt{setup})) ) {
if (exists($globalopt{pdu})) {
xCAT::Utils->runxcmd({ command => ['chdef'], arg => ['-t','node','-o',$node,"otherinterfaces=$ip",'status=Matched',"mac=$mac","usercomment=$vendor","pdutype=$stype"] }, $sub_req, 0, 1);
xCAT::Utils->runxcmd({ command => ['chdef'], arg => ['-t','node','-o',$node,"otherinterfaces=$ip",'status=Matched',"mac=$mac","usercomment=$vendor","pdutype=$stype","community=$community"] }, $sub_req, 0, 1);
} else {
xCAT::Utils->runxcmd({ command => ['chdef'], arg => ['-t','node','-o',$node,"otherinterfaces=$ip",'status=Matched',"mac=$mac","switchtype=$stype","usercomment=$vendor"] }, $sub_req, 0, 1);
xCAT::Utils->runxcmd({ command => ['chdef'], arg => ['-t','node','-o',$node,"otherinterfaces=$ip",'status=Matched',"mac=$mac","switchtype=$stype","usercomment=$vendor","community=$community"] }, $sub_req, 0, 1);
}
}
@@ -1439,32 +1439,48 @@ sub switchsetup {
if ($nettab) {
@nets = $nettab->getAllAttribs('net','mask');
}
#get master from site table
my @entries = xCAT::TableUtils->get_site_attribute("master");
my $master = $entries[0];
foreach my $mytype (keys %$nodes_to_config) {
if ( $mytype eq "irpdu" ) {
send_msg($request, 0, "the setup options for irpdu is not support yet\n");
} elsif ( $mytype eq "crpdu" ) {
my $nodetab = xCAT::Table->new('hosts');
my $nodehash = $nodetab->getNodesAttribs(\@{${nodes_to_config}->{$mytype}},['ip','otherinterfaces']);
foreach my $pdu(@{${nodes_to_config}->{$mytype}}) {
my $cmd = "rspconfig $pdu sshcfg";
xCAT::Utils->runcmd($cmd, 0);
my $ip = $nodehash->{$pdu}->[0]->{ip};
my $mask;
foreach my $net (@nets) {
if (xCAT::NetworkUtils::isInSameSubnet( $net->{'net'}, $ip, $net->{'mask'}, 0)) {
$mask=$net->{'mask'};
}
}
$cmd = "rspconfig $pdu hostname=$pdu ip=$ip netmask=$mask";
xCAT::Utils->runcmd($cmd, 0);
if ($::RUNCMD_RC == 0) {
xCAT::Utils->runxcmd({ command => ['chdef'], arg => ['-t','node','-o',$pdu,"ip=$ip","otherinterfaces="] }, $sub_req, 0, 1);
} else {
send_msg($request, 0, "Failed to run rspconfig command to set ip/netmask\n");
my $nodetab = xCAT::Table->new('hosts');
my $nodehash = $nodetab->getNodesAttribs(\@{${nodes_to_config}->{$mytype}},['ip','otherinterfaces']);
foreach my $pdu(@{${nodes_to_config}->{$mytype}}) {
my $ip = $nodehash->{$pdu}->[0]->{ip};
my $mask;
my $gateway = $master;
my @master_ips = xCAT::NetworkUtils->my_ip_facing($ip);
unless ($master_ips[0]) {
$gateway = $master_ips[1];
}
foreach my $net (@nets) {
if (xCAT::NetworkUtils::isInSameSubnet( $net->{'net'}, $ip, $net->{'mask'}, 0)) {
$mask=$net->{'mask'};
}
}
} else {
send_msg($request, 0, "the pdu type $mytype is not support\n");
my $cmd;
my $rc = 0;
if ( $mytype eq "crpdu" ) {
$cmd = "rspconfig $pdu sshcfg";
send_msg($request, 0, "process command: $cmd\n");
$rc = xCAT::Utils->runcmd($cmd, 0);
$cmd = "rspconfig $pdu hostname=$pdu ip=$ip netmask=$mask";
send_msg($request, 0, "process command: $cmd\n");
$rc = xCAT::Utils->runcmd($cmd, 0);
} elsif ( $mytype eq "irpdu" ) {
$cmd = "rspconfig $pdu hostname=$pdu ip=$ip gateway=$gateway netmask=$mask";
send_msg($request, 0, "process command: $cmd\n");
$rc = xCAT::Utils->runcmd($cmd, 0);
} else {
send_msg($request, 0, "the pdu type $mytype is not support\n");
$rc = 1;
}
if ($rc == 0) {
xCAT::Utils->runxcmd({ command => ['chdef'], arg => ['-t','node','-o',$pdu,'status=configured',"ip=$ip","otherinterfaces="] }, $sub_req, 0, 1);
} else {
send_msg($request, 0, "Failed to run rspconfig command to set ip/netmask\n");
}
}
}
return;
+6 -1
View File
@@ -852,7 +852,7 @@ sub getSiteVal {
#-------------------------------------------------------
sub handled_commands {
return {
findme => 'zvmdiscovery',
#findme => 'zvmdiscovery', # Not handle findme in this plugin, #4860
#nodediscoverdef => 'zvmdiscovery', # Handled by sequential discovery
nodediscoverls => 'zvmdiscovery',
nodediscoverstart => 'zvmdiscovery',
@@ -1710,6 +1710,11 @@ sub process_request {
my $args = $request->{arg};
if ($command eq "findme"){
if (defined($request->{discoverymethod}) and defined($request->{discoverymethod}->[0]) and ($request->{discoverymethod}->[0] ne 'undef')) {
# The findme request had been processed by other module, just return
return;
}
findme( $request, $callback, $request_command );
} elsif ($command eq "nodediscoverls") {
nodediscoverls( $callback, $args );
+11 -14
View File
@@ -24,21 +24,20 @@ BEGIN
use File::Path;
use Fcntl qw(:DEFAULT :flock);
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
umask 0077;
mkpath("/tmp/xcat/");
unless (sysopen(LOCKHANDLE, "/tmp/xcat/consolelock", O_WRONLY | O_CREAT)) {
sleep 15;
print "Unable to open lock file";
exit 0;
}
get_lock();
}
my $sleepint = int(rand(10)); #Stagger start to avoid overwhelming conserver/xCATd
use lib "$::XCATROOT/lib/perl";
require xCAT::Client;
require xCAT::Utils;
require File::Basename;
import File::Basename;
my $scriptname = $0;
umask 0077;
mkpath("/tmp/xcat/");
unless (sysopen(LOCKHANDLE, "/tmp/xcat/consolelock", O_WRONLY | O_CREAT)) {
xCAT::Utils::console_sleep(15, "Unable to open lock file");
exit 0;
}
get_lock();
my $username = "USERID";
my $passsword = "PASSW0RD";
@@ -63,8 +62,7 @@ xCAT::Client::submit_request($cmdref, \&getans);
until ($mm and $username and $slot) {
release_lock(); #Let other clients have a go
$sleepint = 10 + int(rand(20)); #Stagger to minimize lock collisions, but no big deal when it does happen
print "Console not ready, retrying in $sleepint seconds (Hit Ctrl-E,c,o to skip delay)\n";
sleep $sleepint;
xCAT::Utils::console_sleep($sleepint, "Console not ready, retrying in $sleepint seconds (Hit Ctrl-E,c,o to skip delay)\n");
get_lock();
xCAT::Client::submit_request($cmdref, \&getans);
}
@@ -73,8 +71,7 @@ my $solchkcmd = "ssh -t $username" . "@" . "$mm sol -T blade[$slot]";
my $solstatus = `$solchkcmd`;
while ($solstatus !~ /SOL Session: Ready/ and $solstatus !~ /SOL Session: Active/) {
$sleepint = 60 + int(rand(30)); #Stagger sleep to take it easy on AMM/hosting server
print "SOL unavailable, retrying in $sleepint seconds (hit Ctrl-E,c,o to skip)\n";
sleep $sleepint;
xCAT::Utils::console_sleep($sleepint, "SOL unavailable, retrying in $sleepint seconds (hit Ctrl-E,c,o to skip)\n");
$solstatus = `$solchkcmd`;
}
exec "ssh -t $username" . "@" . "$mm console -o -T blade[$slot]";
+10 -12
View File
@@ -24,24 +24,23 @@ BEGIN
use File::Path;
use Fcntl qw(:DEFAULT :flock);
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
umask 0077;
mkpath("/tmp/xcat/");
unless (sysopen(LOCKHANDLE, "/tmp/xcat/consolelock", O_WRONLY | O_CREAT)) {
sleep 15;
print "Unable to open lock file";
exit 0;
}
get_lock();
}
my $sleepint = int(rand(10));
use lib "$::XCATROOT/lib/perl";
require xCAT::Client;
require xCAT::Utils;
use strict;
use xCAT::PPCcli qw(SUCCESS EXPECT_ERROR RC_ERROR NR_ERROR);
use Data::Dumper;
require File::Basename;
import File::Basename;
my $scriptname = $0;
umask 0077;
mkpath("/tmp/xcat/");
unless (sysopen(LOCKHANDLE, "/tmp/xcat/consolelock", O_WRONLY | O_CREAT)) {
xCAT::Utils::console_sleep(15, "Unable to open lock file");
exit 0;
}
get_lock();
##############################################
# Globals
@@ -109,8 +108,7 @@ xCAT::Client::submit_request($cmdref, \&getans);
until ($lparid and $host and $mtms) {
release_lock(); #Let other clients have a go
$sleepint = 10 + int(rand(20)); #Stagger to minimize lock collisions, but no big deal when it does happen
print "Console not ready, retrying in $sleepint seconds (Hit Ctrl-E,c,o to skip delay)\n";
sleep $sleepint;
xCAT::Utils::console_sleep($sleepint, "Console not ready, retrying in $sleepint seconds (Hit Ctrl-E,c,o to skip delay)\n");
get_lock();
xCAT::Client::submit_request($cmdref, \&getans);
}
+10 -12
View File
@@ -30,22 +30,21 @@ BEGIN
use File::Path;
use Fcntl qw(:DEFAULT :flock);
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
umask 0077;
mkpath("/tmp/xcat/");
unless (sysopen(LOCKHANDLE, "/tmp/xcat/consolelock", O_WRONLY | O_CREAT)) {
sleep 15;
print "Unable to open lock file";
exit 0;
}
get_lock();
}
my $sleepint = int(rand(10)); #Stagger start to avoid overwhelming conserver/xCATd
use lib "$::XCATROOT/lib/perl";
$ENV{HOME} = '/root/';
require xCAT::Client;
require xCAT::Utils;
require File::Basename;
import File::Basename;
umask 0077;
mkpath("/tmp/xcat/");
unless (sysopen(LOCKHANDLE, "/tmp/xcat/consolelock", O_WRONLY | O_CREAT)) {
xCAT::Utils::console_sleep(15, "Unable to open lock file");
exit 0;
}
get_lock();
my $scriptname = $0;
my $username = "admin";
my $passsword = "PASSW0RD";
@@ -69,8 +68,7 @@ xCAT::Client::submit_request($cmdref, \&getans);
until ($mm and $username and $slot) {
release_lock(); #Let other clients have a go
$sleepint = 10 + int(rand(20)); #Stagger to minimize lock collisions, but no big deal when it does happen
print "Console not ready, retrying in $sleepint seconds (Hit Ctrl-E,c,o to skip delay)\n";
sleep $sleepint;
xCAT::Utils::console_sleep($sleepint, "Console not ready, retrying in $sleepint seconds (Hit Ctrl-E,c,o to skip delay)\n");
get_lock();
xCAT::Client::submit_request($cmdref, \&getans);
}
+9 -14
View File
@@ -6,6 +6,10 @@ use File::Path;
BEGIN {
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : -d '/opt/xcat' ? '/opt/xcat' : '/usr';
}
use lib "$::XCATROOT/lib/perl";
require xCAT::Client;
require xCAT::Utils;
my $sleepint = int(rand(10)); #Stagger start to avoid overwhelming conserver/xCATd
my ($lockfd, $bmc);
my $username = 'USERID';
@@ -20,21 +24,18 @@ sub acquire_lock {
mkpath(CONSOLE_LOCK_DIR);
print "Acquiring startup lock...";
unless (sysopen($lockfd, CONSOLE_LOCK_FILE, O_WRONLY | O_CREAT)) {
print "Unable to open file ".CONSOLE_LOCK_FILE."\n";
sleep(15);
xCAT::Utils::console_sleep(15, "Unable to open file ".CONSOLE_LOCK_FILE."\n");
exit 1;
}
unless (flock($lockfd, LOCK_EX)) {
print "Unable to lock file ".CONSOLE_LOCK_FILE."\n";
close($lockfd);
sleep(15);
xCAT::Utils::console_sleep(15, "Unable to lock file ".CONSOLE_LOCK_FILE."\n");
exit 1;
}
print "done\n";
unless (syswrite($lockfd, $$, length($$))) {
print "Unable to write file ".CONSOLE_LOCK_FILE."\n";
close($lockfd);
sleep(15);
xCAT::Utils::console_sleep(15, "Unable to write file ".CONSOLE_LOCK_FILE."\n");
exit 1;
}
}
@@ -44,10 +45,6 @@ sub release_lock {
close($lockfd);
}
use lib "$::XCATROOT/lib/perl";
require xCAT::Client;
sub getans {
my $rsp = shift;
if ($rsp->{node}) {
@@ -74,8 +71,7 @@ xCAT::Client::submit_request($cmdref, \&getans);
until (($username or $password) and $bmc) {
#Let other clients have a go
$sleepint = 10 + int(rand(20));
print "Console not ready, retrying in $sleepint seconds (Ctrl-e,c,o to skip delay) \n";
sleep ($sleepint);
xCAT::Utils::console_sleep($sleepint, "Console not ready, retrying in $sleepint seconds (Ctrl-e,c,o to skip delay) \n");
acquire_lock();
sleep(0.1);
release_lock();
@@ -109,8 +105,7 @@ if ($rc) { #some shoddy vendors ignore the IPMI 2.0 requirement to support IPMI
}
while ($rc != 0) {
$sleepint = 10 + int(rand(20));
print "Failure to reach IPMI device, retrying in $sleepint seconds (Hit Ctrl-E,c,o to skip)\n";
sleep ($sleepint);
xCAT::Utils::console_sleep($sleepint, "Failure to reach IPMI device, retrying in $sleepint seconds (Hit Ctrl-E,c,o to skip)\n");
@mcinfo = `$ipmitool -I lanplus $user $pass -H $bmc mc info`;
$rc = $?;
if ($rc) { #repeat workaround for shoddy vendors
+12 -18
View File
@@ -25,31 +25,17 @@ BEGIN
use File::Path;
use Fcntl qw(:DEFAULT :flock);
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
umask 0077;
mkpath("/tmp/xcat/");
unless (sysopen(LOCKHANDLE, "/tmp/xcat/consolelock", O_WRONLY | O_CREAT)) {
sleep 15;
print "Unable to open lock file";
exit 0;
}
get_lock();
my $sleepint = int(rand(10)); #Stagger start to avoid overwhelming conserver/xCATd
print "Opening console in " . (2 + (0.5 * $sleepint)) . " seconds...\n";
sleep $sleepint;
}
my $sleepint = int(rand(10));
use lib "$::XCATROOT/lib/perl";
require xCAT::Client;
require xCAT::Utils;
use strict;
#use Getopt::Long;
#use xCAT::Table;
#use xCAT::PPCdb;
use xCAT::PPCcli qw(SUCCESS EXPECT_ERROR RC_ERROR NR_ERROR);
use Data::Dumper;
require File::Basename;
import File::Basename;
my $scriptname = $0;
##############################################
# Globals
@@ -61,6 +47,15 @@ my $lparid;
my $mtms;
my @cred;
my $credencial;
umask 0077;
mkpath("/tmp/xcat/");
unless (sysopen(LOCKHANDLE, "/tmp/xcat/consolelock", O_WRONLY | O_CREAT)) {
xCAT::Utils::console_sleep(15, "Unable to open lock file");
exit 0;
}
get_lock();
my $sleepint = int(rand(10)); #Stagger start to avoid overwhelming conserver/xCATd
xCAT::Utils::console_sleep($sleepint, "Opening console in " . (2 + (0.5 * $sleepint)) . " seconds...\n");
##########################################################################
# Open remote console
@@ -121,8 +116,7 @@ xCAT::Client::submit_request($cmdref, \&getans);
until ($lparid and $host and $mtms) {
release_lock(); #Let other clients have a go
$sleepint = 10 + int(rand(20)); #Stagger to minimize lock collisions, but no big deal when it does happen
print "Console not ready, retrying in $sleepint seconds (Hit Ctrl-E,c,o to skip delay)\n";
sleep $sleepint;
xCAT::Utils::console_sleep($sleepint, "Console not ready, retrying in $sleepint seconds (Hit Ctrl-E,c,o to skip delay)\n");
get_lock();
xCAT::Client::submit_request($cmdref, \&getans);
}
+11 -12
View File
@@ -1,5 +1,6 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
use strict;
use Fcntl qw(:DEFAULT :flock);
sub get_lock {
@@ -25,24 +26,23 @@ BEGIN
use Fcntl qw(:DEFAULT :flock);
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
umask 0077;
mkpath("/tmp/xcat/");
unless (sysopen(LOCKHANDLE, "/tmp/xcat/consolelock", O_WRONLY | O_CREAT)) {
sleep 15;
print "Unable to open lock file";
exit 0;
}
get_lock();
}
my $sleepint;
use lib "$::XCATROOT/lib/perl";
require xCAT::Client;
require xCAT::Utils;
require File::Basename;
import File::Basename;
my $scriptname = $0;
mkpath("/tmp/xcat/");
unless (sysopen(LOCKHANDLE, "/tmp/xcat/consolelock", O_WRONLY | O_CREAT)) {
xCAT::Utils::console_sleep(15, "Unable to open lock file");
exit 0;
}
get_lock();
my $cmdref = {
command => ["getcons"],
arg => ["text"],
@@ -65,8 +65,7 @@ xCAT::Client::submit_request($cmdref, \&getans);
until ($dsthost and $speed and $dstty) {
release_lock();
$sleepint = int(rand(30)) + 60;
print "Console not ready, retrying in $sleepint seconds (Ctrl-C to skip delay)\n";
exec "sleep $sleepint";
xCAT::Utils::console_sleep($sleepint, "Console not ready, retrying in $sleepint seconds ( Ctrl-E c o to skip delay)\n");
}
release_lock();

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