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:
Executable
+91
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+2
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
);
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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,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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>]
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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/ //'`
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
9
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
Executable
+41
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
1.0
|
||||
@@ -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):
|
||||
|
||||
+4
-1
@@ -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}})
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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".
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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") {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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") {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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]";
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user