2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-06-01 07:51:32 +00:00

Merge branch '2.14.0' into lenovobuild2.14

This commit is contained in:
Jarrod Johnson
2018-05-16 15:41:38 -04:00
151 changed files with 11285 additions and 1580 deletions
-2
View File
@@ -18,8 +18,6 @@ script:
- echo $TRAVIS_JOB_NUMBER
- echo $TRAVIS_BRANCH
- echo $TRAVIS_COMMIT_MESSAGE
- echo $USERNAME
- echo $PASSWORD
- echo $GITHUB_TOKEN
- git log --pretty=format:"%s %b" -2
+1 -1
View File
@@ -1 +1 @@
2.13.11
2.14
+7 -4
View File
@@ -505,8 +505,8 @@ if [ "$OSNAME" != "AIX" ]; then
# Always recreate it, in case the whole dir was copied from devel to 2.x
if [ -n "$1" ]; then embed="$1/"
else embed=""; fi
cat >xCAT-core.repo << EOF
[xcat-2-core]
cat >xcat-core.repo << EOF
[xcat-core]
name=xCAT 2 Core packages
baseurl=$YUMREPOURL/$REL$EMBEDDIR/$CORE
enabled=1
@@ -519,8 +519,8 @@ EOF
cat >mklocalrepo.sh << 'EOF2'
#!/bin/sh
cd `dirname $0`
REPOFILE=`basename xCAT-*.repo`
if [[ $REPOFILE == "xCAT-*.repo" ]]; then
REPOFILE=`basename xcat-*.repo`
if [[ $REPOFILE == "xcat-*.repo" ]]; then
echo "ERROR: For xcat-dep, please execute $0 in the correct <os>/<arch> subdirectory"
exit 1
fi
@@ -532,6 +532,9 @@ if [ ! -d "$DIRECTORY" ]; then
DIRECTORY="/etc/zypp/repos.d"
fi
sed -e 's|baseurl=.*|baseurl=file://'"`pwd`"'|' $REPOFILE | sed -e 's|gpgkey=.*|gpgkey=file://'"`pwd`"'/repodata/repomd.xml.key|' > "$DIRECTORY/$REPOFILE"
if [ -f "$DIRECTORY/xCAT-core.repo" ]; then
mv "$DIRECTORY/xCAT-core.repo" "$DIRECTORY/xCAT-core.repo.nouse"
fi
cd -
EOF2
chmod 775 mklocalrepo.sh
+3 -3
View File
@@ -125,8 +125,8 @@ if [ "$OSNAME" != "AIX" ]; then
fi
done
# Modify xCAT-dep.repo files to point to the correct place
echo "===> Modifying the xCAT-dep.repo files to point to the correct location..."
# Modify xcat-dep.repo files to point to the correct place
echo "===> Modifying the xcat-dep.repo files to point to the correct location..."
# 10/01/2015 - vkhu
# The URLs have been updated in GSA, this section is not needed at the moment
#
@@ -138,7 +138,7 @@ if [ "$OSNAME" != "AIX" ]; then
# oldurl="$YUMREPOURL2"
#fi
#
#sed -i -e "s|=$oldurl|=$newurl|g" `find . -name "xCAT-dep.repo" `
#sed -i -e "s|=$oldurl|=$newurl|g" `find . -name "xcat-dep.repo" `
fi
if [ "$OSNAME" == "AIX" ]; then
+5 -5
View File
@@ -144,19 +144,19 @@ echo "This is an $OSNAME system"
grep -i 'Red' /etc/*release*;
if [ "$OSNAME" != "AIX" -a $? -eq 0 ]; then
cat >$CURDIR/build/xCAT-core.repo << EOF
[xcat-2-core]
cat >$CURDIR/build/xcat-core.repo << EOF
[xcat-core]
name=xCAT 2 Core packages
baseurl=file://$CURDIR/build
enabled=1
gpgcheck=0
EOF
cp $CURDIR/build/xCAT-core.repo /etc/yum.repos.d/
cp $CURDIR/build/xcat-core.repo /etc/yum.repos.d/
createrepo $CURDIR/build
else
rm -f /etc/zypp/repos.d/xCAT-core.repo
zypper ar file://$CURDIR/build xCAT-core
rm -f /etc/zypp/repos.d/xcat-core.repo
zypper ar file://$CURDIR/build xcat-core
fi
fi
@@ -1,22 +1,20 @@
Deploy CUDA nodes
=================
Diskful
Diskful
-------
* To provision diskful nodes using osimage ``rhels7.2-ppc64le-install-cudafull``: ::
* To provision diskful nodes using osimage ``rhels7.5-ppc64le-install-cudafull``: ::
nodeset <noderange> osimage=rhels7.2-ppc64le-install-cudafull
nodeset <noderange> osimage=rhels7.5-ppc64le-install-cudafull
rsetboot <noderange> net
rpower <noderange> boot
rpower <noderange> boot
Diskless
--------
* To provision diskless nodes using osimage ``rhels7.2-ppc64le-netboot-cudafull``: ::
* To provision diskless nodes using osimage ``rhels7.5-ppc64le-netboot-cudafull``: ::
nodeset <noderange> osimage=rhels7.2-ppc64le-netboot-cudafull
nodeset <noderange> osimage=rhels7.5-ppc64le-netboot-cudafull
rsetboot <noderange> net
rpower <noderange> boot
rpower <noderange> boot
+2 -2
View File
@@ -5,9 +5,9 @@ CUDA (Compute Unified Device Architecture) is a parallel computing platform and
For more information, see NVIDIAs website: https://developer.nvidia.com/cuda-zone
xCAT supports CUDA installation for Ubuntu 14.04.3 and RHEL 7.2LE on PowerNV (Non-Virtualized) for both diskful and diskless nodes.
xCAT supports CUDA installation for Ubuntu 14.04.3 and RHEL 7.5 on PowerNV (Non-Virtualized) for both diskful and diskless nodes.
Within the NVIDIA CUDA Toolkit, installing the ``cuda`` package will install both the ``cuda-runtime`` and the ``cuda-toolkit``. The ``cuda-toolkit`` is intended for developing CUDA programs and monitoring CUDA jobs. If your particular installation requires only running GPU jobs, it's recommended to install only the ``cuda-runtime`` package.
Within the NVIDIA CUDA Toolkit, installing the ``cuda`` package will install both the ``cuda-runtime`` and the ``cuda-toolkit``. The ``cuda-toolkit`` is intended for developing CUDA programs and monitoring CUDA jobs. If your particular installation requires only running GPU jobs, it's recommended to install only the ``cuda-runtime`` package.
.. toctree::
:maxdepth: 2
@@ -1,15 +1,15 @@
RHEL 7.2 LE
===========
RHEL 7.5
========
xCAT provides a sample package list (pkglist) files for CUDA. You can find them:
xCAT provides a sample package list (pkglist) files for CUDA. You can find them:
* Diskful: ``/opt/xcat/share/xcat/install/rh/cuda*``
* Diskless: ``/opt/xcat/share/xcat/netboot/rh/cuda*``
Diskful images
---------------
--------------
The following examples will create diskful images for ``cudafull`` and ``cudaruntime``. The osimage definitions will be created from the base ``rhels7.2-ppc64le-install-compute`` osimage.
The following examples will create diskful images for ``cudafull`` and ``cudaruntime``. The osimage definitions will be created from the base ``rhels7.5-ppc64le-install-compute`` osimage.
**[Note]**: There is a requirement to reboot the machine after the CUDA drivers are installed. To satisfy this requirement, the CUDA software is installed in the ``pkglist`` attribute of the osimage definition where a reboot will happen after the Operating System is installed.
@@ -18,18 +18,18 @@ cudafull
#. Create a copy of the ``install-compute`` image and label it ``cudafull``: ::
lsdef -t osimage -z rhels7.2-ppc64le-install-compute \
lsdef -t osimage -z rhels7.5-ppc64le-install-compute \
| sed 's/install-compute:/install-cudafull:/' \
| mkdef -z
| mkdef -z
#. Add the CUDA repo created in the previous step to the ``pkgdir`` attribute: ::
chdef -t osimage -o rhels7.2-ppc64le-install-cudafull -p \
pkgdir=/install/cuda-7.5/ppc64le/cuda-core,/install/cuda-7.5/ppc64le/cuda-deps
chdef -t osimage -o rhels7.5-ppc64le-install-cudafull -p \
pkgdir=/install/cuda-9.2/ppc64le/cuda-core,/install/cuda-9.2/ppc64le/cuda-deps
#. Use the provided ``cudafull`` pkglist to install the CUDA packages: ::
chdef -t osimage -o rhels7.2-ppc64le-install-cudafull \
chdef -t osimage -o rhels7.5-ppc64le-install-cudafull \
pkglist=/opt/xcat/share/xcat/install/rh/cudafull.rhels7.ppc64le.pkglist
cudaruntime
@@ -37,54 +37,54 @@ cudaruntime
#. Create a copy of the ``install-compute`` image and label it ``cudaruntime``: ::
lsdef -t osimage -z rhels7.2-ppc64le-install-compute \
lsdef -t osimage -z rhels7.5-ppc64le-install-compute \
| sed 's/install-compute:/install-cudaruntime:/' \
| mkdef -z
| mkdef -z
#. Add the CUDA repo created in the previous step to the ``pkgdir`` attribute: ::
chdef -t osimage -o rhels7.2-ppc64le-install-cudaruntime -p \
pkgdir=/install/cuda-7.5/ppc64le/cuda-core,/install/cuda-7.5/ppc64le/cuda-deps
chdef -t osimage -o rhels7.5-ppc64le-install-cudaruntime -p \
pkgdir=/install/cuda-9.2/ppc64le/cuda-core,/install/cuda-9.2/ppc64le/cuda-deps
#. Use the provided ``cudaruntime`` pkglist to install the CUDA packages: ::
chdef -t osimage -o rhels7.2-ppc64le-install-cudaruntime \
chdef -t osimage -o rhels7.5-ppc64le-install-cudaruntime \
pkglist=/opt/xcat/share/xcat/instal/rh/cudaruntime.rhels7.ppc64le.pkglist
Diskless images
---------------
The following examples will create diskless images for ``cudafull`` and ``cudaruntime``. The osimage definitions will be created from the base ``rhels7.2-ppc64le-netboot-compute`` osimage.
The following examples will create diskless images for ``cudafull`` and ``cudaruntime``. The osimage definitions will be created from the base ``rhels7.5-ppc64le-netboot-compute`` osimage.
**[Note]**: For diskless, the install of the CUDA packages MUST be done in the ``otherpkglist`` and **NOT** the ``pkglist`` as with diskful. The requirement for rebooting the machine is not applicable in diskless nodes because the image is loaded on each reboot.
**[Note]**: For diskless, the install of the CUDA packages MUST be done in the ``otherpkglist`` and **NOT** the ``pkglist`` as with diskful. The requirement for rebooting the machine is not applicable in diskless nodes because the image is loaded on each reboot.
cudafull
^^^^^^^^
#. Create a copy of the ``netboot-compute`` image and label it ``cudafull``: ::
lsdef -t osimage -z rhels7.2-ppc64le-netboot-compute \
lsdef -t osimage -z rhels7.5-ppc64le-netboot-compute \
| sed 's/netboot-compute:/netboot-cudafull:/' \
| mkdef -z
| mkdef -z
#. Verify that the CUDA repo created in the previous step is available in the directory specified by the ``otherpkgdir`` attribute.
#. Verify that the CUDA repo created in the previous step is available in the directory specified by the ``otherpkgdir`` attribute.
The ``otherpkgdir`` directory can be obtained by running lsdef on the osimage: ::
# lsdef -t osimage rhels7.2-ppc64le-netboot-cudafull -i otherpkgdir
Object name: rhels7.2-ppc64le-netboot-cudafull
otherpkgdir=/install/post/otherpkgs/rhels7.2/ppc64le
# lsdef -t osimage rhels7.5-ppc64le-netboot-cudafull -i otherpkgdir
Object name: rhels7.5-ppc64le-netboot-cudafull
otherpkgdir=/install/post/otherpkgs/rhels7.5/ppc64le
Create a symbolic link of the CUDA repository in the directory specified by ``otherpkgdir`` ::
ln -s /install/cuda-7.5 /install/post/otherpkgs/rhels7.2/ppc64le/cuda-7.5
ln -s /install/cuda-9.2 /install/post/otherpkgs/rhels7.5/ppc64le/cuda-9.2
#. Change the ``rootimgdir`` for the cudafull osimage: ::
chdef -t osimage -o rhels7.2-ppc64le-netboot-cudafull \
rootimgdir=/install/netboot/rhels7.2/ppc64le/cudafull
chdef -t osimage -o rhels7.5-ppc64le-netboot-cudafull \
rootimgdir=/install/netboot/rhels7.5/ppc64le/cudafull
#. Create a custom pkglist file to install additional operating system packages for your CUDA node.
#. Create a custom pkglist file to install additional operating system packages for your CUDA node.
#. Copy the default compute pkglist file as a starting point: ::
@@ -102,7 +102,7 @@ cudafull
#. Set the new file as the ``pkglist`` attribute for the cudafull osimage: ::
chdef -t osimage -o rhels7.2-ppc64le-netboot-cudafull \
chdef -t osimage -o rhels7.5-ppc64le-netboot-cudafull \
pkglist=/install/custom/netboot/rh/cudafull.rhels7.ppc64le.pkglist
@@ -111,48 +111,48 @@ cudafull
#. Create the otherpkg.pkglist file for cudafull: ::
vi /install/custom/netboot/rh/cudafull.rhels7.ppc64le.otherpkgs.pkglist
# add the following packages
cuda-7.5/ppc64le/cuda-deps/dkms
cuda-7.5/ppc64le/cuda-core/cuda
# add the following packages
cuda-9.2/ppc64le/cuda-deps/dkms
cuda-9.2/ppc64le/cuda-core/cuda
#. Set the ``otherpkg.pkglist`` attribute for the cudafull osimage: ::
chdef -t osimage -o rhels7.2-ppc64le-netboot-cudafull \
chdef -t osimage -o rhels7.5-ppc64le-netboot-cudafull \
otherpkglist=/install/custom/netboot/rh/cudafull.rhels7.ppc64le.otherpkgs.pkglist
#. Generate the image: ::
genimage rhels7.2-ppc64le-netboot-cudafull
genimage rhels7.5-ppc64le-netboot-cudafull
#. Package the image: ::
packimage rhels7.2-ppc64le-netboot-cudafull
packimage rhels7.5-ppc64le-netboot-cudafull
cudaruntime
^^^^^^^^^^^
#. Create a copy of the ``netboot-compute`` image and label it ``cudaruntime``: ::
lsdef -t osimage -z rhels7.2-ppc64le-netboot-compute \
lsdef -t osimage -z rhels7.5-ppc64le-netboot-compute \
| sed 's/netboot-compute:/netboot-cudaruntime:/' \
| mkdef -z
#. Verify that the CUDA repo created previously is available in the directory specified by the ``otherpkgdir`` attribute.
#. Verify that the CUDA repo created previously is available in the directory specified by the ``otherpkgdir`` attribute.
#. Obtain the ``otherpkgdir`` directory using the ``lsdef`` command: ::
# lsdef -t osimage rhels7.2-ppc64le-netboot-cudaruntime -i otherpkgdir
Object name: rhels7.2-ppc64le-netboot-cudaruntime
otherpkgdir=/install/post/otherpkgs/rhels7.2/ppc64le
# lsdef -t osimage rhels7.5-ppc64le-netboot-cudaruntime -i otherpkgdir
Object name: rhels7.5-ppc64le-netboot-cudaruntime
otherpkgdir=/install/post/otherpkgs/rhels7.5/ppc64le
#. Create a symbolic link to the CUDA repository in the directory specified by ``otherpkgdir`` ::
ln -s /install/cuda-7.5 /install/post/otherpkgs/rhels7.2/ppc64le/cuda-7.5
ln -s /install/cuda-9.2 /install/post/otherpkgs/rhels7.5/ppc64le/cuda-9.2
#. Change the ``rootimgdir`` for the cudaruntime osimage: ::
chdef -t osimage -o rhels7.2-ppc64le-netboot-cudaruntime \
rootimgdir=/install/netboot/rhels7.2/ppc64le/cudaruntime
chdef -t osimage -o rhels7.5-ppc64le-netboot-cudaruntime \
rootimgdir=/install/netboot/rhels7.5/ppc64le/cudaruntime
#. Create the ``otherpkg.pkglist`` file to do the install of the CUDA runtime packages:
@@ -161,19 +161,52 @@ cudaruntime
vi /install/custom/netboot/rh/cudaruntime.rhels7.ppc64le.otherpkgs.pkglist
# Add the following packages:
cuda-7.5/ppc64le/cuda-deps/dkms
cuda-7.5/ppc64le/cuda-core/cuda-runtime-7-5
cuda-9.2/ppc64le/cuda-deps/dkms
cuda-9.2/ppc64le/cuda-core/cuda-runtime-9-2
#. Set the ``otherpkg.pkglist`` attribute for the cudaruntime osimage: ::
chdef -t osimage -o rhels7.2-ppc64le-netboot-cudaruntime \
chdef -t osimage -o rhels7.5-ppc64le-netboot-cudaruntime \
otherpkglist=/install/custom/netboot/rh/cudaruntime.rhels7.ppc64le.otherpkgs.pkglist
#. Generate the image: ::
genimage rhels7.2-ppc64le-netboot-cudaruntime
genimage rhels7.5-ppc64le-netboot-cudaruntime
#. Package the image: ::
packimage rhels7.2-ppc64le-netboot-cudaruntime
packimage rhels7.5-ppc64le-netboot-cudaruntime
POWER9 Setup
------------
NVIDIA POWER9 CUDA driver need some additional setup. Refer the URL below for details.
http://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#power9-setup
xCAT includes a script, ``cuda_power9_setup`` as example, to help user handle this situation.
Diskful osimage
^^^^^^^^^^^^^^^
For diskful deployment, there is no need to change the osimage definition. Instead, add this postscript to your compute node postbootscrtips list. ::
chdef p9compute -p postscripts=cuda_power9_setup
Diskless osimage
^^^^^^^^^^^^^^^^
For diskless deployment, the script need to add to the postinstall script of the osimage. And it should be run in the chroot environment. Please refer the following commands as an example. ::
mkdir -p /install/custom/netboot/rh
cp /opt/xcat/share/xcat/netboot/rh/compute.rhels7.ppc64le.postinstall /install/custom/netboot/rh/cudafull.rhels7.ppc64le.postinstall
cat >>/install/custom/netboot/rh/cudafull.rhels7.ppc64le.postinstall <<-EOF
cp /install/postscripts/cuda_power9_setup \$installroot/tmp/cuda_power9_setup
chroot \$installroot /tmp/cuda_power9_setup
rm -f \$installroot/tmp/cuda_power9_setup
EOF
chdef -t osimage rhels7.5-ppc64le-netboot-cudafull postinstall=/install/custom/netboot/rh/cudafull.rhels7.ppc64le.postinstall
+16 -20
View File
@@ -1,31 +1,27 @@
RHEL 7.2 LE
===========
RHEL 7.5
========
#. Create a repository on the MN node installing the CUDA Toolkit: ::
# For cuda toolkit name: /root/cuda-repo-rhel7-7-5-local-7.5-18.ppc64le.rpm
# extract the contents from the rpm
# For cuda toolkit name: /path/to/cuda-repo-rhel7-9-2-local-9.2.64-1.ppc64le.rpm
# extract the contents from the rpm
mkdir -p /tmp/cuda
cd /tmp/cuda
rpm2cpio /root/cuda-repo-rhel7-7-5-local-7.5-18.ppc64le.rpm | cpio -i -d
rpm2cpio /path/to/cuda-repo-rhel7-9-2-local-9.2.64-1.ppc64le.rpm | cpio -i -d
# Create the repo directory under xCAT /install dir for cuda 7.5
mkdir -p /install/cuda-7.5/ppc64le/cuda-core
cp -r /tmp/cuda/var/cuda-repo-7-5-local/* /install/cuda-7.5/ppc64le/cuda-core
# Create the repo directory under xCAT /install dir for cuda 9.2
mkdir -p /install/cuda-9.2/ppc64le/cuda-core
cp /tmp/cuda/var/cuda-repo-9-2-local/*.rpm /install/cuda-9.2/ppc64le/cuda-core
# Create the yum repo files
createrepo /install/cuda-9.2/ppc64le/cuda-core
# Create the yum repo files
createrepo /install/cuda-7.5/ppc64le/cuda-core
#. The NVIDIA CUDA Toolkit contains rpms that have dependencies on other external packages (such as ``DKMS``). These are provided by EPEL. It's up to the system administrator to obtain the dependency packages and add those to the ``cuda-deps`` directory: ::
mkdir -p /install/cuda-7.5/ppc64le/cuda-deps
cd /install/cuda-7.5/ppc64le/cuda-deps
mkdir -p /install/cuda-9.2/ppc64le/cuda-deps
# Copy the DKMS rpm to this directory
ls
dkms-2.2.0.3-30.git.7c3e7c5.el7.noarch.rpm
# Execute createrepo in this directory
createrepo /install/cuda-7.5/ppc64le/cuda-deps
# Copy the DKMS rpm to this directory
cp /path/to/dkms-2.4.0-1.20170926git959bd74.el7.noarch.rpm /install/cuda-9.2/ppc64le/cuda-deps
# Execute createrepo in this directory
createrepo /install/cuda-9.2/ppc64le/cuda-deps
@@ -3,43 +3,36 @@ Update NVIDIA Driver
If the user wants to update the newer NVIDIA driver on the system, follow the :doc:`Create CUDA software repository </advanced/gpu/nvidia/repo/index>` document to create another repository for the new driver.
The following example assumes the new driver is in ``/install/cuda-7.5/ppc64le/nvidia_new``.
The following example assumes the new driver is in ``/install/cuda-9.2/ppc64le/nvidia_new``.
Diskful
-------
#. Change pkgdir for the cuda image: ::
chdef -t osimage -o rhels7.2-ppc64le-install-cudafull \
pkgdir=/install/cuda-7.5/ppc64le/nvidia_new,/install/cuda-7.5/ppc64le/cuda-deps
chdef -t osimage -o rhels7.5-ppc64le-install-cudafull \
pkgdir=/install/cuda-9.2/ppc64le/nvidia_new,/install/cuda-9.2/ppc64le/cuda-deps
#. Use xdsh command to remove all the NVIDIA rpms: ::
xdsh <noderange> "yum remove *nvidia* -y"
xdsh <noderange> "yum remove *nvidia* -y"
#. Run updatenode command to update NVIDIA driver on the compute node: ::
updatenode <noderange> -S
#. Reboot compute node: ::
rpower <noderange> off
rpower <noderange> on
#. Verify the newer driver level: ::
nvidia-smi | grep Driver
Diskless
--------
To update a new NVIDIA driver on diskless compute nodes, re-generate the osimage pointing to the new NVIDIA driver repository and reboot the node to load the diskless image.
To update a new NVIDIA driver on diskless compute nodes, re-generate the osimage pointing to the new NVIDIA driver repository and reboot the node to load the diskless image.
Refer to :doc:`Create osimage definitions </advanced/gpu/nvidia/osimage/index>` for specific instructions.
Refer to :doc:`Create osimage definitions </advanced/gpu/nvidia/osimage/index>` for specific instructions.
@@ -55,12 +55,13 @@ The following table illustrates the cluster being used in this example:
setupdhcp=1 \
setuptftp=1 \
setupnameserver=1 \
setupconserver=1
setupconserver=2
**Tips/Hint**
* Even if you do not want xCAT to configure any services, you must define the service nodes in the ``servicenode`` table with at least one attribute, set to 0, otherwise xCAT will not recognize the node as a service node
* See the ``setup*`` attributes in the node definition man page for the list of available services: ``man node``
* For clusters with subnetted management networks, you might want to set ``setupupforward=1``
* For the ``setupconserver`` attribute, if ``conserver`` is used, set to ``1``, if ``goconserver`` is used, set to ``2``
#. Add additional postscripts for Service Nodes (optional)
+1
View File
@@ -23,6 +23,7 @@ Advanced Topics
raid/index.rst
restapi/index.rst
security/index.rst
performance_tuning/index.rst
softlayer/index.rst
sysclone/index.rst
zones/index.rst
@@ -28,10 +28,10 @@ Diskless Installation
*Note: The $1 is a argument that is passed to the the postinstall script at runtime.*
**[kernel mismatch issue]** The Mellanox OFED ISO is built against a series of specific kernel version. If the version of the linux kernel does not match any of the Mellanox offered pre-built kernel modules, you can pass the ``--add-kernel-support`` argument to the Mellanox installation script to build the kernel modules based on the version you are using. ::
**[kernel mismatch issue]** The Mellanox OFED ISO is built against a series of specific kernel version. If the version of the linux kernel does not match any of the Mellanox offered pre-built kernel modules, you can pass the ``--add-kernel-support --without-32bit --without-fw-update --force`` arguments to the Mellanox installation script to build the kernel modules based on the version you are using. ::
/install/postscripts/mlnxofed_ib_install \
-p /install/<path-to>/<MLNX_OFED_LINUX.iso> -m --add-kernel-support -end- \
-p /install/<path-to>/<MLNX_OFED_LINUX.iso> -m --add-kernel-support --without-32bit --without-fw-update --force -end- \
-i $1 -n genimage
#. Generate the diskless image
@@ -0,0 +1,13 @@
Tuning the Database Server
==========================
#. MariaDB database
MariaDB: `Tuning Server Parameters <https://mariadb.com/kb/en/library/optimization-and-tuning>`_
According to this documentation, the two most important variables to configure are key_buffer_size and table_open_cache.
#. PostgreSQL database
PostgreSQL: `Server Configuration <http://www.postgresql.org/docs/9.3/interactive/runtime-config.html>`_
@@ -0,0 +1,13 @@
Performance Tuning
==================
xCAT supports clusters of all sizes. This document is a collection of hints, tips, and special considerations when working with large clusters, especially a single server (management node or service node) manages more than 128 nodes.
The information in this document should be viewed as example data only. Many of the suggestions are based on anecdotal experiences and may not apply to your particular environment. Suggestions in different sections of this document may recommend different or conflicting settings since they may have been provided by different people for different cluster environments. Often there is a significant amount of flexiblity in most of these settings -- you will need to resolve these differences in a way that works best for your cluster.
.. toctree::
:maxdepth: 2
linux_os_tuning.rst
xcatd_tuning.rst
database_tuning.rst
@@ -0,0 +1,46 @@
System Tuning Settings for Linux
==================================
Adjusting Operating System tunables can improve large scale cluster performance, avoid bottlenecks, and prevent failures. The following sections are a collection of suggestions that have been gathered from various large scale HPC clusters. You should investigate and evaluate the validity of each suggestion before applying them to your cluster.
#. Tuning Linux ulimits:
The open file limits are important to high concurrence network services, such as ``xcatd``. For a large cluster, it is required to increase the number of open file limit to avoid **Too many open files** error. The default value is *1024* in most OS distributions, to add below configuration in ``/etc/security/limits.conf`` to increase to *14096*.
::
* soft nofiles 14096
* hard nofiles 14096
#. Tuning Network kernel parameters:
There might be hundreds of hosts in a big network for large cluster, tuning the network kernel parameters for optimum throughput and latency could improve the performance of distributed application. For example, adding below configuration in ``/etc/sysctl.conf`` to increase the buffer.
::
net.core.rmem_max = 33554432
net.core.wmem_max = 33554432
net.core.rmem_default = 65536
net.core.wmem_default = 65536
net.ipv4.tcp_rmem = 4096 33554432 33554432
net.ipv4.tcp_wmem = 4096 33554432 33554432
net.ipv4.tcp_mem= 33554432 33554432 33554432
net.ipv4.route.flush=1
net.core.netdev_max_backlog=1500
And if you encounter **Neighbour table overflow** error, it meams there are two many ARP requests and the server cannot reply. Tune the ARP cache with below parameters.
::
net.ipv4.conf.all.arp_filter = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.neigh.default.gc_thresh1 = 30000
net.ipv4.neigh.default.gc_thresh2 = 32000
net.ipv4.neigh.default.gc_thresh3 = 32768
net.ipv4.neigh.ib0.gc_stale_time = 2000000
For more tunable parameters, you can refer to `Linux System Tuning Recommendations <https://www.ibm.com/developerworks/community/wikis/home?lang=en#!/wiki/Welcome%20to%20High%20Performance%20Computing%20(HPC)%20Central/page/Linux%20System%20Tuning%20Recommendations>`_.
@@ -0,0 +1,25 @@
Tuning xCAT Daemon Attributes
==================================
For large clusters, you consider changing the default settings in ``site`` table to improve the performance on a large-scale cluster or if you are experiencing timeouts or failures in these areas:
**consoleondemand** : When set to ``yes``, conserver connects and creates the console output for a node only when the user explicitly opens the console using rcons or wcons. Default is ``no`` on Linux, ``yes`` on AIX. Setting this to ``yes`` can reduce the load conserver places on your xCAT management node. If you need this set to ``no``, you may then need to consider setting up multiple servers to run the conserver daemon, and specify the correct server on a per-node basis by setting each node's conserver attribute.
**nodestatus** : If set to ``n``, the ``nodelist.status`` column will not be updated during the node deployment, node discovery and power operations. Default is ``y``, always update ``nodelist.status``. Setting this to ``n`` for large clusters can eliminate one node-to-server contact and one xCAT database write operation for each node during node deployment, but you will then need to determine deployment status through some other means.
**precreatemypostscripts** : (``yes/1`` or ``no/0``, only for Linux). Default is ``no``. If ``yes``, it will instruct xcat at ``nodeset`` and ``updatenode`` time to query the database once for all of the nodes passed into the command and create the ``mypostscript`` file for each node, and put them in a directory in ``site.tftpdir`` (such as: ``/tftpboot``). This prevents ``xcatd`` from having to create the ``mypostscript`` files one at a time when each deploying node contacts it, so it will speed up the deployment process. (But it also means that if you change database values for these nodes, you must rerun ``nodeset``.) If **precreatemypostscripts** is set to ``no``, the ``mypostscript`` files will not be generated ahead of time. Instead they will be generated when each node is deployed.
**svloglocal** : if set to ``1``, syslog on the service node will not get forwarded to the mgmt node. The default is to forward all syslog messages. The tradeoff on setting this attribute is reducing network traffic and log size versus having local management node access to all system messages from across the cluster.
**skiptables** : a comma separated list of tables to be skipped by ``dumpxCATdb``. A recommended setting is ``auditlog,eventlog`` because these tables can grow very large. Default is to skip no tables.
**dhcplease** : The lease time for the DHCP client. The default value is *43200*.
**xcatmaxconnections** : Number of concurrent xCAT protocol requests before requests begin queueing. This applies to both client command requests and node requests, e.g. to get postscripts. Default is ``64``.
**xcatmaxbatchconnections** : Number of concurrent xCAT connections allowed from the nodes. Number must be less than **xcatmaxconnections**.
**useflowcontrol** : If ``yes``, the postscript processing on each node contacts ``xcatd`` on the MN/SN using a lightweight UDP packet to wait until ``xcatd`` is ready to handle the requests associated with postscripts. This prevents deploying nodes from flooding ``xcatd`` and locking out admin interactive use. This value works with the **xcatmaxconnections** and **xcatmaxbatch** attributes. If the value is ``no``, nodes sleep for a random time before contacting ``xcatd``, and retry. The default is ``no``. Not supported on AIX.
These attributes may be changed based on the size of your cluster. For a large cluster, it is better to enable **useflowcontrol** and set ``xcatmaxconnection = 128``, ``xcatmaxbatchconnections = 100``. Then the daemon will only allow 100 concurrent connections from the nodes. This will allow 28 connections still to be available on the management node for xCAT commands (e.g ``nodels``).
@@ -18,7 +18,7 @@ POST - Create a token.
Acquire a token for user 'root'. ::
#curl -X POST -k 'https://127.0.0.1/xcatws/tokens?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"userName":"root","userPW":"cluster"}'
curl -X POST -k 'https://127.0.0.1/xcatws/tokens?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"userName":"root","userPW":"cluster"}'
{
"token":{
"id":"a6e89b59-2b23-429a-b3fe-d16807dd19eb",
@@ -52,7 +52,7 @@ Refer to the man page: :doc:`lsdef </guides/admin-guides/references/man1/lsdef.1
Get all the node names from xCAT database. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/nodes?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/nodes?userName=root&userPW=cluster&pretty=1'
[
"node1",
"node2",
@@ -78,7 +78,7 @@ Refer to the man page: :doc:`lsdef </guides/admin-guides/references/man1/lsdef.1
Get all the attributes for node 'node1'. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1?userName=root&userPW=cluster&pretty=1'
{
"node1":{
"profile":"compute",
@@ -108,9 +108,7 @@ Refer to the man page: :doc:`chdef </guides/admin-guides/references/man1/chdef.1
Change the attributes mgt=dfm and netboot=yaboot. ::
#curl -X PUT -k 'https://127.0.0.1/xcatws/nodes/node1?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"mgt":"dfm","netboot":"yaboot"}'
curl -X PUT -k 'https://127.0.0.1/xcatws/nodes/node1?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"mgt":"dfm","netboot":"yaboot"}'
POST - Create the node {noderange}.
```````````````````````````````````
@@ -118,7 +116,7 @@ Refer to the man page: :doc:`mkdef </guides/admin-guides/references/man1/mkdef.1
**Parameters:**
* Json format: An object which includes multiple 'att:value' pairs. DataBody: {attr1:v1,att2:v2,...}.
* Json format: An object which includes multiple 'att:value' pairs. DataBody: {options:{opt1:v1,opt2:v2},attr1:v1,att2:v2,...}.
**Returns:**
@@ -129,8 +127,7 @@ Refer to the man page: :doc:`mkdef </guides/admin-guides/references/man1/mkdef.1
Create a node with attributes groups=all, mgt=dfm and netboot=yaboot ::
#curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node1?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"groups":"all","mgt":"dfm","netboot":"yaboot"}'
curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node1?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"options":{"--template":"x86_64kvmguest-template"},'
DELETE - Remove the node {noderange}.
`````````````````````````````````````
@@ -144,8 +141,8 @@ Refer to the man page: :doc:`rmdef </guides/admin-guides/references/man1/rmdef.1
Delete the node node1 ::
#curl -X DELETE -k 'https://127.0.0.1/xcatws/nodes/node1?userName=root&userPW=cluster&pretty=1'
curl -X DELETE -k 'https://127.0.0.1/xcatws/nodes/node1?userName=root&userPW=cluster&pretty=1'
[URI:/nodes/{noderange}/attrs/{attr1,attr2,attr3 ...}] - The attributes resource for the node {noderange}
---------------------------------------------------------------------------------------------------------
@@ -165,7 +162,7 @@ Refer to the man page: :doc:`lsdef </guides/admin-guides/references/man1/lsdef.1
Get the attributes {groups,mgt,netboot} for node node1 ::
#curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/attrs/groups,mgt,netboot?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/attrs/groups,mgt,netboot?userName=root&userPW=cluster&pretty=1'
{
"node1":{
"netboot":"xnba",
@@ -190,8 +187,8 @@ Refer to the man page: :doc:`makehosts </guides/admin-guides/references/man8/mak
Create the mapping of ip and hostname record for node 'node1'. ::
#curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node1/host?userName=root&userPW=cluster&pretty=1'
curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node1/host?userName=root&userPW=cluster&pretty=1'
[URI:/nodes/{noderange}/dns] - The dns record resource for the node {noderange}
-------------------------------------------------------------------------------
@@ -210,8 +207,8 @@ Refer to the man page: :doc:`makedns </guides/admin-guides/references/man8/maked
Create the dns record for node 'node1'. ::
#curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node1/dns?userName=root&userPW=cluster&pretty=1'
curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node1/dns?userName=root&userPW=cluster&pretty=1'
DELETE - Remove the dns record for the node {noderange}.
````````````````````````````````````````````````````````
@@ -225,8 +222,8 @@ Refer to the man page: :doc:`makedns </guides/admin-guides/references/man8/maked
Delete the dns record for node node1 ::
#curl -X DELETE -k 'https://127.0.0.1/xcatws/nodes/node1/dns?userName=root&userPW=cluster&pretty=1'
curl -X DELETE -k 'https://127.0.0.1/xcatws/nodes/node1/dns?userName=root&userPW=cluster&pretty=1'
[URI:/nodes/{noderange}/dhcp] - The dhcp record resource for the node {noderange}
---------------------------------------------------------------------------------
@@ -243,8 +240,8 @@ Refer to the man page: :doc:`makedhcp </guides/admin-guides/references/man8/make
Create the dhcp record for node 'node1'. ::
#curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node1/dhcp?userName=root&userPW=cluster&pretty=1'
curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node1/dhcp?userName=root&userPW=cluster&pretty=1'
DELETE - Remove the dhcp record for the node {noderange}.
`````````````````````````````````````````````````````````
@@ -258,8 +255,8 @@ Refer to the man page: :doc:`makedhcp </guides/admin-guides/references/man8/make
Delete the dhcp record for node node1 ::
#curl -X DELETE -k 'https://127.0.0.1/xcatws/nodes/node1/dhcp?userName=root&userPW=cluster&pretty=1'
curl -X DELETE -k 'https://127.0.0.1/xcatws/nodes/node1/dhcp?userName=root&userPW=cluster&pretty=1'
[URI:/nodes/{noderange}/nodestat}] - The attributes resource for the node {noderange}
-------------------------------------------------------------------------------------
@@ -277,13 +274,37 @@ Refer to the man page: :doc:`nodestat </guides/admin-guides/references/man1/node
Get the running status for node node1 ::
#curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/nodestat?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/nodestat?userName=root&userPW=cluster&pretty=1'
{
"node1":{
"nodestat":"noping"
}
}
[URI:/nodes/{noderange}/nodels}] - Lists the nodes, noderange cannot start with /
---------------------------------------------------------------------------------
GET - Lists the nodes.
``````````````````````
Refer to the man page: :doc:`nodels </guides/admin-guides/references/man1/nodels.1>`
**Returns:**
* Json format: An array of node names.
**Example:**
Get the node names from xCAT database. ::
curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node[1-3]/nodels?userName=root&userPW=cluster&pretty=1'
[
"node1",
"node2",
"node3",
]
[URI:/nodes/{noderange}/subnodes] - The sub-nodes resources for the node {noderange}
------------------------------------------------------------------------------------
@@ -301,7 +322,7 @@ Refer to the man page: :doc:`rscan </guides/admin-guides/references/man1/rscan.1
Get all the children nodes for node 'node1'. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/subnodes?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/subnodes?userName=root&userPW=cluster&pretty=1'
{
"cmm01node09":{
"mpa":"ngpcmm01",
@@ -338,7 +359,7 @@ Refer to the man page: :doc:`rpower </guides/admin-guides/references/man1/rpower
Get the power status. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/power?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/power?userName=root&userPW=cluster&pretty=1'
{
"node1":{
"power":"on"
@@ -362,8 +383,8 @@ Refer to the man page: :doc:`rpower </guides/admin-guides/references/man1/rpower
Change the power status to on ::
#curl -X PUT -k 'https://127.0.0.1/xcatws/nodes/node1/power?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"action":"on"}'
curl -X PUT -k 'https://127.0.0.1/xcatws/nodes/node1/power?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"action":"on"}'
[URI:/nodes/{noderange}/energy] - The energy resource for the node {noderange}
------------------------------------------------------------------------------
@@ -380,8 +401,8 @@ Refer to the man page: :doc:`renergy </guides/admin-guides/references/man1/rener
Get all the energy attributes. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/energy?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/energy?userName=root&userPW=cluster&pretty=1'
{
"node1":{
"cappingmin":"272.3 W",
@@ -407,8 +428,8 @@ Refer to the man page: :doc:`renergy </guides/admin-guides/references/man1/rener
Turn on the cappingstatus to [on] ::
#curl -X PUT -k 'https://127.0.0.1/xcatws/nodes/node1/energy?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"cappingstatus":"on"}'
curl -X PUT -k 'https://127.0.0.1/xcatws/nodes/node1/energy?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"cappingstatus":"on"}'
[URI:/nodes/{noderange}/energy/{cappingmaxmin,cappingstatus,cappingvalue ...}] - The specific energy attributes resource for the node {noderange}
-------------------------------------------------------------------------------------------------------------------------------------------------
@@ -426,7 +447,7 @@ Refer to the man page: :doc:`renergy </guides/admin-guides/references/man1/rener
Get the energy attributes which are specified in the URI. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/energy/cappingmaxmin,cappingstatus?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/energy/cappingmaxmin,cappingstatus?userName=root&userPW=cluster&pretty=1'
{
"node1":{
"cappingmin":"272.3 W",
@@ -451,7 +472,7 @@ Refer to the man page: :doc:`rspconfig </guides/admin-guides/references/man1/rsp
Get the snmp community for the service processor of node1. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/sp/community?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/sp/community?userName=root&userPW=cluster&pretty=1'
{
"node1":{
"SP SNMP Community":"public"
@@ -475,8 +496,8 @@ Refer to the man page: :doc:`rspconfig </guides/admin-guides/references/man1/rsp
Set the snmp community to [mycommunity]. ::
#curl -X PUT -k 'https://127.0.0.1/xcatws/nodes/node1/sp/community?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"value":"mycommunity"}'
curl -X PUT -k 'https://127.0.0.1/xcatws/nodes/node1/sp/community?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"value":"mycommunity"}'
[URI:/nodes/{noderange}/nextboot] - The temporary bootorder resource in next boot for the node {noderange}
----------------------------------------------------------------------------------------------------------
@@ -494,7 +515,7 @@ Refer to the man page: :doc:`rsetboot </guides/admin-guides/references/man1/rset
Get the bootorder for the next boot. (It's only valid after setting.) ::
#curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/nextboot?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/nextboot?userName=root&userPW=cluster&pretty=1'
{
"node1":{
"nextboot":"Network"
@@ -518,8 +539,8 @@ Refer to the man page: :doc:`rsetboot </guides/admin-guides/references/man1/rset
Set the bootorder for the next boot. ::
#curl -X PUT -k 'https://127.0.0.1/xcatws/nodes/node1/nextboot?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"order":"net"}'
curl -X PUT -k 'https://127.0.0.1/xcatws/nodes/node1/nextboot?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"order":"net"}'
[URI:/nodes/{noderange}/bootstate] - The boot state resource for node {noderange}.
----------------------------------------------------------------------------------
@@ -537,7 +558,7 @@ Refer to the man page: :doc:`nodeset </guides/admin-guides/references/man1/nimno
Get the next boot state for the node1. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/bootstate?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/bootstate?userName=root&userPW=cluster&pretty=1'
{
"node1":{
"bootstat":"boot"
@@ -561,8 +582,8 @@ Refer to the man page: :doc:`nodeset </guides/admin-guides/references/man1/nimno
Set the next boot state for the node1. ::
#curl -X PUT -k 'https://127.0.0.1/xcatws/nodes/node1/bootstate?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"osimage":"rhels6.4-x86_64-install-compute"}'
curl -X PUT -k 'https://127.0.0.1/xcatws/nodes/node1/bootstate?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"osimage":"rhels6.4-x86_64-install-compute"}'
[URI:/nodes/{noderange}/vitals] - The vitals resources for the node {noderange}
-------------------------------------------------------------------------------
@@ -580,7 +601,7 @@ Refer to the man page: :doc:`rvitals </guides/admin-guides/references/man1/rvita
Get all the vitails attributes for the node1. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/vitals?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/vitals?userName=root&userPW=cluster&pretty=1'
{
"node1":{
"SysBrd Fault":"0",
@@ -611,7 +632,7 @@ Refer to the man page: :doc:`rvitals </guides/admin-guides/references/man1/rvita
Get the 'fanspeed' vitals attribute. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/vitals/fanspeed?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/vitals/fanspeed?userName=root&userPW=cluster&pretty=1'
{
"node1":{
"Fan 1A Tach":"3219 RPM",
@@ -642,7 +663,7 @@ Refer to the man page: :doc:`rinv </guides/admin-guides/references/man1/rinv.1>`
Get all the inventory attributes for node1. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/inventory?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/inventory?userName=root&userPW=cluster&pretty=1'
{
"node1":{
"DIMM 21 ":"8GB PC3-12800 (1600 MT/s) ECC RDIMM",
@@ -673,7 +694,7 @@ Refer to the man page: :doc:`rinv </guides/admin-guides/references/man1/rinv.1>`
Get the 'model' inventory attribute for node1. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/inventory/model?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/inventory/model?userName=root&userPW=cluster&pretty=1'
{
"node1":{
"System Description":"System x3650 M4",
@@ -698,7 +719,7 @@ Refer to the man page: :doc:`reventlog </guides/admin-guides/references/man1/rev
Get all the eventlog for node1. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/eventlog?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/eventlog?userName=root&userPW=cluster&pretty=1'
{
"node1":{
"eventlog":[
@@ -721,7 +742,7 @@ Refer to the man page: :doc:`reventlog </guides/admin-guides/references/man1/rev
Delete all the event log for node1. ::
#curl -X DELETE -k 'https://127.0.0.1/xcatws/nodes/node1/eventlog?userName=root&userPW=cluster&pretty=1'
curl -X DELETE -k 'https://127.0.0.1/xcatws/nodes/node1/eventlog?userName=root&userPW=cluster&pretty=1'
[
{
"eventlog":[
@@ -752,7 +773,7 @@ Refer to the man page: :doc:`rbeacon </guides/admin-guides/references/man1/rbeac
Turn on the beacon. ::
#curl -X PUT -k 'https://127.0.0.1/xcatws/nodes/node1/beacon?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"action":"on"}'
curl -X PUT -k 'https://127.0.0.1/xcatws/nodes/node1/beacon?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"action":"on"}'
[
{
"name":"node1",
@@ -777,7 +798,7 @@ Refer to the man page: :doc:`updatenode </guides/admin-guides/references/man1/up
Initiate an updatenode process. ::
#curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node2/updating?userName=root&userPW=cluster&pretty=1'
curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node2/updating?userName=root&userPW=cluster&pretty=1'
[
"There were no syncfiles defined to process. File synchronization has completed.",
"Performing software maintenance operations. This could take a while, if there are packages to install.
@@ -803,7 +824,7 @@ Refer to the man page: :doc:`updatenode </guides/admin-guides/references/man1/up
Initiate an file syncing process. ::
#curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node2/filesyncing?userName=root&userPW=cluster&pretty=1'
curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node2/filesyncing?userName=root&userPW=cluster&pretty=1'
[
"There were no syncfiles defined to process. File synchronization has completed."
]
@@ -825,7 +846,7 @@ Refer to the man page: :doc:`updatenode </guides/admin-guides/references/man1/up
Initiate an software maintenance process. ::
#curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node2/sw?userName=root&userPW=cluster&pretty=1'
curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node2/sw?userName=root&userPW=cluster&pretty=1'
{
"node2":[
" Wed Apr 3 09:05:42 CST 2013 Running postscript: ospkgs",
@@ -859,7 +880,7 @@ Refer to the man page: :doc:`updatenode </guides/admin-guides/references/man1/up
Initiate an updatenode process. ::
#curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node2/postscript?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"scripts":["syslog","remoteshell"]}'
curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node2/postscript?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"scripts":["syslog","remoteshell"]}'
{
"node2":[
" Wed Apr 3 09:01:33 CST 2013 Running postscript: syslog",
@@ -895,7 +916,7 @@ Refer to the man page: :doc:`xdsh </guides/admin-guides/references/man1/xdsh.1>`
Run the 'date' command on the node2. ::
#curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node2/nodeshell?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"command":["date","ls"]}'
curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node2/nodeshell?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"command":["date","ls"]}'
{
"node2":[
" Wed Apr 3 08:30:26 CST 2013",
@@ -925,7 +946,7 @@ Refer to the man page: :doc:`xdcp </guides/admin-guides/references/man1/xdcp.1>`
Copy files /tmp/f1 and /tmp/f2 from xCAT MN to the node2:/tmp. ::
#curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node2/nodecopy?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"src":["/tmp/f1","/tmp/f2"],"target":"/tmp"}'
curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node2/nodecopy?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"src":["/tmp/f1","/tmp/f2"],"target":"/tmp"}'
no output for succeeded copy.
[URI:/nodes/{noderange}/vm] - The virtualization node {noderange}.
@@ -953,20 +974,20 @@ Refer to the man page: :doc:`chvm </guides/admin-guides/references/man1/chvm.1>`
Set memory to 3000MB. ::
#curl -X PUT -k 'https://127.0.0.1/xcatws/nodes/node1/vm?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"memorysize":"3000"}'
curl -X PUT -k 'https://127.0.0.1/xcatws/nodes/node1/vm?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"memorysize":"3000"}'
**Example2:**
Add a new 20G disk. ::
#curl -X PUT -k 'https://127.0.0.1/xcatws/nodes/node1/vm?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"adddisk":"20G"}'
curl -X PUT -k 'https://127.0.0.1/xcatws/nodes/node1/vm?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"adddisk":"20G"}'
**Example3:**
Purge the disk 'hdb'. ::
#curl -X PUT -k 'https://127.0.0.1/xcatws/nodes/node1/vm?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"purgedisk":"hdb"}'
curl -X PUT -k 'https://127.0.0.1/xcatws/nodes/node1/vm?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"purgedisk":"hdb"}'
POST - Create the vm node {noderange}.
``````````````````````````````````````
@@ -988,8 +1009,8 @@ Refer to the man page: :doc:`mkvm </guides/admin-guides/references/man1/mkvm.1>`
Create the vm node1 with a 30G disk, 2048M memory and 2 cpus. ::
#curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node1/vm?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"disksize":"30G","memorysize":"2048","cpucount":"2"}'
curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node1/vm?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"disksize":"30G","memorysize":"2048","cpucount":"2"}'
DELETE - Remove the vm node {noderange}.
````````````````````````````````````````
@@ -1009,8 +1030,8 @@ Refer to the man page: :doc:`rmvm </guides/admin-guides/references/man1/rmvm.1>`
Remove the vm node1 by force and purge the disk. ::
#curl -X DELETE -k 'https://127.0.0.1/xcatws/nodes/node1/vm?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"force":"yes","purge":"yes"}'
curl -X DELETE -k 'https://127.0.0.1/xcatws/nodes/node1/vm?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"force":"yes","purge":"yes"}'
[URI:/nodes/{noderange}/vmclone] - The clone resource for the virtual node {noderange}.
---------------------------------------------------------------------------------------
@@ -1038,7 +1059,7 @@ Refer to the man page: :doc:`clonevm </guides/admin-guides/references/man1/clone
Create a clone master named "vmmaster" from the node1. ::
#curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node1/vmclone?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"tomaster":"vmmaster","detach":"yes"}'
curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node1/vmclone?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"tomaster":"vmmaster","detach":"yes"}'
{
"node1":{
"vmclone":"Cloning of node1.hda.qcow2 complete (clone uses 9633.19921875 for a disk size of 30720MB)"
@@ -1049,8 +1070,8 @@ Create a clone master named "vmmaster" from the node1. ::
Clone the node1 from the clone master named "vmmaster". ::
#curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node1/vmclone?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"frommaster":"vmmaster"}'
curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node1/vmclone?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"frommaster":"vmmaster"}'
[URI:/nodes/{noderange}/vmmigrate] - The virtualization resource for migration.
-------------------------------------------------------------------------------
@@ -1069,8 +1090,8 @@ Refer to the man page: :doc:`rmigrate </guides/admin-guides/references/man1/rmig
Migrate node1 to target host host2. ::
#curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node1/vmmigrate?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"target":"host2"}'
curl -X POST -k 'https://127.0.0.1/xcatws/nodes/node1/vmmigrate?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"target":"host2"}'
Osimage resources
=================
@@ -1093,7 +1114,7 @@ Refer to the man page: :doc:`lsdef </guides/admin-guides/references/man1/lsdef.1
Get all the osimage names. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/osimages?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/osimages?userName=root&userPW=cluster&pretty=1'
[
"sles11.2-x86_64-install-compute",
"sles11.2-x86_64-install-iscsi",
@@ -1118,14 +1139,14 @@ Refer to the man page: :doc:`copycds </guides/admin-guides/references/man8/copyc
Create osimage resources based on the ISO specified ::
#curl -X POST -k 'https://127.0.0.1/xcatws/osimages?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"iso":"/iso/RHEL6.4-20130130.0-Server-ppc64-DVD1.iso"}'
curl -X POST -k 'https://127.0.0.1/xcatws/osimages?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"iso":"/iso/RHEL6.4-20130130.0-Server-ppc64-DVD1.iso"}'
**Example2:**
Create osimage resources based on an xCAT image or configuration file ::
#curl -X POST -k 'https://127.0.0.1/xcatws/osimages?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"file":"/tmp/sles11.2-x86_64-install-compute.tgz"}'
curl -X POST -k 'https://127.0.0.1/xcatws/osimages?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"file":"/tmp/sles11.2-x86_64-install-compute.tgz"}'
[URI:/osimages/{imgname}] - The osimage resource
------------------------------------------------
@@ -1145,7 +1166,7 @@ Refer to the man page: :doc:`lsdef </guides/admin-guides/references/man1/lsdef.1
Get the attributes for the specified osimage. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/osimages/sles11.2-x86_64-install-compute?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/osimages/sles11.2-x86_64-install-compute?userName=root&userPW=cluster&pretty=1'
{
"sles11.2-x86_64-install-compute":{
"provmethod":"install",
@@ -1179,8 +1200,8 @@ Refer to the man page: :doc:`chdef </guides/admin-guides/references/man1/chdef.1
Change the 'osvers' and 'osarch' attributes for the osiamge. ::
#curl -X PUT -k 'https://127.0.0.1/xcatws/osimages/sles11.2-ppc64-install-compute/?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"osvers":"sles11.3","osarch":"x86_64"}'
curl -X PUT -k 'https://127.0.0.1/xcatws/osimages/sles11.2-ppc64-install-compute/?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"osvers":"sles11.3","osarch":"x86_64"}'
POST - Create the osimage {imgname}.
````````````````````````````````````
@@ -1198,8 +1219,8 @@ Refer to the man page: :doc:`mkdef </guides/admin-guides/references/man1/mkdef.1
Create a osimage obj with the specified parameters. ::
#curl -X POST -k 'https://127.0.0.1/xcatws/osimages/sles11.3-ppc64-install-compute?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"osvers":"sles11.3","osarch":"ppc64","osname":"Linux","provmethod":"install","profile":"compute"}'
curl -X POST -k 'https://127.0.0.1/xcatws/osimages/sles11.3-ppc64-install-compute?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"osvers":"sles11.3","osarch":"ppc64","osname":"Linux","provmethod":"install","profile":"compute"}'
DELETE - Remove the osimage {imgname}.
``````````````````````````````````````
@@ -1213,8 +1234,8 @@ Refer to the man page: :doc:`rmdef </guides/admin-guides/references/man1/rmdef.1
Delete the specified osimage. ::
#curl -X DELETE -k 'https://127.0.0.1/xcatws/osimages/sles11.3-ppc64-install-compute?userName=root&userPW=cluster&pretty=1'
curl -X DELETE -k 'https://127.0.0.1/xcatws/osimages/sles11.3-ppc64-install-compute?userName=root&userPW=cluster&pretty=1'
[URI:/osimages/{imgname}/attrs/attr1,attr2,attr3 ...] - The attributes resource for the osimage {imgname}
---------------------------------------------------------------------------------------------------------
@@ -1233,7 +1254,8 @@ Refer to the man page: :doc:`lsdef </guides/admin-guides/references/man1/lsdef.1
Get the specified attributes. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/osimages/sles11.2-ppc64-install-compute/attrs/imagetype,osarch,osname,provmethod?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/osimages/sles11.2-ppc64-install-compute/attrs/imagetype,osarch,osname,provmethod?userName=root&userPW=cluster&pretty=1'
{
"sles11.2-ppc64-install-compute":{
"provmethod":"install",
@@ -1263,20 +1285,20 @@ Refer to the man page: :doc:` </guides/admin-guides/references/>`
Generates a stateless image based on the specified osimage ::
#curl -X POST -k 'https://127.0.0.1/xcatws/osimages/sles11.2-x86_64-install-compute/instance?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"action":"gen"}'
curl -X POST -k 'https://127.0.0.1/xcatws/osimages/sles11.2-x86_64-install-compute/instance?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"action":"gen"}'
**Example2:**
Packs the stateless image from the chroot file system based on the specified osimage ::
#curl -X POST -k 'https://127.0.0.1/xcatws/osimages/sles11.2-x86_64-install-compute/instance?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"action":"pack"}'
curl -X POST -k 'https://127.0.0.1/xcatws/osimages/sles11.2-x86_64-install-compute/instance?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"action":"pack"}'
**Example3:**
Exports an xCAT image based on the specified osimage ::
#curl -X POST -k 'https://127.0.0.1/xcatws/osimages/sles11.2-x86_64-install-compute/instance?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"action":"export"}'
curl -X POST -k 'https://127.0.0.1/xcatws/osimages/sles11.2-x86_64-install-compute/instance?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"action":"export"}'
DELETE - Delete the stateless or statelite image instance for the osimage {imgname} from the file system
````````````````````````````````````````````````````````````````````````````````````````````````````````
@@ -1290,8 +1312,8 @@ Refer to the man page: :doc:`rmimage </guides/admin-guides/references/man1/rmima
Delete the stateless image for the specified osimage ::
#curl -X DELETE -k 'https://127.0.0.1/xcatws/osimages/sles11.2-x86_64-install-compute/instance?userName=root&userPW=cluster&pretty=1'
curl -X DELETE -k 'https://127.0.0.1/xcatws/osimages/sles11.2-x86_64-install-compute/instance?userName=root&userPW=cluster&pretty=1'
Network Resources
=================
@@ -1318,7 +1340,7 @@ Refer to the man page: :doc:`lsdef </guides/admin-guides/references/man1/lsdef.1
Get all the networks names from xCAT database. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/networks?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/networks?userName=root&userPW=cluster&pretty=1'
[
"network1",
"network2",
@@ -1342,8 +1364,8 @@ Refer to the man page: :doc:`makenetworks </guides/admin-guides/references/man8/
Create the networks resources base on the network configuration on xCAT MN. ::
#curl -X POST -k 'https://127.0.0.1/xcatws/networks?userName=root&userPW=cluster&pretty=1'
curl -X POST -k 'https://127.0.0.1/xcatws/networks?userName=root&userPW=cluster&pretty=1'
[URI:/networks/{netname}] - The network resource
------------------------------------------------
@@ -1362,7 +1384,8 @@ Refer to the man page: :doc:`lsdef </guides/admin-guides/references/man1/lsdef.1
Get all the attributes for network 'network1'. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/networks/network1?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/networks/network1?userName=root&userPW=cluster&pretty=1'
{
"network1":{
"gateway":"<xcatmaster>",
@@ -1391,8 +1414,8 @@ Refer to the man page: :doc:`chdef </guides/admin-guides/references/man1/chdef.1
Change the attributes mgtifname=eth0 and net=10.1.0.0. ::
#curl -X PUT -k 'https://127.0.0.1/xcatws/networks/network1?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"mgtifname":"eth0","net":"10.1.0.0"}'
curl -X PUT -k 'https://127.0.0.1/xcatws/networks/network1?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"mgtifname":"eth0","net":"10.1.0.0"}'
POST - Create the network {netname}. DataBody: {attr1:v1,att2:v2...}.
`````````````````````````````````````````````````````````````````````
@@ -1410,8 +1433,8 @@ Refer to the man page: :doc:`mkdef </guides/admin-guides/references/man1/mkdef.1
Create a network with attributes gateway=10.1.0.1, mask=255.255.0.0 ::
#curl -X POST -k 'https://127.0.0.1/xcatws/networks/network1?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"gateway":"10.1.0.1","mask":"255.255.0.0"}'
curl -X POST -k 'https://127.0.0.1/xcatws/networks/network1?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"gateway":"10.1.0.1","mask":"255.255.0.0"}'
DELETE - Remove the network {netname}.
``````````````````````````````````````
@@ -1425,8 +1448,8 @@ Refer to the man page: :doc:`rmdef </guides/admin-guides/references/man1/rmdef.1
Delete the network network1 ::
#curl -X DELETE -k 'https://127.0.0.1/xcatws/networks/network1?userName=root&userPW=cluster&pretty=1'
curl -X DELETE -k 'https://127.0.0.1/xcatws/networks/network1?userName=root&userPW=cluster&pretty=1'
[URI:/networks/{netname}/attrs/attr1,attr2,...] - The attributes resource for the network {netname}
---------------------------------------------------------------------------------------------------
@@ -1445,7 +1468,8 @@ Refer to the man page: :doc:`lsdef </guides/admin-guides/references/man1/lsdef.1
Get the attributes {groups,mgt,netboot} for network network1 ::
#curl -X GET -k 'https://127.0.0.1/xcatws/networks/network1/attrs/gateway,mask,mgtifname,net,tftpserver?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/networks/network1/attrs/gateway,mask,mgtifname,net,tftpserver?userName=root&userPW=cluster&pretty=1'
{
"network1":{
"gateway":"9.114.34.254",
@@ -1476,7 +1500,8 @@ Refer to the man page: :doc:`lsdef </guides/admin-guides/references/man1/lsdef.1
Get all the policy objects. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/policy?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/policy?userName=root&userPW=cluster&pretty=1'
[
"1",
"1.2",
@@ -1504,7 +1529,8 @@ Refer to the man page: :doc:`lsdef </guides/admin-guides/references/man1/lsdef.1
Get all the attribute for policy 1. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/policy/1?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/policy/1?userName=root&userPW=cluster&pretty=1'
{
"1":{
"name":"root",
@@ -1532,8 +1558,7 @@ Refer to the man page: :doc:`chdef </guides/admin-guides/references/man1/chdef.1
Set the name attribute for policy 3. ::
#curl -X PUT -k 'https://127.0.0.1/xcatws/policy/3?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"name":"root"}'
curl -X PUT -k 'https://127.0.0.1/xcatws/policy/3?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"name":"root"}'
POST - Create the policy {policyname}. DataBody: {attr1:v1,att2:v2...}.
```````````````````````````````````````````````````````````````````````
@@ -1553,8 +1578,8 @@ Refer to the man page: :doc:`chdef </guides/admin-guides/references/man1/chdef.1
Create a new policy 10. ::
#curl -X POST -k 'https://127.0.0.1/xcatws/policy/10?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"name":"root","commands":"rpower"}'
curl -X POST -k 'https://127.0.0.1/xcatws/policy/10?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"name":"root","commands":"rpower"}'
DELETE - Remove the policy {policy_priority}.
`````````````````````````````````````````````
@@ -1570,8 +1595,8 @@ Refer to the man page: :doc:`rmdef </guides/admin-guides/references/man1/rmdef.1
Delete the policy 10. ::
#curl -X DELETE -k 'https://127.0.0.1/xcatws/policy/10?userName=root&userPW=cluster&pretty=1'
curl -X DELETE -k 'https://127.0.0.1/xcatws/policy/10?userName=root&userPW=cluster&pretty=1'
[URI:/policy/{policyname}/attrs/{attr1,attr2,attr3,...}] - The attributes resource for the policy {policy_priority}
-------------------------------------------------------------------------------------------------------------------
@@ -1592,7 +1617,8 @@ Refer to the man page: :doc:`lsdef </guides/admin-guides/references/man1/lsdef.1
Get the name and rule attributes for policy 1. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/policy/1/attrs/name,rule?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/policy/1/attrs/name,rule?userName=root&userPW=cluster&pretty=1'
{
"1":{
"name":"root",
@@ -1625,7 +1651,8 @@ Refer to the man page: :doc:`lsdef </guides/admin-guides/references/man1/lsdef.1
Get all the group names from xCAT database. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/groups?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/groups?userName=root&userPW=cluster&pretty=1'
[
"__mgmtnode",
"all",
@@ -1650,7 +1677,8 @@ Refer to the man page: :doc:`lsdef </guides/admin-guides/references/man1/lsdef.1
Get all the attributes for group 'all'. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/groups/all?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/groups/all?userName=root&userPW=cluster&pretty=1'
{
"all":{
"members":"zxnode2,nodexxx,node1,node4"
@@ -1675,8 +1703,7 @@ Refer to the man page: :doc:`chdef </guides/admin-guides/references/man1/chdef.1
Change the attributes mgt=dfm and netboot=yaboot. ::
#curl -X PUT -k 'https://127.0.0.1/xcatws/groups/all?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"mgt":"dfm","netboot":"yaboot"}'
curl -X PUT -k 'https://127.0.0.1/xcatws/groups/all?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"mgt":"dfm","netboot":"yaboot"}'
[URI:/groups/{groupname}/attrs/{attr1,attr2,attr3 ...}] - The attributes resource for the group {groupname}
-----------------------------------------------------------------------------------------------------------
@@ -1694,7 +1721,7 @@ Refer to the man page: :doc:`lsdef </guides/admin-guides/references/man1/lsdef.1
Get the attributes {mgt,netboot} for group all ::
#curl -X GET -k 'https://127.0.0.1/xcatws/groups/all/attrs/mgt,netboot?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/groups/all/attrs/mgt,netboot?userName=root&userPW=cluster&pretty=1'
{
"all":{
"netboot":"yaboot",
@@ -1728,7 +1755,7 @@ Refer to the man page: :doc:`lsdef </guides/admin-guides/references/man1/lsdef.1
Get all the global configuration ::
#curl -X GET -k 'https://127.0.0.1/xcatws/globalconf?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/globalconf?userName=root&userPW=cluster&pretty=1'
{
"clustersite":{
"xcatconfdir":"/etc/xcat",
@@ -1755,7 +1782,8 @@ Refer to the man page: :doc:`lsdef </guides/admin-guides/references/man1/lsdef.1
Get the 'master' and 'domain' configuration. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/globalconf/attrs/master,domain?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/globalconf/attrs/master,domain?userName=root&userPW=cluster&pretty=1'
{
"clustersite":{
"domain":"cluster.com",
@@ -1782,8 +1810,8 @@ Refer to the man page: :doc:`chdef </guides/admin-guides/references/man1/chdef.1
Change/Add the domain attribute. ::
#curl -X PUT -k 'https://127.0.0.1/xcatws/globalconf/attrs/domain?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"domain":"cluster.com"}'
curl -X PUT -k 'https://127.0.0.1/xcatws/globalconf/attrs/domain?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"domain":"cluster.com"}'
DELETE - Remove the site attributes.
````````````````````````````````````
@@ -1799,8 +1827,8 @@ Refer to the man page: :doc:`chdef </guides/admin-guides/references/man1/chdef.1
Remove the domain configure. ::
#curl -X DELETE -k 'https://127.0.0.1/xcatws/globalconf/attrs/domain?userName=root&userPW=cluster&pretty=1'
curl -X DELETE -k 'https://127.0.0.1/xcatws/globalconf/attrs/domain?userName=root&userPW=cluster&pretty=1'
Service Resources
=================
@@ -1822,8 +1850,8 @@ Refer to the man page: :doc:`makedns </guides/admin-guides/references/man8/maked
Initialize the dns service. ::
#curl -X POST -k 'https://127.0.0.1/xcatws/services/dns?userName=root&userPW=cluster&pretty=1'
curl -X POST -k 'https://127.0.0.1/xcatws/services/dns?userName=root&userPW=cluster&pretty=1'
[URI:/services/dhcp] - The dhcp service resource.
-------------------------------------------------
@@ -1840,8 +1868,8 @@ Refer to the man page: :doc:`makedhcp </guides/admin-guides/references/man8/make
Create the dhcpd.conf and restart the dhcpd. ::
#curl -X POST -k 'https://127.0.0.1/xcatws/services/dhcp?userName=root&userPW=cluster&pretty=1'
curl -X POST -k 'https://127.0.0.1/xcatws/services/dhcp?userName=root&userPW=cluster&pretty=1'
[URI:/services/host] - The hostname resource.
---------------------------------------------
@@ -1858,8 +1886,8 @@ Refer to the man page: :doc:`makehosts </guides/admin-guides/references/man8/mak
Create the ip/hostname records for all the nodes to /etc/hosts. ::
#curl -X POST -k 'https://127.0.0.1/xcatws/services/host?userName=root&userPW=cluster&pretty=1'
curl -X POST -k 'https://127.0.0.1/xcatws/services/host?userName=root&userPW=cluster&pretty=1'
[URI:/services/slpnodes] - The nodes which support SLP in the xCAT cluster
--------------------------------------------------------------------------
@@ -1876,7 +1904,8 @@ Refer to the man page: :doc:`lsslp </guides/admin-guides/references/man1/lsslp.1
Get all the nodes which support slp in the network. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/services/slpnodes?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/services/slpnodes?userName=root&userPW=cluster&pretty=1'
{
"ngpcmm01":{
"mpa":"ngpcmm01",
@@ -1912,7 +1941,7 @@ Refer to the man page: :doc:`lsslp </guides/admin-guides/references/man1/lsslp.1
Get all the CMM nodes which support slp in the network. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/services/slpnodes/CMM?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/services/slpnodes/CMM?userName=root&userPW=cluster&pretty=1'
{
"ngpcmm01":{
"mpa":"ngpcmm01",
@@ -1966,7 +1995,7 @@ GET - Get attributes of tables for a noderange.
Get all the columns from table nodetype for node1 and node2. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/tables/nodetype/nodes/node1,node2?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/tables/nodetype/nodes/node1,node2?userName=root&userPW=cluster&pretty=1'
{
"nodetype":[
{
@@ -1991,7 +2020,7 @@ Get all the columns from table nodetype for node1 and node2. ::
Get all the columns from tables nodetype and noderes for node1 and node2. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/tables/nodetype,noderes/nodes/node1,node2?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/tables/nodetype,noderes/nodes/node1,node2?userName=root&userPW=cluster&pretty=1'
{
"noderes":[
{
@@ -2040,8 +2069,8 @@ PUT - Change the node table attributes for {noderange}.
Change the nodetype.arch and noderes.netboot attributes for nodes node1,node2. ::
#curl -X PUT -k 'https://127.0.0.1/xcatws/tables/nodetype,noderes/nodes/node1,node2?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"nodetype":{"arch":"x86_64"},"noderes":{"netboot":"xnba"}}'
curl -X PUT -k 'https://127.0.0.1/xcatws/tables/nodetype,noderes/nodes/node1,node2?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"nodetype":{"arch":"x86_64"},"noderes":{"netboot":"xnba"}}'
[URI:/tables/{tablelist}/nodes/nodes/{noderange}/{attrlist}] - The node table attributes resource
-------------------------------------------------------------------------------------------------
@@ -2059,7 +2088,7 @@ GET - Get table attributes for a noderange.
Get OS and ARCH attributes from nodetype table for node1 and node2. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/tables/nodetype/nodes/node1,node2/os,arch?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/tables/nodetype/nodes/node1,node2/os,arch?userName=root&userPW=cluster&pretty=1'
{
"nodetype":[
{
@@ -2078,7 +2107,7 @@ Get OS and ARCH attributes from nodetype table for node1 and node2. ::
[URI:/tables/{tablelist}/rows] - The non-node table resource
------------------------------------------------------------
Use this for tables that don't have node name as the key of the table, for example: passwd, site, networks, policy, etc.
Use this for tables that don't have node name as the key of the table, for example: passwd, site, networks, polciy, etc.
GET - Get all rows from non-node tables.
````````````````````````````````````````
@@ -2092,7 +2121,7 @@ GET - Get all rows from non-node tables.
Get all rows from networks table. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/tables/networks/rows?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/tables/networks/rows?userName=root&userPW=cluster&pretty=1'
{
"networks":[
{
@@ -2115,7 +2144,7 @@ Get all rows from networks table. ::
[URI:/tables/{tablelist}/rows/{keys}] - The non-node table rows resource
------------------------------------------------------------------------
Use this for tables that don't have node name as the key of the table, for example: passwd, site, networks, policy, etc.
Use this for tables that don't have node name as the key of the table, for example: passwd, site, networks, polciy, etc.
{keys} should be the name=value pairs which are used to search table. e.g. {keys} should be [net=192.168.1.0,mask=255.255.255.0] for networks table query since the net and mask are the keys of networks table.
@@ -2131,7 +2160,7 @@ GET - Get attributes for rows from non-node tables.
Get row which net=192.168.1.0,mask=255.255.255.0 from networks table. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/tables/networks/rows/net=192.168.1.0,mask=255.255.255.0?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/tables/networks/rows/net=192.168.1.0,mask=255.255.255.0?userName=root&userPW=cluster&pretty=1'
{
"networks":[
{
@@ -2161,8 +2190,8 @@ PUT - Change the non-node table attributes for the row that matches the {keys}.
Create a route row in the routes table. ::
#curl -X PUT -k 'https://127.0.0.1/xcatws/tables/routes/rows/routename=privnet?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"net":"10.0.1.0","mask":"255.255.255.0","gateway":"10.0.1.254","ifname":"eth1"}'
curl -X PUT -k 'https://127.0.0.1/xcatws/tables/routes/rows/routename=privnet?userName=root&userPW=cluster&pretty=1' -H Content-Type:application/json --data '{"net":"10.0.1.0","mask":"255.255.255.0","gateway":"10.0.1.254","ifname":"eth1"}'
DELETE - Delete rows from a non-node table that have the attribute values specified in {keys}.
``````````````````````````````````````````````````````````````````````````````````````````````
@@ -2174,12 +2203,12 @@ DELETE - Delete rows from a non-node table that have the attribute values specif
Delete a route row which routename=privnet in the routes table. ::
#curl -X DELETE -k 'https://127.0.0.1/xcatws/tables/routes/rows/routename=privnet?userName=root&userPW=cluster&pretty=1'
curl -X DELETE -k 'https://127.0.0.1/xcatws/tables/routes/rows/routename=privnet?userName=root&userPW=cluster&pretty=1'
[URI:/tables/{tablelist}/rows/{keys}/{attrlist}] - The non-node table attributes resource
-----------------------------------------------------------------------------------------
Use this for tables that don't have node name as the key of the table, for example: passwd, site, networks, policy, etc.
Use this for tables that don't have node name as the key of the table, for example: passwd, site, networks, polciy, etc.
GET - Get specific attributes for rows from non-node tables.
````````````````````````````````````````````````````````````
@@ -2193,7 +2222,7 @@ GET - Get specific attributes for rows from non-node tables.
Get attributes mgtifname and tftpserver which net=192.168.1.0,mask=255.255.255.0 from networks table. ::
#curl -X GET -k 'https://127.0.0.1/xcatws/tables/networks/rows/net=192.168.1.0,mask=255.255.255.0/mgtifname,tftpserver?userName=root&userPW=cluster&pretty=1'
curl -X GET -k 'https://127.0.0.1/xcatws/tables/networks/rows/net=192.168.1.0,mask=255.255.255.0/mgtifname,tftpserver?userName=root&userPW=cluster&pretty=1'
{
"networks":[
{
@@ -75,7 +75,7 @@ The REST API client needs to download the xCAT certificate CA from the xCAT http
When accessing the REST API, the certificate CA must be specified and the FQDN of the https server must be used. For example: ::
curl -X GET --cacert /root/ca-cert.pem 'https://<FQDN of xCAT MN>/xcatws/nodes?userName=root& userPW=cluster'
curl -X GET --cacert /root/ca-cert.pem 'https://<FQDN of xCAT MN>/xcatws/nodes?userName=root&userPW=<root-pw>'
Extend the Timeout of Web Server
================================
@@ -83,10 +83,10 @@ Extend the Timeout of Web Server
Some operations like 'create osimage' (copycds) need a long time (longer than 3 minutes sometimes) to complete. It would fail with a ``timeout error`` (504 Gateway Time-out) if the timeout setting in the web server is not extended: ::
For [RHEL]
sed -i 's/^Timeout.*/Timeout 600/' /etc/httpd/conf/httpd.conf
service htttd restart
Edit "/etc/httpd/conf/httpd.conf" and change existing or add new entry: "Timeout 600"
service httpd restart
For [SLES]
echo "Timeout 600" >> /etc/apache2/httpd.conf
Edit "/etc/apache2/httpd.conf" and change existing or add new entry: "Timeout 600"
service apache2 restart
Set Up an Account for Web Service Access
@@ -114,16 +114,27 @@ Use non-root Account
Create new user and setup the password and policy rules. ::
useradd wsuser
passwd wsuser # set the password
tabch key=xcat,username=wsuser passwd.password=cluster
mkdef -t policy 6 name=wsuser rule=allow
# create a user
useradd -u <wsuid> <wsuser>
# set the password
passwd <wsuser>
# add password to passwd table
tabch key=xcat,username=<wsuser> passwd.password=<wspw>
# add user to policy table
mkdef -t policy 6 name=<wsuser> rule=allow
``Note:`` in the tabch command above you can put the salted password (from /etc/shadow) in the xCAT passwd table instead of the clear text password, if you prefer.
Identical user with the same name and uid need to be created on each compute node. ::
# create a user
useradd -u <wsuid> <wsuser>
# set the password
passwd <wsuser>
Create the SSL certificate under that user's home directory so that user can be authenticated to xCAT. This is done by running the following command on the Management node as root: ::
/opt/xcat/share/xcat/scripts/setup-local-client.sh <username>
/opt/xcat/share/xcat/scripts/setup-local-client.sh <wsuser>
When running this command you'll see SSL certificates created. Enter "y" where prompted and take the defaults.
@@ -133,11 +144,15 @@ To enable the POST method of resources like nodeshell, nodecopy, updating and fi
Run a test request to see if everything is working: ::
curl -X GET --cacert /root/ca-cert.pem 'https://<xcat-mn-host>/xcatws/nodes?userName=<user>&userPW=<password>'
curl -X GET --cacert /root/ca-cert.pem 'https://<xcat-mn-host>/xcatws/nodes?userName=<wsuser>&userPW=<wspw>'
or if you did not set up the certificate: ::
curl -X GET -k 'https://<xcat-mn-host>/xcatws/nodes?userName=<user>&userPW=<password>'
curl -X GET -k 'https://<xcat-mn-host>/xcatws/nodes?userName=<wsuser>&userPW=<wspw>'
You should see some output that includes your list of nodes.
If errors returned, check `/var/log/httpd/ssl_error_log` on xCAT MN.
``Note:`` if passwords need to be changed in the future, make sure to update the xCAT passwd table. xCAT REST API uses passwords stored in that table to authenticate users.
@@ -37,14 +37,14 @@ where:
Example: ::
curl -X GET --cacert /root/ca-cert.pem 'https://<FQDN of xCAT MN>/xcatws/nodes?userName=root&userPW=cluster'
curl -X GET -k 'https://<FQDN of xCAT MN>/xcatws/nodes?userName=root&userPW=cluster'
Access Token
------------
xCAT also supports the use the Access Token to replace the using of username+password in every access. Before accessing any resource, you need get a token with your account (username+password) ::
# curl -X POST --cacert /root/ca-cert.pem \
# curl -X POST -k \
'https://<FQDN of xCAT MN>/xcatws/tokens?pretty=1' -H Content-Type:application/json --data \
'{"userName":"root","userPW":"cluster"}'
{
@@ -56,7 +56,7 @@ xCAT also supports the use the Access Token to replace the using of username+pas
Then in the subsequent REST API access, the token can be used to replace the user account (username+password) ::
curl -X GET --cacert /root/ca-cert.pem -H X-Auth-Token:5cabd675-bc2e-4318-b1d6-831fd1f32f97 'https://<FQDN of xCAT MN>/xcatws/<resource>?<parameters>
curl -X GET -k -H X-Auth-Token:5cabd675-bc2e-4318-b1d6-831fd1f32f97 'https://<FQDN of xCAT MN>/xcatws/<resource>?<parameters>
The validity of token is 24 hours. If an old token has expired, you will get a 'Authentication failure' error. Then you need reacquire a token with your account.
@@ -183,10 +183,17 @@ Testing the API
Normally you will make REST API calls from your code. You can use any language that has REST API bindings (most modern languages do).
An Example of How to Use xCAT REST API from Python
--------------------------------------------------
Refer to the file `/opt/xcat/ws/xcatws-test.py <https://github.com/xcat2/xcat-core/blob/master/xCAT-server/xCAT-wsapi/xcatws-test.py>`_: ::
./xcatws-test.py --user wsuser -password cluster_rest --xcatmn <FQDN of xCAT MN>
An Example of How to Use xCAT REST API from PERL
------------------------------------------------
Refer to the file /opt/xcat/ws/xcatws-test.pl: ::
Refer to the file `/opt/xcat/ws/xcatws-test.pl <https://github.com/xcat2/xcat-core/blob/master/xCAT-server/xCAT-wsapi/xcatws-test.pl>`_: ::
./xcatws-test.pl -m GET -u "https://127.0.0.1/xcatws/nodes?userName=root&userPW=cluster"
@@ -202,9 +209,9 @@ It can be used as an example script to access and control xCAT resources. From t
./xcatws-test.sh -u root -p cluster -h <FQDN of xCAT MN> -t
./xcatws-test.sh -u root -p cluster -h <FQDN of xCAT MN> -c -t
But for exploration and experimentation, you can make API calls from your browser or using the **curl** command.
But for exploration and experimentation, you can make API calls from your browser or by using the **curl** command.
To make an API call from your browser, uses the desired URL from this document. To simplify the test step, all the examples for the resources uses 'curl -k' to use insecure http connection and use the 'username+password' to authenticate the user. ::
To make an API call from your browser, use the desired URL from this document. To simplify the test step, all the examples for the resources use 'curl -k' for unsecure http connection and use the 'username+password' to authenticate the user. ::
curl -X GET -k 'https://myserver/xcatws/nodes?userName=xxx&userPW=xxx&pretty=1'
+1 -1
View File
@@ -59,7 +59,7 @@ author = u'IBM Corporation'
# The short X.Y version.
version = '2'
# The full version, including alpha/beta/rc tags.
release = '2.13.11'
release = '2.14'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -101,6 +101,14 @@ The BMC IP address is obtained by the open range dhcp server and the plan in thi
chdef cn01 chain="runcmd=bmcsetup"
#. **[Optional]** More operation plan to do after hardware disocvery is done, ``ondiscover`` option can be used.
For example, configure console, copy SSH key for **OpenBMC**, then disable ``powersupplyredundancy`` ::
chdef cn01 -p chain="ondiscover=makegocons|rspconfig:sshcfg|rspconfig:powersupplyredundancy=disabled"
**Note**: ``|`` is used to split commands, and ``:`` is used to split command with its option.
#. Set the target `osimage` into the chain table to automatically provision the operating system after the node discovery is complete. ::
chdef cn01 -p chain="osimage=<osimage_name>"
@@ -113,6 +121,11 @@ The BMC IP address is obtained by the open range dhcp server and the plan in thi
chdef cn01 bmc=50.0.101.1
**[Optional]** If more configuration planed to be done on BMC, the following command is also needed. ::
chdef cn01 bmcvlantag=<vlanid> # tag VLAN ID for BMC
chdef cn01 bmcusername=<desired_username>
chdef cn01 bmcpassword=<desired_password>
#. Add the compute node IP information to ``/etc/hosts``: ::
@@ -85,6 +85,14 @@ The BMC IP address is obtained by the open range dhcp server and the plan is to
chdef cn01 chain="runcmd=bmcsetup"
#. **[Optional]** More operation plan to do after hardware disocvery is done, ``ondiscover`` option can be used.
For example, configure console, copy SSH key for **OpenBMC**, then disable ``powersupplyredundancy`` ::
chdef cn01 -p chain="ondiscover=makegocons|rspconfig:sshcfg|rspconfig:powersupplyredundancy=disabled"
**Note**: ``|`` is used to split commands, and ``:`` is used to split command with its option.
#. Set the target `osimage` into the chain table to automatically provision the operating system after the node discovery is complete. ::
chdef cn01 -p chain="osimage=<osimage_name>"
@@ -18,10 +18,24 @@ Predefine a group of nodes with desired IP address for host and IP address for F
nodeadd cn1 groups=powerLE,all
chdef cn1 mgt=ipmi cons=ipmi ip=10.0.101.1 bmc=50.0.101.1 netboot=petitboot installnic=mac primarynic=mac
**[Optional]** If more configuration planed to be done on BMC, the following command is also needed. ::
chdef cn1 bmcvlantag=<vlanid> # tag VLAN ID for BMC
chdef cn1 bmcusername=<desired_username>
chdef cn1 bmcpassword=<desired_password>
In order to do BMC configuration during the discovery process, set ``runcmd=bmcsetup``. ::
chdef cn1 chain="runcmd=bmcsetup"
**[Optional]** More operation plan to do after hardware disocvery is done, ``ondiscover`` option can be used.
For example, configure console, copy SSH key for **OpenBMC**, then disable ``powersupplyredundancy`` ::
chdef cn01 -p chain="ondiscover=makegocons|rspconfig:sshcfg|rspconfig:powersupplyredundancy=disabled"
**Note**: ``|`` is used to split commands, and ``:`` is used to split command with its option.
Set the target `osimage` into the chain table to automatically provision the operating system after the node discovery is complete. ::
chdef cn1 -p chain="osimage=<osimage_name>"
@@ -54,10 +54,25 @@ After switches are defined, the server node can be predefined with the following
chdef cn1 mgt=ipmi cons=ipmi ip=10.0.101.1 bmc=50.0.101.1 netboot=petitboot installnic=mac primarynic=mac
chdef cn1 switch=switch1 switchport=0
**[Optional]** If more configuration planed to be done on BMC, the following command is also needed. ::
chdef cn1 bmcvlantag=<vlanid> # tag VLAN ID for BMC
chdef cn1 bmcusername=<desired_username>
chdef cn1 bmcpassword=<desired_password>
In order to do BMC configuration during the discovery process, set ``runcmd=bmcsetup``. ::
chdef cn1 chain="runcmd=bmcsetup"
**[Optional]** More operation plan to do after hardware disocvery is done, ``ondiscover`` option can be used.
For example, configure console, copy SSH key for **OpenBMC**, then disable ``powersupplyredundancy`` ::
chdef cn01 -p chain="ondiscover=makegocons|rspconfig:sshcfg|rspconfig:powersupplyredundancy=disabled"
**Note**: ``|`` is used to split commands, and ``:`` is used to split command with its option.
Set the target `osimage` into the chain table to automatically provision the operating system after the node discovery is complete. ::
chdef cn1 -p chain="osimage=<osimage_name>"
@@ -2,12 +2,12 @@
Unattended flash of OpenBMC firmware will do the following events:
#. Upload both BMC firmware file and PNOR firmware file
#. Activate both BMC firmware and PNOR firmware
#. Upload both BMC firmware file and Host firmware file
#. Activate both BMC firmware and Host firmware
#. If BMC firmware becomes activate, reboot BMC to apply new BMC firmware, or else, ``rflash`` will exit
#. If BMC itself state is ``NotReady``, ``rflash`` will exit
#. If BMC itself state is ``Ready``, and use ``--no-host-reboot`` option, ``rflash`` will not reboot the compute node
#. If BMC itself state is ``Ready``, and do not use ``--no-host-reboot`` option, ``rflash`` will reboot the compute node to apply PNOR firmware
#. If BMC itself state is ``Ready``, and do not use ``--no-host-reboot`` option, ``rflash`` will reboot the compute node to apply Host firmware
Use the following command to flash the firmware unattended: ::
@@ -28,8 +28,8 @@ The sequence of events that must happen to flash OpenBMC firmware is the followi
#. Power off the Host
#. Upload and Activate BMC
#. Reboot the BMC (applies BMC)
#. Upload and Activate PNOR
#. Power on the Host (applies PNOR)
#. Upload and Activate Host
#. Power on the Host (applies Host)
Power off Host
@@ -42,7 +42,7 @@ Use the rpower command to power off the host: ::
Upload and Activate BMC Firmware
--------------------------------
Use the rflash command to upload and activate the PNOR firmware: ::
Use the rflash command to upload and activate the Host firmware: ::
rflash <noderange> -a /path/to/obmc-phosphor-image-witherspoon.ubi.mtd.tar
@@ -61,10 +61,10 @@ The BMC will take 2-5 minutes to reboot, check the status using: ``rpower <noder
**Known Issue:** On reboot, the first call to the BMC after reboot, xCAT will return ``Error: BMC did not respond within 10 seconds, retry the command.``. Please retry.
Upload and Activate PNOR Firmware
Upload and Activate Host Firmware
---------------------------------
Use the rflash command to upload and activate the PNOR firmware: ::
Use the rflash command to upload and activate the Host firmware: ::
rflash <noderange> -a /path/to/witherspoon.pnor.squashfs.tar
@@ -31,7 +31,7 @@ OpenPOWER OpenBMC:
==================
\ **rbeacon**\ \ *noderange*\ {\ **on | off**\ }
\ **rbeacon**\ \ *noderange*\ {\ **on | off | stat**\ }
@@ -40,7 +40,7 @@ DESCRIPTION
***********
\ **rbeacon**\ Turns beacon (a light on the front of the physical server) on/off/blink or gives status of a node or noderange.
\ **rbeacon**\ Turns beacon (a light on the front and/or rear of the physical server) on/off/blink or gives status of a node or noderange.
********
@@ -170,7 +170,7 @@ To apply the firmware level, a reboot is required to BMC and HOST.
\ **-d**\ :
This option steamlines the update, activate, reboot BMC and reboot HOST procedure. It expects a directory containing both BMC and PNOR .tar files. When BMC and PNOR tar files are provided, the command will upload and activate firmware. After BMC becomes activate, it will reboot BMC. If BMC state is Ready, the command will reboot the HOST. If BMC state is NotReady, the command will exit.
This option steamlines the update, activate, reboot BMC and reboot HOST procedure. It expects a directory containing both BMC and Host .tar files. When BMC and Host tar files are provided, the command will upload and activate firmware. After BMC becomes activate, it will reboot BMC. If BMC state is Ready, the command will reboot the HOST. If BMC state is NotReady, the command will exit.
\ **Note:**\ When using \ **-**\ **-no-host-reboot**\ , it will not reboot the host after BMC is reboot.
@@ -212,7 +212,7 @@ This delete option will delete update image from BMC. It expects an ID as the in
OpenPOWER BMC specific (using IPMI):
Used for IBM Power S822LC for Big Data systems only. Specifies the directory where the \ **pUpdate**\ utility and at least one of BMC or PNOR update files are located. The utility and update files can be downloaded from FixCentral.
Used for IBM Power S822LC for Big Data systems only. Specifies the directory where the \ **pUpdate**\ utility and at least one of BMC or Host update files are located. The utility and update files can be downloaded from FixCentral.
@@ -236,7 +236,7 @@ This delete option will delete update image from BMC. It expects an ID as the in
OpenPOWER BMC specific (using IPMI):
Used for IBM Power S822LC for Big Data systems only. Used to recover the BMC with a BMC image downloaded from FixCentral.
Used for IBM Power S822LC for Big Data systems only. Used to recover the BMC with a BMC image downloaded from FixCentral. This option will only work if BMC is in "Brick protection" state.
@@ -357,7 +357,7 @@ This delete option will delete update image from BMC. It expects an ID as the in
6. To update the firmware on IBM Power S822LC for Big Data machine specify the node name and the file path of the data directory containing pUpdate utility, both BMC and PNOR update files:
6. To update the firmware on IBM Power S822LC for Big Data machine specify the node name and the file path of the data directory containing pUpdate utility, both BMC and Host update files:
.. code-block:: perl
@@ -90,7 +90,7 @@ OPTIONS
\ **-C|-**\ **-cleanup**\
Perform additional cleanup by running \ **nodeset offline**\, \ **makeconservercf -d**\ and \ **makegocons --cleanup**\ 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*\ .
@@ -67,7 +67,7 @@ OpenPOWER (OpenBMC) specific:
=============================
\ **rvitals**\ \ *noderange*\ [\ **temp | voltage | wattage | fanspeed | power | leds | altitude | all**\ ]
\ **rvitals**\ \ *noderange*\ [\ **temp | voltage | wattage | fanspeed | power | leds | altitude | all**\ ] [\ **-V**\ | \ **-**\ **-verbose**\ ]
@@ -19,7 +19,7 @@ SYNOPSIS
********
\ **group Attributes:**\ \ *addkcmdline*\ , \ *arch*\ , \ *authdomain*\ , \ *authkey*\ , \ *authtype*\ , \ *bmc*\ , \ *bmcpassword*\ , \ *bmcport*\ , \ *bmcusername*\ , \ *bmcvlantag*\ , \ *cfgmgr*\ , \ *cfgmgtroles*\ , \ *cfgserver*\ , \ *chain*\ , \ *chassis*\ , \ *cmdmapping*\ , \ *community*\ , \ *cons*\ , \ *conserver*\ , \ *consoleondemand*\ , \ *consport*\ , \ *cpucount*\ , \ *cputype*\ , \ *currchain*\ , \ *currstate*\ , \ *dhcpinterfaces*\ , \ *disksize*\ , \ *displayname*\ , \ *dockercpus*\ , \ *dockerflag*\ , \ *dockerhost*\ , \ *dockermemory*\ , \ *dockernics*\ , \ *domainadminpassword*\ , \ *domainadminuser*\ , \ *domaintype*\ , \ *getmac*\ , \ *groupname*\ , \ *grouptype*\ , \ *hcp*\ , \ *height*\ , \ *hostcluster*\ , \ *hostinterface*\ , \ *hostmanager*\ , \ *hostnames*\ , \ *hosttype*\ , \ *hwtype*\ , \ *id*\ , \ *initrd*\ , \ *installnic*\ , \ *interface*\ , \ *ip*\ , \ *iscsipassword*\ , \ *iscsiserver*\ , \ *iscsitarget*\ , \ *iscsiuserid*\ , \ *kcmdline*\ , \ *kernel*\ , \ *linkports*\ , \ *mac*\ , \ *membergroups*\ , \ *members*\ , \ *memory*\ , \ *mgt*\ , \ *micbridge*\ , \ *michost*\ , \ *micid*\ , \ *miconboot*\ , \ *micpowermgt*\ , \ *micvlog*\ , \ *migrationdest*\ , \ *monserver*\ , \ *mpa*\ , \ *mtm*\ , \ *nameservers*\ , \ *netboot*\ , \ *nfsdir*\ , \ *nfsserver*\ , \ *nicaliases*\ , \ *niccustomscripts*\ , \ *nicdevices*\ , \ *nicextraparams*\ , \ *nichostnameprefixes*\ , \ *nichostnamesuffixes*\ , \ *nicips*\ , \ *nicnetworks*\ , \ *nicsadapter*\ , \ *nictypes*\ , \ *nimserver*\ , \ *nodetype*\ , \ *ondiscover*\ , \ *os*\ , \ *osvolume*\ , \ *otherinterfaces*\ , \ *ou*\ , \ *outlet*\ , \ *parent*\ , \ *passwd.HMC*\ , \ *passwd.admin*\ , \ *passwd.celogin*\ , \ *passwd.general*\ , \ *passwd.hscroot*\ , \ *password*\ , \ *pdu*\ , \ *pdutype*\ , \ *postbootscripts*\ , \ *postscripts*\ , \ *power*\ , \ *pprofile*\ , \ *prescripts-begin*\ , \ *prescripts-end*\ , \ *primarynic*\ , \ *privkey*\ , \ *privtype*\ , \ *productkey*\ , \ *profile*\ , \ *protocol*\ , \ *provmethod*\ , \ *rack*\ , \ *room*\ , \ *routenames*\ , \ *seclevel*\ , \ *serial*\ , \ *serialflow*\ , \ *serialport*\ , \ *serialspeed*\ , \ *servicenode*\ , \ *setupconserver*\ , \ *setupdhcp*\ , \ *setupftp*\ , \ *setupipforward*\ , \ *setupldap*\ , \ *setupnameserver*\ , \ *setupnfs*\ , \ *setupnim*\ , \ *setupntp*\ , \ *setupproxydhcp*\ , \ *setuptftp*\ , \ *sfp*\ , \ *side*\ , \ *slot*\ , \ *slotid*\ , \ *slots*\ , \ *snmpauth*\ , \ *snmppassword*\ , \ *snmpprivacy*\ , \ *snmpuser*\ , \ *snmpusername*\ , \ *snmpversion*\ , \ *storagcontroller*\ , \ *storagetype*\ , \ *supernode*\ , \ *supportedarchs*\ , \ *supportproxydhcp*\ , \ *switch*\ , \ *switchinterface*\ , \ *switchport*\ , \ *switchtype*\ , \ *switchvlan*\ , \ *syslog*\ , \ *termport*\ , \ *termserver*\ , \ *tftpdir*\ , \ *tftpserver*\ , \ *unit*\ , \ *urlpath*\ , \ *usercomment*\ , \ *userid*\ , \ *username*\ , \ *vmbeacon*\ , \ *vmbootorder*\ , \ *vmcfgstore*\ , \ *vmcluster*\ , \ *vmcpus*\ , \ *vmhost*\ , \ *vmmanager*\ , \ *vmmaster*\ , \ *vmmemory*\ , \ *vmnicnicmodel*\ , \ *vmnics*\ , \ *vmothersetting*\ , \ *vmphyslots*\ , \ *vmstorage*\ , \ *vmstoragecache*\ , \ *vmstorageformat*\ , \ *vmstoragemodel*\ , \ *vmtextconsole*\ , \ *vmvirtflags*\ , \ *vmvncport*\ , \ *webport*\ , \ *wherevals*\ , \ *xcatmaster*\
\ **group Attributes:**\ \ *addkcmdline*\ , \ *arch*\ , \ *authdomain*\ , \ *authkey*\ , \ *authtype*\ , \ *bmc*\ , \ *bmcpassword*\ , \ *bmcport*\ , \ *bmcusername*\ , \ *bmcvlantag*\ , \ *cfgmgr*\ , \ *cfgmgtroles*\ , \ *cfgserver*\ , \ *chain*\ , \ *chassis*\ , \ *cmdmapping*\ , \ *community*\ , \ *cons*\ , \ *conserver*\ , \ *consoleenabled*\ , \ *consoleondemand*\ , \ *consport*\ , \ *cpucount*\ , \ *cputype*\ , \ *currchain*\ , \ *currstate*\ , \ *dhcpinterfaces*\ , \ *disksize*\ , \ *displayname*\ , \ *dockercpus*\ , \ *dockerflag*\ , \ *dockerhost*\ , \ *dockermemory*\ , \ *dockernics*\ , \ *domainadminpassword*\ , \ *domainadminuser*\ , \ *domaintype*\ , \ *getmac*\ , \ *groupname*\ , \ *grouptype*\ , \ *hcp*\ , \ *height*\ , \ *hostcluster*\ , \ *hostinterface*\ , \ *hostmanager*\ , \ *hostnames*\ , \ *hosttype*\ , \ *hwtype*\ , \ *id*\ , \ *initrd*\ , \ *installnic*\ , \ *interface*\ , \ *ip*\ , \ *iscsipassword*\ , \ *iscsiserver*\ , \ *iscsitarget*\ , \ *iscsiuserid*\ , \ *kcmdline*\ , \ *kernel*\ , \ *linkports*\ , \ *mac*\ , \ *membergroups*\ , \ *members*\ , \ *memory*\ , \ *mgt*\ , \ *micbridge*\ , \ *michost*\ , \ *micid*\ , \ *miconboot*\ , \ *micpowermgt*\ , \ *micvlog*\ , \ *migrationdest*\ , \ *monserver*\ , \ *mpa*\ , \ *mtm*\ , \ *nameservers*\ , \ *netboot*\ , \ *nfsdir*\ , \ *nfsserver*\ , \ *nicaliases*\ , \ *niccustomscripts*\ , \ *nicdevices*\ , \ *nicextraparams*\ , \ *nichostnameprefixes*\ , \ *nichostnamesuffixes*\ , \ *nicips*\ , \ *nicnetworks*\ , \ *nicsadapter*\ , \ *nictypes*\ , \ *nimserver*\ , \ *nodetype*\ , \ *ondiscover*\ , \ *os*\ , \ *osvolume*\ , \ *otherinterfaces*\ , \ *ou*\ , \ *outlet*\ , \ *parent*\ , \ *passwd.HMC*\ , \ *passwd.admin*\ , \ *passwd.celogin*\ , \ *passwd.general*\ , \ *passwd.hscroot*\ , \ *password*\ , \ *pdu*\ , \ *pdutype*\ , \ *postbootscripts*\ , \ *postscripts*\ , \ *power*\ , \ *pprofile*\ , \ *prescripts-begin*\ , \ *prescripts-end*\ , \ *primarynic*\ , \ *privkey*\ , \ *privtype*\ , \ *productkey*\ , \ *profile*\ , \ *protocol*\ , \ *provmethod*\ , \ *rack*\ , \ *room*\ , \ *routenames*\ , \ *seclevel*\ , \ *serial*\ , \ *serialflow*\ , \ *serialport*\ , \ *serialspeed*\ , \ *servicenode*\ , \ *setupconserver*\ , \ *setupdhcp*\ , \ *setupftp*\ , \ *setupipforward*\ , \ *setupldap*\ , \ *setupnameserver*\ , \ *setupnfs*\ , \ *setupnim*\ , \ *setupntp*\ , \ *setupproxydhcp*\ , \ *setuptftp*\ , \ *sfp*\ , \ *side*\ , \ *slot*\ , \ *slotid*\ , \ *slots*\ , \ *snmpauth*\ , \ *snmppassword*\ , \ *snmpprivacy*\ , \ *snmpuser*\ , \ *snmpusername*\ , \ *snmpversion*\ , \ *storagcontroller*\ , \ *storagetype*\ , \ *supernode*\ , \ *supportedarchs*\ , \ *supportproxydhcp*\ , \ *switch*\ , \ *switchinterface*\ , \ *switchport*\ , \ *switchtype*\ , \ *switchvlan*\ , \ *syslog*\ , \ *termport*\ , \ *termserver*\ , \ *tftpdir*\ , \ *tftpserver*\ , \ *unit*\ , \ *urlpath*\ , \ *usercomment*\ , \ *userid*\ , \ *username*\ , \ *vmbeacon*\ , \ *vmbootorder*\ , \ *vmcfgstore*\ , \ *vmcluster*\ , \ *vmcpus*\ , \ *vmhost*\ , \ *vmmanager*\ , \ *vmmaster*\ , \ *vmmemory*\ , \ *vmnicnicmodel*\ , \ *vmnics*\ , \ *vmothersetting*\ , \ *vmphyslots*\ , \ *vmstorage*\ , \ *vmstoragecache*\ , \ *vmstorageformat*\ , \ *vmstoragemodel*\ , \ *vmtextconsole*\ , \ *vmvirtflags*\ , \ *vmvncport*\ , \ *webport*\ , \ *wherevals*\ , \ *xcatmaster*\
***********
@@ -209,6 +209,12 @@ group Attributes:
\ **consoleenabled**\ (nodehm.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.
\ **consoleondemand**\ (nodehm.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.
@@ -19,7 +19,7 @@ SYNOPSIS
********
\ **node Attributes:**\ \ *addkcmdline*\ , \ *appstatus*\ , \ *appstatustime*\ , \ *arch*\ , \ *authdomain*\ , \ *authkey*\ , \ *authtype*\ , \ *bmc*\ , \ *bmcpassword*\ , \ *bmcport*\ , \ *bmcusername*\ , \ *bmcvlantag*\ , \ *cfgmgr*\ , \ *cfgmgtroles*\ , \ *cfgserver*\ , \ *chain*\ , \ *chassis*\ , \ *cmdmapping*\ , \ *community*\ , \ *cons*\ , \ *conserver*\ , \ *consoleondemand*\ , \ *consport*\ , \ *cpucount*\ , \ *cputype*\ , \ *currchain*\ , \ *currstate*\ , \ *dhcpinterfaces*\ , \ *disksize*\ , \ *displayname*\ , \ *dockercpus*\ , \ *dockerflag*\ , \ *dockerhost*\ , \ *dockermemory*\ , \ *dockernics*\ , \ *domainadminpassword*\ , \ *domainadminuser*\ , \ *domaintype*\ , \ *getmac*\ , \ *groups*\ , \ *hcp*\ , \ *height*\ , \ *hidden*\ , \ *hostcluster*\ , \ *hostinterface*\ , \ *hostmanager*\ , \ *hostnames*\ , \ *hosttype*\ , \ *hwtype*\ , \ *id*\ , \ *initrd*\ , \ *installnic*\ , \ *interface*\ , \ *ip*\ , \ *iscsipassword*\ , \ *iscsiserver*\ , \ *iscsitarget*\ , \ *iscsiuserid*\ , \ *kcmdline*\ , \ *kernel*\ , \ *linkports*\ , \ *mac*\ , \ *memory*\ , \ *mgt*\ , \ *micbridge*\ , \ *michost*\ , \ *micid*\ , \ *miconboot*\ , \ *micpowermgt*\ , \ *micvlog*\ , \ *migrationdest*\ , \ *monserver*\ , \ *mpa*\ , \ *mtm*\ , \ *nameservers*\ , \ *netboot*\ , \ *nfsdir*\ , \ *nfsserver*\ , \ *nicaliases*\ , \ *niccustomscripts*\ , \ *nicdevices*\ , \ *nicextraparams*\ , \ *nichostnameprefixes*\ , \ *nichostnamesuffixes*\ , \ *nicips*\ , \ *nicnetworks*\ , \ *nicsadapter*\ , \ *nictypes*\ , \ *nimserver*\ , \ *node*\ , \ *nodetype*\ , \ *ondiscover*\ , \ *os*\ , \ *osvolume*\ , \ *otherinterfaces*\ , \ *ou*\ , \ *outlet*\ , \ *parent*\ , \ *passwd.HMC*\ , \ *passwd.admin*\ , \ *passwd.celogin*\ , \ *passwd.general*\ , \ *passwd.hscroot*\ , \ *password*\ , \ *pdu*\ , \ *pdutype*\ , \ *postbootscripts*\ , \ *postscripts*\ , \ *power*\ , \ *pprofile*\ , \ *prescripts-begin*\ , \ *prescripts-end*\ , \ *primarynic*\ , \ *primarysn*\ , \ *privkey*\ , \ *privtype*\ , \ *productkey*\ , \ *profile*\ , \ *protocol*\ , \ *provmethod*\ , \ *rack*\ , \ *room*\ , \ *routenames*\ , \ *seclevel*\ , \ *serial*\ , \ *serialflow*\ , \ *serialport*\ , \ *serialspeed*\ , \ *servicenode*\ , \ *setupconserver*\ , \ *setupdhcp*\ , \ *setupftp*\ , \ *setupipforward*\ , \ *setupldap*\ , \ *setupnameserver*\ , \ *setupnfs*\ , \ *setupnim*\ , \ *setupntp*\ , \ *setupproxydhcp*\ , \ *setuptftp*\ , \ *sfp*\ , \ *side*\ , \ *slot*\ , \ *slotid*\ , \ *slots*\ , \ *snmpauth*\ , \ *snmppassword*\ , \ *snmpprivacy*\ , \ *snmpuser*\ , \ *snmpusername*\ , \ *snmpversion*\ , \ *status*\ , \ *statustime*\ , \ *storagcontroller*\ , \ *storagetype*\ , \ *supernode*\ , \ *supportedarchs*\ , \ *supportproxydhcp*\ , \ *switch*\ , \ *switchinterface*\ , \ *switchport*\ , \ *switchtype*\ , \ *switchvlan*\ , \ *syslog*\ , \ *termport*\ , \ *termserver*\ , \ *tftpdir*\ , \ *tftpserver*\ , \ *unit*\ , \ *updatestatus*\ , \ *updatestatustime*\ , \ *urlpath*\ , \ *usercomment*\ , \ *userid*\ , \ *username*\ , \ *vmbeacon*\ , \ *vmbootorder*\ , \ *vmcfgstore*\ , \ *vmcluster*\ , \ *vmcpus*\ , \ *vmhost*\ , \ *vmmanager*\ , \ *vmmaster*\ , \ *vmmemory*\ , \ *vmnicnicmodel*\ , \ *vmnics*\ , \ *vmothersetting*\ , \ *vmphyslots*\ , \ *vmstorage*\ , \ *vmstoragecache*\ , \ *vmstorageformat*\ , \ *vmstoragemodel*\ , \ *vmtextconsole*\ , \ *vmvirtflags*\ , \ *vmvncport*\ , \ *webport*\ , \ *xcatmaster*\ , \ *zonename*\
\ **node Attributes:**\ \ *addkcmdline*\ , \ *appstatus*\ , \ *appstatustime*\ , \ *arch*\ , \ *authdomain*\ , \ *authkey*\ , \ *authtype*\ , \ *bmc*\ , \ *bmcpassword*\ , \ *bmcport*\ , \ *bmcusername*\ , \ *bmcvlantag*\ , \ *cfgmgr*\ , \ *cfgmgtroles*\ , \ *cfgserver*\ , \ *chain*\ , \ *chassis*\ , \ *cmdmapping*\ , \ *community*\ , \ *cons*\ , \ *conserver*\ , \ *consoleenabled*\ , \ *consoleondemand*\ , \ *consport*\ , \ *cpucount*\ , \ *cputype*\ , \ *currchain*\ , \ *currstate*\ , \ *dhcpinterfaces*\ , \ *disksize*\ , \ *displayname*\ , \ *dockercpus*\ , \ *dockerflag*\ , \ *dockerhost*\ , \ *dockermemory*\ , \ *dockernics*\ , \ *domainadminpassword*\ , \ *domainadminuser*\ , \ *domaintype*\ , \ *getmac*\ , \ *groups*\ , \ *hcp*\ , \ *height*\ , \ *hidden*\ , \ *hostcluster*\ , \ *hostinterface*\ , \ *hostmanager*\ , \ *hostnames*\ , \ *hosttype*\ , \ *hwtype*\ , \ *id*\ , \ *initrd*\ , \ *installnic*\ , \ *interface*\ , \ *ip*\ , \ *iscsipassword*\ , \ *iscsiserver*\ , \ *iscsitarget*\ , \ *iscsiuserid*\ , \ *kcmdline*\ , \ *kernel*\ , \ *linkports*\ , \ *mac*\ , \ *memory*\ , \ *mgt*\ , \ *micbridge*\ , \ *michost*\ , \ *micid*\ , \ *miconboot*\ , \ *micpowermgt*\ , \ *micvlog*\ , \ *migrationdest*\ , \ *monserver*\ , \ *mpa*\ , \ *mtm*\ , \ *nameservers*\ , \ *netboot*\ , \ *nfsdir*\ , \ *nfsserver*\ , \ *nicaliases*\ , \ *niccustomscripts*\ , \ *nicdevices*\ , \ *nicextraparams*\ , \ *nichostnameprefixes*\ , \ *nichostnamesuffixes*\ , \ *nicips*\ , \ *nicnetworks*\ , \ *nicsadapter*\ , \ *nictypes*\ , \ *nimserver*\ , \ *node*\ , \ *nodetype*\ , \ *ondiscover*\ , \ *os*\ , \ *osvolume*\ , \ *otherinterfaces*\ , \ *ou*\ , \ *outlet*\ , \ *parent*\ , \ *passwd.HMC*\ , \ *passwd.admin*\ , \ *passwd.celogin*\ , \ *passwd.general*\ , \ *passwd.hscroot*\ , \ *password*\ , \ *pdu*\ , \ *pdutype*\ , \ *postbootscripts*\ , \ *postscripts*\ , \ *power*\ , \ *pprofile*\ , \ *prescripts-begin*\ , \ *prescripts-end*\ , \ *primarynic*\ , \ *primarysn*\ , \ *privkey*\ , \ *privtype*\ , \ *productkey*\ , \ *profile*\ , \ *protocol*\ , \ *provmethod*\ , \ *rack*\ , \ *room*\ , \ *routenames*\ , \ *seclevel*\ , \ *serial*\ , \ *serialflow*\ , \ *serialport*\ , \ *serialspeed*\ , \ *servicenode*\ , \ *setupconserver*\ , \ *setupdhcp*\ , \ *setupftp*\ , \ *setupipforward*\ , \ *setupldap*\ , \ *setupnameserver*\ , \ *setupnfs*\ , \ *setupnim*\ , \ *setupntp*\ , \ *setupproxydhcp*\ , \ *setuptftp*\ , \ *sfp*\ , \ *side*\ , \ *slot*\ , \ *slotid*\ , \ *slots*\ , \ *snmpauth*\ , \ *snmppassword*\ , \ *snmpprivacy*\ , \ *snmpuser*\ , \ *snmpusername*\ , \ *snmpversion*\ , \ *status*\ , \ *statustime*\ , \ *storagcontroller*\ , \ *storagetype*\ , \ *supernode*\ , \ *supportedarchs*\ , \ *supportproxydhcp*\ , \ *switch*\ , \ *switchinterface*\ , \ *switchport*\ , \ *switchtype*\ , \ *switchvlan*\ , \ *syslog*\ , \ *termport*\ , \ *termserver*\ , \ *tftpdir*\ , \ *tftpserver*\ , \ *unit*\ , \ *updatestatus*\ , \ *updatestatustime*\ , \ *urlpath*\ , \ *usercomment*\ , \ *userid*\ , \ *username*\ , \ *vmbeacon*\ , \ *vmbootorder*\ , \ *vmcfgstore*\ , \ *vmcluster*\ , \ *vmcpus*\ , \ *vmhost*\ , \ *vmmanager*\ , \ *vmmaster*\ , \ *vmmemory*\ , \ *vmnicnicmodel*\ , \ *vmnics*\ , \ *vmothersetting*\ , \ *vmphyslots*\ , \ *vmstorage*\ , \ *vmstoragecache*\ , \ *vmstorageformat*\ , \ *vmstoragemodel*\ , \ *vmtextconsole*\ , \ *vmvirtflags*\ , \ *vmvncport*\ , \ *webport*\ , \ *xcatmaster*\ , \ *zonename*\
***********
@@ -221,6 +221,12 @@ node Attributes:
\ **consoleenabled**\ (nodehm.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.
\ **consoleondemand**\ (nodehm.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.
@@ -19,7 +19,7 @@ SYNOPSIS
********
\ **pdu Attributes:**\ \ *machinetype*\ , \ *modelnum*\ , \ *node*\ , \ *nodetype*\ , \ *outlet*\ , \ *serialnum*\
\ **pdu Attributes:**\ \ *node*\ , \ *nodetype*\ , \ *outlet*\
***********
@@ -39,14 +39,6 @@ pdu Attributes:
\ **machinetype**\ (pdu.machinetype)
\ **modelnum**\ (pdu.modelnum)
\ **node**\ (pdu.node)
The hostname/address of the pdu to which the settings apply
@@ -65,10 +57,6 @@ pdu Attributes:
\ **serialnum**\ (pdu.serialnum)
********
SEE ALSO
@@ -51,7 +51,7 @@ 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
the console nodes by 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
@@ -8,11 +8,11 @@ Internet Repository
**[xcat-core]**
For the xCAT build you want to install, download the ``xCAT-core.repo`` file and copy to ``/etc/yum.repos.d``
For the xCAT build you want to install, download the ``xcat-core.repo`` file and copy to ``/etc/yum.repos.d``
**[xcat-dep]**
From the `xCAT-dep Online Repository <http://xcat.org/files/xcat/repos/yum/xcat-dep/>`_, navigate to the correct subdirectory for the target machine and download the ``xCAT-dep.repo`` file and copy to ``/etc/yum.repos.d``.
From the `xCAT-dep Online Repository <http://xcat.org/files/xcat/repos/yum/xcat-dep/>`_, navigate to the correct subdirectory for the target machine and download the ``xcat-dep.repo`` file and copy to ``/etc/yum.repos.d``.
If using internet repositories, continue to the next step to install xCAT.
@@ -8,11 +8,11 @@ Internet Repository
**[xcat-core]**
For the xCAT build you want to install, download the ``xCAT-core.repo`` file and copy to ``/etc/zypp/repos.d``
For the xCAT build you want to install, download the ``xcat-core.repo`` file and copy to ``/etc/zypp/repos.d``
**[xcat-dep]**
From the `xCAT-dep Online Repository <http://xcat.org/files/xcat/repos/yum/xcat-dep/>`_, navigate to the correct subdirectory for the target machine and download the ``xCAT-dep.repo`` file and copy to ``/etc/zypp/repos.d``.
From the `xCAT-dep Online Repository <http://xcat.org/files/xcat/repos/yum/xcat-dep/>`_, navigate to the correct subdirectory for the target machine and download the ``xcat-dep.repo`` file and copy to ``/etc/zypp/repos.d``.
If using internet repositories, continue to the next step to install xCAT.
+17 -1
View File
@@ -7,6 +7,22 @@ The following table is a summary of the new operating system (OS), hardware, and
* **SLES** - Suse Linux Enterprise Server
* **UBT** - Ubuntu
xCAT 2.14.x
-----------
+---------------------------------+---------------+-------------+----------------------------------+
|xCAT |New OS |New |New Feature |
|Version | |Hardware | |
+=================================+===============+=============+==================================+
|| xCAT 2.14 |- RHEL 7.5 | |- OpenBMC support in python: |
|| 2018/4/20 | | | |
|| | | | rspconfig,reventlog |
| `2.14 Release Notes <https:// | | | |
| github.com/xcat2/xcat-core/wiki | | |- Performance Tuning doc update |
| /XCAT_2.14_Release_Notes>`_ | | | |
+---------------------------------+---------------+-------------+----------------------------------+
xCAT 2.13.x
-----------
@@ -59,7 +75,7 @@ xCAT 2.13.x
+---------------------------------+---------------+-------------+----------------------------------+
|| xCAT 2.13.7 | | |- OpenBMC support: |
|| 2017/9/22 | | | |
|| | | | rflash for OpenBMC and PNOR |
|| | | | rflash for OpenBMC and Host |
| `2.13.7 Release Notes <https:// | | | |
| github.com/xcat2/xcat-core/wiki | | | reventlog to get/clear event log|
| /XCAT_2.13.7_Release_Notes>`_ | | | |
@@ -9,9 +9,9 @@ Collect the required files
Collect the following files and put them into a directory on the Management Node.
* pUpdate
* pnor
* bmc
* pUpdate utility
* .pnor for host
* .bin for bmc
If running ``rflash`` in Hierarchy, the firmware files/directory must be accessible on the Service Nodes.
@@ -26,7 +26,7 @@ The ``pUpdate`` utility is leveraged in doing the firmware update against the ta
* power off the host
* flash bmc and reboot
* flash pnor
* flash host
* power on the host
Monitor the progress for the nodes by looking at the files under ``/var/log/xcat/rflash/``.
@@ -3,7 +3,7 @@ Python framework
When testing the scale up of xCAT commands against OpenBMC REST API, it was evident that the Perl framework of xCAT did not scale well and was not sending commands to the BMCs in a true parallel fashion.
The team investigated the possibility of using Python framework
The team investigated the possibility of using Python framework. This support is implemented using Python 2.x framework.
.. toctree::
:maxdepth: 2
+4 -2
View File
@@ -1129,12 +1129,15 @@ sub handle_response {
return;
}
my $msgsource;
my $msgsource = "";
if ($ENV{'XCATSHOWSVR'}) {
unless ($rsp->{NoSvrPrefix}) { # some plugins could disable the prefix forcely by seting the flag in response.
$msgsource = $rsp->{xcatdsource}->[0] if ($rsp->{xcatdsource});
}
}
if ($rsp->{host}) {
$msgsource = $rsp->{xcatdsource}->[0] if ($rsp->{xcatdsource});
}
#print "in handle_response\n";
# Handle errors
@@ -1186,7 +1189,6 @@ sub handle_response {
}
}
if ($rsp->{info}) {
#print "printing info\n";
if (ref($rsp->{info}) eq 'ARRAY') {
foreach my $text (@{ $rsp->{info} }) {
+7 -2
View File
@@ -716,7 +716,8 @@ sub getOSnodes
Determines the server node names as known by a lists of nodes.
Arguments:
A list of node names.
$nodes: A list of node names.
$skipfacing: do not get facing ip when noderes.xcatmaster is not set
Returns:
A hash ref of arrays, the key is the service node pointing to
@@ -736,6 +737,7 @@ sub get_server_nodes
my $class = shift;
my $callback = shift;
my $nodes = shift;
my $skipfacing=shift;
my @nodelist;
if ($nodes)
@@ -760,12 +762,15 @@ sub get_server_nodes
my $xcatmaster = $xcatmasters->{$node}->[0]->{xcatmaster};
$serv = xCAT::NetworkUtils->getipaddr($xcatmaster);
}
else
elsif (!$skipfacing)
{
# get ip facing node
my @servd = xCAT::NetworkUtils->my_ip_facing($node);
unless ($servd[0]) { $serv = $servd[1]; }
}
else{
next;
}
chomp $serv;
if (xCAT::NetworkUtils->validate_ip($serv)) {
+6 -1
View File
@@ -356,7 +356,7 @@ sub dump_mac_info {
$ret{$switch}->{ErrorStr} = $self->{macinfo}->{$switch}->{ErrorStr};
# To show the error message that the username/password related error is for SNMP only
if ($ret{$switch}->{ErrorStr} =~ /user\s*name|password/i) {
if ($ret{$switch}->{ErrorStr} =~ /user\s*name|password$/i) {
$ret{$switch}->{ErrorStr} .= " through SNMP";
}
} else {
@@ -729,6 +729,11 @@ sub refresh_switch {
my @res=xCAT::Utils->runcmd("ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no $switch 'bridge fdb show|grep -i -v permanent|tr A-Z a-z 2>/dev/null' 2>/dev/null",-1);
if ($::RUNCMD_RC) {
xCAT::MsgUtils->message("S", "Failed to get mac table with ssh to $switch, fall back to snmp! To obtain mac table with ssh, please make sure the passwordless root ssh to $switch is available");
if ($self->{collect_mac_info}) {
my $errmsg = "Failed to get MAC table from $switch. Make sure passwordless SSH to the switch is enabled.";
$self->{macinfo}->{$switch}->{ErrorStr} = $errmsg;
return;
}
}else{
foreach (@res){
if($_ =~ m/^([0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}) dev swp([0-9]+) vlan ([0-9]+) .*/){
+115 -4
View File
@@ -18,6 +18,8 @@ use Socket;
use File::Path;
use constant PERF_LOG => "/var/log/xcat/perf.log";
my $host = "";
my $isSN = xCAT::Utils->isServiceNode();
$::NOK = -1;
$::OK = 0;
@@ -484,7 +486,8 @@ sub message
if ($errstr)
{
print $stdouterrf
"Unable to log $rsp to syslog because of $errstr\n";
"Error: Unable to log to syslog: $errstr\n";
print "$rsp\n";
}
}
@@ -546,6 +549,106 @@ sub message
return;
}
#-----------------------------------------------------------------------------
=head3 error_message
A wrap function for message. If $callback is not defined, send the log to
syslog, otherwise, send error message to client. Print service host if runs
on service node.
Example:
xCAT::MsgUtils->error_message($msg, $callback);
=cut
#-----------------------------------------------------------------------------
sub error_message
{
shift;
my $msg = shift;
my $callback = shift;
my $rsp;
$rsp->{data}->[0] = $msg;
if (!defined($callback)) {
message(undef, "S", $rsp, undef);
return;
}
if ($isSN && !$host) {
my @hostinfo = xCAT::NetworkUtils->determinehostname();
$host = $hostinfo[-1];
}
$rsp->{host} = $host if $host;
message(undef, "E", $rsp, $callback);
}
#-----------------------------------------------------------------------------
=head3 info_message
A wrap function for message. If $callback is not defined, send the log to
syslog, otherwise, send info message to client. Print service host if runs
on service node.
Example:
xCAT::MsgUtils->info_message($msg, $callback);
=cut
#-----------------------------------------------------------------------------
sub info_message
{
shift;
my $msg = shift;
my $callback = shift;
my $rsp;
$rsp->{data}->[0] = $msg;
if (!defined($callback)) {
message(undef, "S", $rsp, undef);
return;
}
if ($isSN && !$host) {
my @hostinfo = xCAT::NetworkUtils->determinehostname();
$host = $hostinfo[-1];
}
$rsp->{host} = $host if $host;
message(undef, "I", $rsp, $callback);
}
#-----------------------------------------------------------------------------
=head3 warn_message
A wrap function for message. If $callback is not defined, send the log to
syslog, otherwise, send warning message to client. Print service host if runs
on service node.
Example:
xCAT::MsgUtils->warn_message($msg, $callback);
=cut
#-----------------------------------------------------------------------------
sub warn_message
{
shift;
my $msg = shift;
my $callback = shift;
my $rsp;
$rsp->{data}->[0] = $msg;
if (!defined($callback)) {
message(undef, "S", $rsp, undef);
return;
}
if ($isSN && !$host) {
my @hostinfo = xCAT::NetworkUtils->determinehostname();
$host = $hostinfo[-1];
}
$rsp->{host} = $host if $host;
message(undef, "W", $rsp, $callback);
}
#--------------------------------------------------------------------------------
=head2 xCAT Logging Routines
@@ -794,9 +897,6 @@ sub trace() {
if (($level eq "I") || ($level eq "i")) { $prefix = "INFO"; }
if (($level eq "D") || ($level eq "d")) { $prefix = "DEBUG"; }
my @tmp = xCAT::TableUtils->get_site_attribute("xcatdebugmode");
my $xcatdebugmode = $tmp[0];
if (($level eq "E")
|| ($level eq "e")
|| ($level eq "I")
@@ -809,8 +909,15 @@ sub trace() {
syslog("$prefix", $msg);
closelog();
};
if ($@) {
print "Error: Unable to log to syslog: $@\n";
print "$msg\n";
}
return;
}
my @tmp = xCAT::TableUtils->get_site_attribute("xcatdebugmode");
my $xcatdebugmode = $tmp[0];
if (($level eq "D")
|| ($level eq "d")) {
if (($verbose == 1) || ($xcatdebugmode eq "1") || ($xcatdebugmode eq "2")) {
@@ -819,6 +926,10 @@ sub trace() {
openlog("xcat", "nofatal,pid", "local4");
syslog("$prefix", $msg);
closelog();
};
if ($@) {
print "Error: Unable to log to syslog: $@\n";
print "$msg\n";
}
}
}
+11 -1
View File
@@ -86,7 +86,7 @@ my %usage = (
",
"rbeacon.openbmc" =>
"OpenPOWER (OpenBMC) specific:
rbeacon [on|off]
rbeacon [on|off|stat]
",
"rvitals" => "",
"rvitals.common" =>
@@ -185,6 +185,16 @@ my %usage = (
rspconfig <noderange> [hostname|ntpservers]
rspconfig <noderange> [hostname=<*|hostname>|ntpservers=<ntpservers>]
rspconfig <noderange> sshcfg
rspconfig <noderange> powerrestorepolicy
rspconfig <noderange> powerrestorepolicy={always_on|restore|always_off}
rspconfig <noderange> powersupplyredundancy
rspconfig <noderange> powersupplyredundancy={disabled|enabled}
rspconfig <noderange> timesyncmethod
rspconfig <noderange> timesyncmethod={ntp|manual}
rspconfig <noderange> bootmode
rspconfig <noderange> bootmode={safe|regular|setup}
rspconfig <noderange> autoreboot
rspconfig <noderange> autoreboot={0|1}
",
"rspconfig.begin" =>
"BMC/MPA Common:
+8 -3
View File
@@ -129,9 +129,14 @@ sub check_pr_format{
$check_result_str .= "> **PR FORMAT CORRECT**";
send_back_comment("$check_result_str");
}else{
$check_result_str .= "> **PR FORMAT ERROR** : $checkrst";
send_back_comment("$check_result_str");
return 1;
if($checkrst =~ /milestone/ || $checkrst =~ /labels/){
$check_result_str .= "> **PR FORMAT WARNING** : $checkrst";
send_back_comment("$check_result_str");
}else{
$check_result_str .= "> **PR FORMAT ERROR** : $checkrst";
send_back_comment("$check_result_str");
return 1;
}
}
}
return 0;
+2 -2
View File
@@ -102,9 +102,9 @@ foreach (keys %ENV) {
}
}
# Allow to print server information when -V
# Allow to print server information when -V/--verbose
foreach (reverse(@ARGV)) {
if ($_ eq '-V') {
if ($_ eq '-V' || $_ eq '--verbose') {
$ENV{'XCATSHOWSVR'} = 1;
last;
}
+2 -2
View File
@@ -17,12 +17,12 @@ B<rbeacon> I<noderange> {B<on>|B<blink>|B<off>|B<stat>}
=head2 OpenPOWER OpenBMC:
B<rbeacon> I<noderange> {B<on>|B<off>}
B<rbeacon> I<noderange> {B<on>|B<off>|B<stat>}
=head1 DESCRIPTION
B<rbeacon> Turns beacon (a light on the front of the physical server) on/off/blink or gives status of a node or noderange.
B<rbeacon> Turns beacon (a light on the front and/or rear of the physical server) on/off/blink or gives status of a node or noderange.
=head1 EXAMPLES
+4 -4
View File
@@ -123,7 +123,7 @@ B<Note:> When using B<rflash> in hierarchical environment, the .tar file must be
B<-d>:
This option steamlines the update, activate, reboot BMC and reboot HOST procedure. It expects a directory containing both BMC and PNOR .tar files. When BMC and PNOR tar files are provided, the command will upload and activate firmware. After BMC becomes activate, it will reboot BMC. If BMC state is Ready, the command will reboot the HOST. If BMC state is NotReady, the command will exit.
This option steamlines the update, activate, reboot BMC and reboot HOST procedure. It expects a directory containing both BMC and Host .tar files. When BMC and Host tar files are provided, the command will upload and activate firmware. After BMC becomes activate, it will reboot BMC. If BMC state is Ready, the command will reboot the HOST. If BMC state is NotReady, the command will exit.
B<Note:> When using B<--no-host-reboot>, it will not reboot the host after BMC is reboot.
@@ -155,7 +155,7 @@ Specifies the directory where the raw data from rpm packages for each CEC/Frame
OpenPOWER BMC specific (using IPMI):
Used for IBM Power S822LC for Big Data systems only. Specifies the directory where the B<pUpdate> utility and at least one of BMC or PNOR update files are located. The utility and update files can be downloaded from FixCentral.
Used for IBM Power S822LC for Big Data systems only. Specifies the directory where the B<pUpdate> utility and at least one of BMC or Host update files are located. The utility and update files can be downloaded from FixCentral.
=item B<--activate> {B<concurrent> | B<disruptive>}
@@ -173,7 +173,7 @@ Used to recover the flash image in the permanent side of the chip to the tempora
OpenPOWER BMC specific (using IPMI):
Used for IBM Power S822LC for Big Data systems only. Used to recover the BMC with a BMC image downloaded from FixCentral.
Used for IBM Power S822LC for Big Data systems only. Used to recover the BMC with a BMC image downloaded from FixCentral. This option will only work if BMC is in "Brick protection" state.
=item B<--retry=>I<count>
@@ -245,7 +245,7 @@ Print verbose message to rflash log file (/var/log/xcat/rflash/fs3.log) when upd
rflash fs3 /firmware/8335_810.1543.20151021b_update.hpm -V
=item 6.
To update the firmware on IBM Power S822LC for Big Data machine specify the node name and the file path of the data directory containing pUpdate utility, both BMC and PNOR update files:
To update the firmware on IBM Power S822LC for Big Data machine specify the node name and the file path of the data directory containing pUpdate utility, both BMC and Host update files:
rflash briggs01 -d /root/supermicro/OP825
+1 -1
View File
@@ -32,7 +32,7 @@ B<rvitals> I<noderange> [B<temp>|B<voltage>|B<wattage>|B<fanspeed>|B<power>|B<le
=head2 OpenPOWER (OpenBMC) specific:
B<rvitals> I<noderange> [B<temp>|B<voltage>|B<wattage>|B<fanspeed>|B<power>|B<leds>|B<altitude>|B<all>]
B<rvitals> I<noderange> [B<temp>|B<voltage>|B<wattage>|B<fanspeed>|B<power>|B<leds>|B<altitude>|B<all>] [B<-V>| B<--verbose>]
=head1 B<Description>
+14 -6
View File
@@ -360,17 +360,17 @@ while :; do
logger -s -t $log_label -p local4.info "Running nextdestiny $XCATMASTER:$XCATPORT..."
destiny=`/bin/nextdestiny $XCATMASTER:$XCATPORT`
logger -s -t $log_label -p local4.info "nextdestiny - Complete."
elif [ "$dest" = ondiscover ]; then
logger -s -t $log_label -p local4.info "Running nextdestiny (ondiscover) $XCATMASTER:$XCATPORT..."
destiny=`/bin/nextdestiny $XCATMASTER:$XCATPORT`
logger -s -t $log_label -p local4.info "nextdestiny (ondiscover) - Complete."
elif [ "$dest" = runcmd ]; then
$destparameter
logger -s -t $log_label -p local4.info "Running nextdestiny $XCATMASTER:$XCATPORT..."
destiny=`/bin/nextdestiny $XCATMASTER:$XCATPORT`
dest=`echo $destiny|awk -F= '{print $1}'`
$destparameter
logger -s -t $log_label -p local4.info "nextdestiny - Complete."
elif [ "$dest" = runimage ]; then
logger -s -t $log_label -p local4.info "Running nextdestiny $XCATMASTER:$XCATPORT..."
destiny=`/bin/nextdestiny $XCATMASTER:$XCATPORT`
dest=`echo $destiny|awk -F= '{print $1}'`
logger -s -t $log_label -p local4.info "nextdestiny - Complete."
mkdir /tmp/`basename $destparameter`
cd /tmp/`basename $destparameter`
eval destparameter=$destparameter
@@ -390,12 +390,20 @@ while :; do
tar xvf `basename $destparameter`
./runme.sh
cd -
logger -s -t $log_label -p local4.info "Running nextdestiny $XCATMASTER:$XCATPORT..."
destiny=`/bin/nextdestiny $XCATMASTER:$XCATPORT`
dest=`echo $destiny|awk -F= '{print $1}'`
logger -s -t $log_label -p local4.info "nextdestiny - Complete."
elif [ "$dest" = "reboot" -o "$dest" = "boot" ]; then
logger -s -t $log_label -p local4.info "Running nextdestiny $XCATMASTER:$XCATPORT..."
/bin/nextdestiny $XCATMASTER:$XCATPORT
logger -s -t $log_label -p local4.info "nextdestiny - Complete."
if [ $IPMI_SUPPORT -ne 0 ]; then
ipmitool chassis bootdev pxe
# Set boot from network will cause OpenPOWER server wait at petitboot menu, so do nothing here
if uname -m | grep x86_64; then
ipmitool chassis bootdev pxe
fi
fi
reboot -f
elif [ "$dest" = "install" -o "$dest" = "netboot" ]; then
@@ -122,7 +122,7 @@ class RestSession(object):
response, err = sub.communicate()
if not response:
error = 'Error: Did not receive response from server after ' \
error = 'Did not receive response from server after ' \
'running command \'%s\'' % request_cmd
raise SelfServerException(error)
@@ -54,6 +54,7 @@ class ParallelNodesCommand(BaseCommand):
"""
self.inventory = inventory
self.callback = callback
self.cwd = kwargs.get('cwd')
self.debugmode = kwargs.get('debugmode')
self.verbose = kwargs.get('verbose')
@@ -7,7 +7,7 @@
import struct
import sys
import inspect
import re
import re, os
import logging
from logging.handlers import SysLogHandler
@@ -23,7 +23,11 @@ def getxCATLog(name=None):
return xl
def enableSyslog(name='xcat'):
h = SysLogHandler(address='/dev/log', facility=SysLogHandler.LOG_LOCAL4)
try:
h = SysLogHandler(address='/dev/log', facility=SysLogHandler.LOG_LOCAL4)
except:
# this will connect localhost:514
h = SysLogHandler(facility=SysLogHandler.LOG_LOCAL4)
h.setFormatter(logging.Formatter('%s: ' % name + '%(levelname)s %(message)s'))
logging.getLogger('xcatagent').addHandler(h)
@@ -82,6 +86,21 @@ def sort_string_with_numbers(origin_list):
new_list.sort()
return [string for __,string in new_list]
def mask_str2int(mask):
count_bit = lambda bin_str: len([i for i in bin_str if i=='1'])
mask_splited = mask.split('.')
mask_count = [count_bit(bin(int(i))) for i in mask_splited]
return sum(mask_count)
def mask_int2str(mask_int):
mask_num = (0x1 << 32) - (0x1 << (32 - mask_int))
return "%s.%s.%s.%s" % (str((mask_num >> 24) & 0xff), str((mask_num >>16)&0xff), str((mask_num >> 8) & 0xff), str(mask_num & 0xff))
def get_full_path(cwd, directory):
if not os.path.isabs(directory):
directory = os.path.join(cwd, directory)
return directory
class Messager(object):
def __init__(self, name=None):
self.logger = logging.getLogger(name or 'xcatagent')
@@ -145,7 +145,7 @@ class OpenBMCBmcConfigTask(ParallelNodesCommand):
for key in keys:
self._dump_download(obmc, node, str(key))
except SelfServerException as e:
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
def dump_process(self, **kw):
@@ -174,7 +174,7 @@ class OpenBMCBmcConfigTask(ParallelNodesCommand):
else:
self.callback.error('Could not find dump %s after waiting %d seconds.' % (dump_id, 20 * 15), node)
except SelfServerException as e:
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
def gard_clear(self, **kw):
@@ -188,7 +188,7 @@ class OpenBMCBmcConfigTask(ParallelNodesCommand):
obmc.clear_gard()
self.callback.info('%s: GARD cleared' % node)
except SelfServerException as e:
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
def pre_set_sshcfg(self, *arg, **kw):
@@ -296,14 +296,15 @@ rmdir \"/tmp/$userid\" \n")
return
else:
self._set_netinfo(netinfo_dict['ip'], netinfo_dict['netmask'],
netinfo_dict['gateway'], netinfo_dict['vlan'])
netinfo_dict['gateway'], netinfo_dict['vlan'], **kw)
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']
if kw['nodeinfo']['bmc'] != kw['nodeinfo']['bmcip']:
hostname = kw['nodeinfo']['bmc']
else:
return self.callback.error("Invalid OpenBMC Hostname %s, can't set to OpenBMC" % kw['nodeinfo']['bmc'], node)
self._set_apis_values("hostname", hostname, **kw)
self._get_netinfo(hostname=True, ntpserver=False, **kw)
return
@@ -324,6 +325,10 @@ rmdir \"/tmp/$userid\" \n")
if not netinfo:
return self.callback.error('No network information get', node)
if 'error' in netinfo:
self.callback.info('%s: %s' % (node, netinfo['error']))
return
bmcip = node_info['bmcip']
nic = self._get_facing_nic(bmcip, netinfo)
if not nic:
@@ -341,6 +346,10 @@ rmdir \"/tmp/$userid\" \n")
if nic in netinfo:
ntpservers = netinfo[nic]['ntpservers']
self.callback.info('%s: BMC NTP Servers: %s' % (node, ntpservers))
if ntpservers != None:
# Display a warning if the host in not powered off
# Time on the BMC is not synced while the host is powered on
self.callback.info('%s: Warning: time will not be synchronized until the host is powered off.' % node)
def _get_facing_nic(self, bmcip, netinfo):
for k,v in netinfo.items():
@@ -371,11 +380,20 @@ rmdir \"/tmp/$userid\" \n")
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)
except SelfServerException as e:
return self.callback.error(e.message, node)
except SelfClientException as e:
if e.code == 404:
return self.callback.error('404 Not Found - Requested endpoint does not exist or may ' \
'indicate function is not supported on this OpenBMC firmware.', node)
if e.code == 403:
return self.callback.error('403 Forbidden - Requested endpoint does not exist or may ' \
'indicate function is not yet supported by OpenBMC firmware.', node)
return self.callback.error(e.message, node)
self.callback.info("%s: BMC Setting %s..." % (node, openbmc.RSPCONFIG_APIS[key]['display_name']))
@@ -387,19 +405,111 @@ rmdir \"/tmp/$userid\" \n")
obmc.login()
value = obmc.get_apis_values(key)
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
except SelfServerException as e:
return self.callback.error(e.message, node)
except SelfClientException as e:
if e.code == 404:
return self.callback.error('404 Not Found - Requested endpoint does not exist or may ' \
'indicate function is not supported on this OpenBMC firmware.', node)
if e.code == 403:
return self.callback.error('403 Forbidden - Requested endpoint does not exist or may ' \
'indicate function is not yet supported by OpenBMC firmware.', node)
return self.callback.error(e.message, node)
str_value = '0.'+str(value)
if isinstance(value, dict):
str_value = str(value.values()[0])
elif value:
str_value = str(value)
else:
str_value = '0'
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):
def _print_bmc_netinfo(self, node, ip, netmask, gateway, vlan):
self.callback.info('%s: BMC IP: %s'% (node, ip))
self.callback.info('%s: BMC Netmask: %s' % (node, netmask))
self.callback.info('%s: BMC Gateway: %s' % (node, gateway))
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)
self.callback.info('%s: BMC VLAN ID: %s' % (node, vlan))
def _set_netinfo(self, ip, netmask, gateway, vlan=False, **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)
if 'error' in netinfo:
return self.callback.info('%s: %s' % (node, netinfo['error']))
bmcip = node_info['bmcip']
origin_nic = nic = self._get_facing_nic(bmcip, netinfo)
if not nic:
return self.callback.error('Can not get facing NIC for %s' % bmcip, node)
prefix = int(utils.mask_str2int(netmask))
if (ip == netinfo[nic]['ip'] and prefix == netinfo[nic]['netmask'] and
gateway == netinfo[nic]['gateway']):
if not vlan or vlan == str(netinfo[nic]['vlanid']):
self._print_bmc_netinfo(node, ip, netmask, gateway, vlan)
return
origin_type = netinfo[origin_nic]['ipsrc']
origin_ip_obj = netinfo[origin_nic]['ipobj']
if vlan:
pre_nic = nic.split('_')[0]
try:
obmc.set_vlan(pre_nic, vlan)
sleep( 15 )
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
return
nic = pre_nic + '_' + vlan
try:
obmc.set_netinfo(nic, ip, prefix, gateway)
sleep( 5 )
nic_netinfo = obmc.get_nic_netinfo(nic)
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
return
if not nic_netinfo:
return self.callback.error('Did not get info for NIC %s' % nic, node)
set_success = False
for net_id, attr in nic_netinfo.items():
if (attr['ip'] == ip and
attr["netmask"] == prefix and
attr['gateway'] == gateway):
set_success = True
if not set_success:
return self.callback.error('Config BMC IP failed', node)
try:
if origin_type == 'DHCP':
obmc.disable_dhcp(origin_nic)
elif origin_type == 'Static':
obmc.delete_ip_object(origin_nic, origin_ip_obj)
else:
self.callback.error('Get wrong Origin type %s for NIC %s IP object %s' % (origin_type, nic, origin_ip_obj), node)
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
self. _print_bmc_netinfo(node, ip, netmask, gateway, vlan)
def _get_netinfo(self, ip=False, ipsrc=False, netmask=False, gateway=False, vlan=False, hostname=False, ntpservers=False, **kw):
node = kw['node']
@@ -424,6 +534,10 @@ rmdir \"/tmp/$userid\" \n")
if hostname:
self.callback.info("%s: BMC Hostname: %s" %(node, bmchostname))
if 'error' in netinfo:
return self.callback.info('%s: %s' % (node, netinfo['error']))
dic_length = len(netinfo)
netinfodict = {'ip':[], 'netmask':[], 'gateway':[],
'vlan':[], 'ipsrc':[], 'ntpservers':[]}
@@ -432,7 +546,7 @@ rmdir \"/tmp/$userid\" \n")
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['netmask'].append("BMC Netmask"+addon_string+": %s" % utils.mask_int2str(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"])
@@ -26,7 +26,7 @@ class OpenBMCEventlogTask(ParallelNodesCommand):
number_to_display = 0
try:
# Number of records to display from the end
number_to_display = 0-int(num_to_display[0])
number_to_display = 0-int(num_to_display)
except Exception:
# All records to display
number_to_display = 0
@@ -56,7 +56,63 @@ class OpenBMCEventlogTask(ParallelNodesCommand):
def clear_all_ev_records(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_all_eventlog_records()
self.callback.info('%s: %s' % (node, "Logs cleared"))
except (SelfServerException, SelfClientException) as e:
self.callback.error('%s' % e.message, node)
def resolve_ev_records(self, resolve_list, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback, debugmode=self.debugmode, verbose=self.verbose)
try:
obmc.login()
# Get all eventlog records
eventlog_info_dict = obmc.get_eventlog_info()
keys = eventlog_info_dict.keys()
# Sort the keys in natural order
keys.sort(key=lambda x : int(x[0:]))
resolved, ids = resolve_list.split('=')
eventlog_ids_to_resolve = []
if ids.upper() == "LED":
# loop through eventlog_info_dict and collect LED ids to be resolved into a eventlog_ids_to_resolve array
for key in list(keys):
if "[LED]" in eventlog_info_dict[key]:
if "Resolved: 0" in eventlog_info_dict[key]:
eventlog_ids_to_resolve.append(key)
else:
if self.verbose:
self.callback.info('%s: Not resolving already resolved eventlog ID %s' % (node, key))
else:
# loop through list of ids and collect ids to resolve into a eventlog_ids_to_resolve array
for id_to_resolve in ids.split(','):
if id_to_resolve in eventlog_info_dict:
if "Resolved: 0" in eventlog_info_dict[id_to_resolve]:
eventlog_ids_to_resolve.append(id_to_resolve)
else:
if self.verbose:
self.callback.info('%s: Not resolving already resolved eventlog ID %s' % (node, id_to_resolve))
else:
self.callback.info('%s: Invalid ID: %s' % (node, id_to_resolve))
if len(eventlog_ids_to_resolve) == 0:
# At the end and there are no entries to resolve
self.callback.info('%s: No event log entries needed to be resolved' % node)
else:
# Resolve entries that were collected into the eventlog_ids_to_resolve array
obmc.resolve_event_log_entries(eventlog_ids_to_resolve)
for entry in eventlog_ids_to_resolve:
self.callback.info('%s: Resolved %s' % (node, entry))
except (SelfServerException, SelfClientException) as e:
self.callback.error('%s' % e.message, node)
@@ -0,0 +1,567 @@
#!/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
import os, re
from common import utils
from common.task import ParallelNodesCommand
from common.exceptions import SelfClientException, SelfServerException
from hwctl import openbmc_client as openbmc
import logging
logger = logging.getLogger('xcatagent')
XCAT_LOG_DIR = "/var/log/xcat"
XCAT_LOG_RFLASH_DIR = XCAT_LOG_DIR + "/rflash/"
class OpenBMCFlashTask(ParallelNodesCommand):
"""Executor for flash-related actions."""
activate_result = {}
firmware = {}
firmware_file = None
log_handle = {}
nodes_num = 0
def _msg_process(self, node, msg, msg_type='I', update_rc=False, checkv=False):
if msg_type == 'E':
self.callback.error(msg, node)
elif not checkv:
self.callback.info('%s: %s' % (node, msg))
elif self.verbose:
self.callback.info('%s: %s' % (node, msg))
if update_rc:
self.activate_result.update({node: msg})
if node not in self.log_handle:
log_file = XCAT_LOG_RFLASH_DIR + '/' + node + '.log'
self.log_handle.update({node: open(log_file, 'a')})
try:
self.log_handle[node].writelines(msg + '\n')
self.log_handle[node].flush()
except Exception as e:
self.callback.error('Failed to record rflash log for node %s' % node)
def _firmware_file_check(self, firmware_file, **kw):
target_file = utils.get_full_path(self.cwd, firmware_file)
self.firmware_file = target_file
if (not os.access(target_file, os.F_OK) or
not os.access(target_file, os.R_OK)):
error = 'Cannot access %s. Check the management ' \
'node and/or service nodes.' % target_file
self.callback.error(error)
raise Exception('Invalid firmware file %s' % target_file)
def validate_activate_firm(self, task, activate_arg, **kw):
if activate_arg.endswith('.tar'):
self._firmware_file_check(activate_arg)
else:
if not re.match('\A[0-9a-fA-F]+\Z', activate_arg):
self.callback.error('Invalid firmware ID %s' % activate_arg)
def validate_delete_firm(self, task, delete_id, **kw):
if not re.match('\A[0-9a-fA-F]+\Z', delete_id):
self.callback.error('Invalid firmware ID %s' % activate_arg)
def validate_upload_firm(self, task, upload_file, **kw):
self._firmware_file_check(upload_file)
def _get_firmware_version(self, target_file):
version = purpose = None
with open(target_file, 'r') as fh:
for line in fh:
if 'version=' in line:
version = line.split('=')[-1].strip()
if 'purpose=' in line:
purpose = line.split('=')[-1].strip().split('.')[-1]
if version and purpose:
break
return { version: {'purpose': purpose} }
def pre_activate_firm(self, task, activate_arg, **kw):
if not os.path.exists(XCAT_LOG_RFLASH_DIR):
os.makedirs(XCAT_LOG_RFLASH_DIR)
if activate_arg.endswith('.tar'):
version = self._get_firmware_version(self.firmware_file)
self.firmware.update(version)
self.callback.info('Attempting to upload %s, please wait...' % self.firmware_file)
else:
self.callback.info('Attempting to activate ID=%s, please wait..' % activate_arg)
self.nodes_num = len(self.inventory)
def pre_delete_firm(self, task, delete_id, **kw):
self.callback.info('Attempting to delete ID=%s, please wait..' % delete_id)
def pre_flash_process(self, task, directory, no_host_reboot, **kw):
if not os.path.exists(XCAT_LOG_RFLASH_DIR):
os.makedirs(XCAT_LOG_RFLASH_DIR)
directory = utils.get_full_path(self.cwd, directory)
tmp_dict = {'BMC': [], 'Host': []}
for filename in os.listdir(directory):
if filename.endswith('.tar'):
filename = os.path.join(directory, filename)
try:
version = self._get_firmware_version(filename)
except Exception as e:
continue
self.firmware.update(version)
for key, value in version.items():
tmp_dict[ value['purpose'] ].append(filename)
self.firmware[key].update({'file': filename})
bmc_file_num = len(tmp_dict['BMC'])
host_file_num = len(tmp_dict['Host'])
error = None
if not bmc_file_num:
error = 'No BMC tar file found in %s' % directory
elif not host_file_num:
error = 'No HOST tar file found in %s' % directory
elif bmc_file_num > 1:
error = 'More than 1 BMC tar file %s found in %s' \
% (' '.join(tmp_dict['BMC']), directory)
elif host_file_num > 1:
error = 'More than 1 HOST tar file %s found in %s' \
% (' '.join(tmp_dict['Host']), directory)
if error:
self.callback.error(error)
raise Exception('No or More tar file found')
self.callback.info('Attempting to upload %s and %s, please wait..' \
% (tmp_dict['BMC'][0], tmp_dict['Host'][0]))
self.nodes_num = len(self.inventory)
def pre_upload_firm(self, task, upload_arg, **kw):
if not os.path.exists(XCAT_LOG_RFLASH_DIR):
os.makedirs(XCAT_LOG_RFLASH_DIR)
self.callback.info('Attempting to upload %s, please wait...' % self.firmware_file)
def _get_firm_id(self, obmc, node):
mapping_ids = []
if self.firmware:
version_list = self.firmware.keys()
else:
return []
for i in range(6):
try:
has_functional, firm_obj_dict = obmc.list_firmware()
except (SelfServerException, SelfClientException) as e:
self._msg_process(node, e.message, msg_type='E', update_rc=True)
return []
for key, value in firm_obj_dict.items():
if value.version and value.version in version_list:
firm_id = key.split('-')[-1]
mapping_ids.append(firm_id)
msg = 'Firmware upload successful. ' \
'Attempting to activate firmware: %s (ID: %s)' \
% (value.version, firm_id)
self._msg_process(node, msg, update_rc=True)
version_list.remove(value.version)
if not version_list:
return mapping_ids
for i in version_list:
msg = 'Could not find ID for firmware %s to '\
'activate, waiting %d seconds and retry...' \
% (i, 10)
self._msg_process(node, msg, update_rc=True, checkv=True)
gevent.sleep ( 10 )
error = []
for i in version_list:
msg = 'Could not find firmware %s after waiting %d seconds.' % (i, 10*6)
error.qppend(msg)
self._msg_process(node, msg, msg_type='E')
if error:
msg = ' '.join(error)
self.activate_result.update({node: msg})
return []
def _check_id_status(self, obmc, check_ids, node, only_act=True):
firm_ids = check_ids
priority_ids = []
process_status = {}
for i in range(80):
try:
has_functional, firm_obj_dict = obmc.list_firmware()
except (SelfServerException, SelfClientException) as e:
return self._msg_process(node, e.message, msg_type='E', update_rc=True)
for key, value in firm_obj_dict.items():
key_id = key.split('-')[-1]
if key_id in firm_ids:
activation_state = value.active
firm_version = value.version
if activation_state == 'Failed':
activation_msg = 'Firmware %s activation failed.' % (firm_version)
self._msg_process(node, activation_msg, msg_type='E', update_rc=True)
firm_ids.remove(key_id)
if activation_state == 'Active':
activation_msg = 'Firmware %s activation successful.' % (firm_version)
self._msg_process(node, activation_msg, update_rc=True)
firm_ids.remove(key_id)
if value.priority != 0:
priority_ids.append(key_id)
if activation_state == 'Activating':
activating_progress_msg = 'Activating %s ... %s%%' \
% (firm_version, value.progress)
process_status[key_id] = activating_progress_msg
self._msg_process(node, activating_progress_msg, checkv=True)
if not firm_ids:
break
gevent.sleep( 15 )
error = []
for i in firm_ids:
msg = 'After %d seconds check the firmware id %s current status is "%s"' \
% (80*15, process_status[i], i)
error.append(msg)
self._msg_process(node, msg, msg_type='E')
if error:
msg = ' '.join(error)
self.activate_result.update({node: msg})
return
for i in priority_ids:
try:
obmc.set_priority(i)
except (SelfServerException, SelfClientException) as e:
msg = e.message
error.append(msg)
self._msg_process(node, msg, msg_type='E')
if error:
msg = ' '.join(error)
self.activate_result.update({node: msg})
return
self.activate_result.update({node: 'SUCCESS'})
def _reboot_to_effect(self, obmc, no_host_reboot, node):
self._msg_process(node, 'Firmware will be flashed on reboot, deleting all BMC diagnostics...')
try:
obmc.clear_dump('all')
except (SelfServerException, SelfClientException) as e:
self.callback.warn('%s: Could not clear BMC diagnostics successfully %s, ignoring...' % (node, e.message))
try:
obmc.reboot_bmc()
except (SelfServerException, SelfClientException) as e:
return self._msg_process(node, e.message, msg_type='E', update_rc=True)
self._msg_process(node, openbmc.RPOWER_STATES['bmcreboot'], update_rc=True)
gevent.sleep( 10 )
bmc_state = None
for i in range(20):
try:
obmc.login()
state = obmc.get_bmc_state()
bmc_state = state.get('bmc')
if bmc_state == 'Ready':
break
except (SelfServerException, SelfClientException) as e:
self._msg_process(node, e.message, checkv=True)
self._msg_process(node, 'Retry BMC state, wait for 15 seconds ...', update_rc=True)
gevent.sleep( 15 )
if bmc_state != 'Ready':
error = 'Sent bmcreboot but state did not change to BMC Ready after ' \
'waiting %s seconds. (State=BMC %s).' % (20*15, bmc_state)
return self._msg_process(node, error, msg_type='E', update_rc=True)
self._msg_process(node, 'BMC %s' % bmc_state, update_rc=True)
if no_host_reboot:
self.activate_result.update({node: 'SUCCESS'})
return
try:
obmc.set_power_state('off')
self.callback.update_node_attributes('status', node, 'powering-off')
off_flag = False
start_timeStamp = int(time.time())
for i in range (0, 30):
states = obmc.list_power_states()
state = obmc.get_host_state(states)
if openbmc.RPOWER_STATES.get(state) == '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)
return self._msg_process(node, error, update_rc=True)
ret = obmc.set_power_state('on')
self.callback.update_node_attributes('status', node, 'powering-on')
self._msg_process(node, 'reset')
self.activate_result.update({node: 'SUCCESS'})
except (SelfServerException, SelfClientException) as e:
self._msg_process(node, e.message, update_rc=True)
def activate_firm(self, activate_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()
except (SelfServerException, SelfClientException) as e:
return self._msg_process(node, e.message, msg_type='E', update_rc=True)
firmware_version = ''
if self.firmware_file:
firmware_version = self.firmware.keys()[0]
try:
obmc.upload_firmware(self.firmware_file)
except (SelfServerException, SelfClientException) as e:
return self._msg_process(node, e.message, msg_type='E', update_rc=True)
activate_ids = self._get_firm_id(obmc, node)
if not activate_ids:
return
activate_id = activate_ids[0]
else:
activate_id = activate_arg
error = ''
try:
obmc.activate_firmware(activate_id)
except SelfServerException as e:
error = e.message
except SelfClientException as e:
if e.code == 403:
error = 'Invalid ID provided to activate. ' \
'Use the -l option to view valid firmware IDs.'
else:
error = e.message
if error:
return self._msg_process(node, error, msg_type='E', update_rc=True)
msg = 'rflash %s started, please wait...' % firmware_version
self._msg_process(node, msg, checkv=True)
check_ids = [activate_id]
self._check_id_status(obmc, check_ids, node)
def delete_firm(self, delete_id, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
error = ''
try:
obmc.login()
except (SelfServerException, SelfClientException) as e:
return self.callback.error(e.message, node)
try:
has_functional, firm_obj_dict = obmc.list_firmware()
except (SelfServerException, SelfClientException) as e:
return self.callback.error(e.message, node)
host_flag = False
for key, value in firm_obj_dict.items():
key_id = key.split('-')[-1]
if key_id != delete_id:
continue
if value.functional or (value.priority == 0 and not has_functional):
if value.purpose == 'BMC':
return self.callback.error('Deleting currently active BMC firmware' \
' is not supported', node)
elif value.purpose == 'Host':
host_flag = True
break
else:
self.callback.error('Unable to determine the purpose of the ' \
'firmware to delete', node)
if host_flag:
try:
states = obmc.list_power_states()
state = obmc.get_host_state(states)
if openbmc.RPOWER_STATES.get(state) == 'on':
return self.callback.error('Deleting currently active firmware on' \
' powered on host is not supported', node)
except (SelfServerException, SelfClientException) as e:
return self.callback.error(e.message, node)
try:
obmc.delete_firmware(delete_id)
except SelfServerException as e:
error = e.message
except SelfClientException as e:
if e.code == 404:
error = 'Invalid ID provided to delete. ' \
'Use the -l option to view valid firmware IDs.'
else:
error = e.message
if error:
self.callback.error(error, node)
else:
self.callback.info('%s: [%s] Firmware removed' % (node, delete_id))
def flash_process(self, directory, no_host_reboot, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
try:
obmc.login()
except (SelfServerException, SelfClientException) as e:
return self._msg_process(node, e.message, msg_type='E', update_rc=True)
try:
for key, value in self.firmware.items():
obmc.upload_firmware(value['file'])
except (SelfServerException, SelfClientException) as e:
return self._msg_process(node, e.message, msg_type='E', update_rc=True)
activate_ids = self._get_firm_id(obmc, node)
if not activate_ids:
return
for i in activate_ids:
error = ''
try:
obmc.activate_firmware(i)
except SelfServerException as e:
error = e.message
except SelfClientException as e:
if e.code == 403:
error = 'Invalid ID %s provided to activate. Use the -l option ' \
'to view valid firmware IDs.' % i
else:
error = e.message
if error:
return self._msg_process(node, error, msg_type='E', update_rc=True)
for key in self.firmware:
msg = 'rflash %s started, please wait...' % key
self._msg_process(node, msg, checkv=True)
self._check_id_status(obmc, activate_ids, node, only_act=False)
self._reboot_to_effect(obmc, no_host_reboot, node)
def list_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()
has_functional, firm_obj_dict = obmc.list_firmware()
except (SelfServerException, SelfClientException) as e:
return self.callback.error(e.message, node)
firm_info.append('%-8s %-7s %-10s %-s' % ('ID', 'Purpose', 'State', 'Version'))
firm_info.append('-' * 55)
for key, value in firm_obj_dict.items():
status = value.active
if value.functional:
status += '(*)'
elif value.priority == 0:
if not has_functional:
status += '(*)'
else:
status += '(+)'
firm_info.append('%-8s %-7s %-10s %-s' % (key.split('-')[-1],
value.purpose, status, value.version))
for info in firm_info:
self.callback.info('%s: %s' % (node, info))
return firm_info
def upload_firm(self, upload_file, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
try:
obmc.login()
except (SelfServerException, SelfClientException) as e:
return self._msg_process(node, e.message, msg_type='E')
try:
obmc.upload_firmware(self.firmware_file)
self._msg_process(node, 'Firmware upload successful. Use -l option to list.')
except (SelfServerException, SelfClientException) as e:
return self._msg_process(node, e.message, msg_type='E')
def _flash_summary(self):
if not self.activate_result:
return self.callback.error('No summary infomation')
success_num = failed_num = 0
failed_list = []
for key, value in self.activate_result.items():
if value == 'SUCCESS':
success_num += 1
else:
failed_num += 1
failed_list.append('%s: %s' % (key, value))
self.callback.info('-' * 55)
self.callback.info('%s complete: Total=%d Success=%d Failed=%d' % \
('Firmware update', self.nodes_num, success_num, failed_num))
for i in failed_list:
self.callback.info(i)
self.callback.info('-' * 55)
def post_activate_firm(self, task, activate_arg, **kw):
self._flash_summary()
def post_flash_process(self, task, directory, no_host_reboot, **kw):
self._flash_summary()
@@ -8,6 +8,7 @@
from __future__ import print_function
import gevent
import time
import os
from common.task import ParallelNodesCommand
from common.exceptions import SelfClientException, SelfServerException
@@ -20,6 +21,26 @@ logger = logging.getLogger('xcatagent')
class OpenBMCInventoryTask(ParallelNodesCommand):
"""Executor for inventory-related actions."""
def pre_get_firm_info(self, task, target_file=None, **kw):
if not target_file:
return
target_file = utils.get_full_path(self.cwd, target_file)
version = purpose = None
with open(target_file, 'r') as fh:
for line in fh:
if 'version=' in line:
version = line.split('=')[-1].strip()
if 'purpose=' in line:
purpose = line.split('=')[-1].strip()
if version and purpose:
break
self.callback.info('TAR %s Firmware Product Version: %s' \
% (purpose, version))
def _get_firm_info(self, firm_info_list):
(has_functional, firm_obj_dict) = firm_info_list
firm_info = []
@@ -97,7 +118,7 @@ class OpenBMCInventoryTask(ParallelNodesCommand):
return inventory_info
def get_firm_info(self, **kw):
def get_firm_info(self, target_file=None, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
@@ -26,25 +26,6 @@ POWER_STATE_DB = {
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']
@@ -54,7 +35,7 @@ class OpenBMCPowerTask(ParallelNodesCommand):
try:
obmc.login()
states = obmc.list_power_states()
state = self._determine_state(states)
state = obmc.get_host_state(states)
self.callback.info('%s: %s' % (node, openbmc.RPOWER_STATES.get(state, state)))
except (SelfServerException, SelfClientException) as e:
@@ -70,10 +51,8 @@ class OpenBMCPowerTask(ParallelNodesCommand):
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)
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
return bmc_state
try:
@@ -85,9 +64,10 @@ class OpenBMCPowerTask(ParallelNodesCommand):
self.callback.info('%s: %s' % (node, openbmc.RPOWER_STATES.get(bmc_state, bmc_state)))
except SelfServerException, SelfClientException:
# There is no response when BMC is not ready
except SelfServerException as e:
self.callback.error(openbmc.RPOWER_STATES[bmc_not_ready], node)
except SelfClientException as e:
self.callback.error("%s (%s)" % (openbmc.RPOWER_STATES[bmc_not_ready], e.message), node)
return bmc_state
@@ -115,7 +95,7 @@ class OpenBMCPowerTask(ParallelNodesCommand):
try:
obmc.login()
states = obmc.list_power_states()
status = self._determine_state(states)
status = obmc.get_host_state(states)
new_status =''
if optype == 'reset' and status in ['Off', 'chassison']:
@@ -130,7 +110,7 @@ class OpenBMCPowerTask(ParallelNodesCommand):
start_timeStamp = int(time.time())
for i in range (0, 30):
states = obmc.list_power_states()
status = self._determine_state(states)
status = obmc.get_host_state(states)
if openbmc.RPOWER_STATES.get(status) == 'off':
off_flag = True
break
@@ -159,13 +139,32 @@ class OpenBMCPowerTask(ParallelNodesCommand):
new_status = ''
try:
obmc.login()
except (SelfServerException, SelfClientException) as e:
return self.callback.error(e.message, node)
firm_obj_dict = {}
try:
has_functional, firm_obj_dict = obmc.list_firmware()
except (SelfServerException, SelfClientException) as e:
self.callback.syslog('%s: %s' % (node, e.message))
clear_flag = False
for key, value in firm_obj_dict.items():
if not value.functional and value.priority == 0:
clear_flag = True
break
if clear_flag:
self.callback.info('%s: Firmware will be flashed on reboot, deleting all BMC diagnostics...' % node)
try:
obmc.clear_dump('all')
except (SelfServerException, SelfClientException) as e:
self.callback.warn('%s: Could not clear BMC diagnostics successfully %s' % (node, e.message))
try:
obmc.reboot_bmc(optype)
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
else:
try:
obmc.reboot_bmc(optype)
except (SelfServerException, SelfClientException) as e:
self.callback.error(e.message, node)
else:
self.callback.info('%s: %s' % (node, openbmc.RPOWER_STATES['bmcreboot']))
self.callback.info('%s: %s' % (node, openbmc.RPOWER_STATES['bmcreboot']))
@@ -32,24 +32,28 @@ SENSOR_POWER_UNITS = ("Amperes", "Joules", "Watts")
class OpenBMCSensorTask(ParallelNodesCommand):
"""Executor for sensor-related actions."""
def _get_beacon_info(self, beacon_dict):
def _get_beacon_info(self, beacon_dict, display_type='full'):
led_label = 'LEDs'
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')))
# display_type == 'full' for detailed output for 'rvitals leds' command
# display_type == 'compact' for compact output for 'rbeacon stat' command
if display_type == 'compact':
info_list.append('Front:%s Rear:%s' % (beacon_dict.get('front_id'), beacon_dict.get('rear_id', 'N/A')))
return info_list
for i in range(4):
info_list.append('%s Fan%s: %s' % (led_label, i, beacon_dict.get('fan' + str(i), 'N/A')))
led_types = ('Fault', 'Identify', 'Power')
for i in ('Front', 'Rear'):
for led_type in led_types:
tmp_type = led_type.lower()
if led_type == 'Identify':
tmp_type = 'id'
key_type = i.lower() + '_' + tmp_type
info_list.append('%s %s %s: %s' % (led_label, i, led_type, beacon_dict.get(key_type, 'N/A')))
return info_list
@@ -92,7 +96,7 @@ class OpenBMCSensorTask(ParallelNodesCommand):
return sensor_info
def get_beacon_info(self, **kw):
def get_beacon_info(self, display_type, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
@@ -102,7 +106,7 @@ class OpenBMCSensorTask(ParallelNodesCommand):
try:
obmc.login()
beacon_dict = obmc.get_beacon_info()
beacon_info = self._get_beacon_info(beacon_dict)
beacon_info = self._get_beacon_info(beacon_dict, display_type)
if not beacon_info:
beacon_info = ['No attributes returned from the BMC.']
@@ -0,0 +1,54 @@
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
class FlashInterface(object):
"""Interface for flash-related actions."""
interface_type = 'flash'
version = '1.0'
def activate_firm(self, task, activate_arg):
"""Activate firmware.
:param task: a Task instance containing the nodes to act on.
:activate_arg: arg for activate
"""
return task.run('activate_firm', activate_arg)
def delete_firm(self, task, delete_id):
"""Delete firmware.
:param task: a Task instance containing the nodes to act on.
:param delete_id: firmware id want to delete
"""
return task.run('delete_firm', delete_id)
def flash_process(self, task, directory, no_host_reboot):
"""Upload and activate firmware
:param task: a Task instance containing the nodes to act on.
:directory: firmware directory
"""
return task.run('flash_process', directory, no_host_reboot)
def list_firm_info(self, task):
"""List firmware
:param task: a Task instance containing the nodes to act on.
"""
return task.run('list_firm_info')
def upload_firm(self, task, upload_file):
"""Upload firmware file.
:param task: a Task instance containing the nodes to act on.
:param upload_file: the file want to upload
"""
return task.run('upload_firm', upload_file)
class DefaultFlashManager(FlashInterface):
"""Interface for flash-related actions."""
pass
@@ -19,13 +19,14 @@ class InventoryInterface(object):
"""
return task.run('get_info', inventory_type)
def get_firm_info(self, task):
def get_firm_info(self, task, target_arg=None):
"""Return the firm info of the task's nodes.
:param task: a Task instance containing the nodes to act on.
:param check_arg: firmware file to check, for rflash check
:return firm info list
"""
return task.run('get_firm_info')
return task.run('get_firm_info', target_arg)
class DefaultInventoryManager(InventoryInterface):
"""Interface for inventory-related actions."""
@@ -145,15 +145,15 @@ BOOTSOURCE_SET_STATE = {
FIRM_URLS = {
"activate" : {
"path" : "/software/%(id)s/attr/RequestedActivation",
"field" : "Software.Activation.RequestedActivations.Active",
"path" : "/software/%s/attr/RequestedActivation",
"field" : "xyz.openbmc_project.Software.Activation.RequestedActivations.Active",
},
"delete" : {
"path" : "/software/%(id)s/action/Delete",
"path" : "/software/%s/action/Delete",
"field" : [],
},
"priority" : {
"path" : "/software/%(id)s/attr/Priority",
"path" : "/software/%s/attr/Priority",
"field" : False,
},
"list" : {
@@ -162,11 +162,14 @@ FIRM_URLS = {
}
RSPCONFIG_NETINFO_URL = {
'delete_ip_object': "/network/#NIC#/ipv4/#OBJ#",
'disable_dhcp': "/network/#NIC#/attr/DHCPEnabled",
'get_netinfo': "/network/enumerate",
'nic_ip': "/network/#NIC#/action/IP",
'vlan': "/network/action/VLAN",
'get_nic_netinfo': "/network/#NIC#/ipv4/enumerate",
'ipdhcp': "/network/action/Reset",
'nic_ip': "/network/#NIC#/action/IP",
'ntpservers': "/network/#NIC#/attr/NTPServers",
'vlan': "/network/action/VLAN",
}
PASSWD_URL = '/user/root/action/SetPassword'
@@ -178,27 +181,31 @@ RSPCONFIG_APIS = {
'display_name': "BMC Hostname",
},
'autoreboot' : {
'baseurl': "/control/host0/auto_reboot/",
'set_url': "attr/AutoReboot",
'get_url': "attr/AutoReboot",
'baseurl': "/control/host0/auto_reboot",
'set_url': "/attr/AutoReboot",
'get_url': "",
'display_name': "BMC AutoReboot",
'attr_values': {
'0': False,
'1': True,
},
},
'powersupplyredundancy':{
'baseurl': "/sensors/chassis/PowerSupplyRedundancy/",
'set_url': "/action/setValue",
'get_url': "/action/getValue",
'set_url': "action/setValue",
'get_url': "action/getValue",
'get_method': 'POST',
'get_data': '[]',
'get_data': [],
'display_name': "BMC PowerSupplyRedundancy",
'attr_values': {
'disabled': "Disables",
'enabled': "Enabled",
'disabled': ["Disabled"],
'enabled': ["Enabled"],
},
},
'powerrestorepolicy': {
'baseurl': "/control/host0/power_restore_policy/",
'set_url': "attr/PowerRestorePolicy",
'get_url': "attr/PowerRestorePolicy",
'baseurl': "/control/host0/power_restore_policy",
'set_url': "/attr/PowerRestorePolicy",
'get_url': "",
'display_name': "BMC PowerRestorePolicy",
'attr_values': {
'restore': "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore",
@@ -207,9 +214,9 @@ RSPCONFIG_APIS = {
},
},
'bootmode': {
'baseurl': "/control/host0/boot/",
'set_url': "attr/BootMode",
'get_url': "attr/BootMode",
'baseurl': "/control/host0/boot",
'set_url': "/attr/BootMode",
'get_url': "",
'display_name':"BMC BootMode",
'attr_values': {
'regular': "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular",
@@ -217,9 +224,24 @@ RSPCONFIG_APIS = {
'setup': "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup",
},
},
'timesyncmethod': {
'baseurl': '/time/sync_method',
'get_url': '',
'set_url': '/attr/TimeSyncMethod',
'display_name': 'BMC TimeSyncMethod',
'attr_values': {
'ntp': 'xyz.openbmc_project.Time.Synchronization.Method.NTP',
'manual': 'xyz.openbmc_project.Time.Synchronization.Method.Manual',
},
},
}
EVENTLOG_URLS = {
"list": "/logging/enumerate",
"clear_all": "/logging/action/deleteAll",
"resolve": "/logging/entry/{}/attr/Resolved",
}
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: "
@@ -251,14 +273,19 @@ class OpenBMCRest(object):
self.root_url = HTTP_PROTOCOL + self.bmcip + PROJECT_URL
self.download_root_url = HTTP_PROTOCOL + self.bmcip + '/'
def _print_record_log (self, msg, cmd):
def _print_record_log (self, msg, cmd, error_flag=False):
if self.verbose :
if self.verbose or error_flag:
localtime = time.asctime( time.localtime(time.time()) )
log = self.name + ': [openbmc_debug] ' + cmd + ' ' + msg
self.messager.info(localtime + ' ' + log)
if self.verbose:
self.messager.info(localtime + ' ' + log)
logger.debug(log)
def _print_error_log (self, msg, cmd):
self._print_record_log(msg, cmd, True)
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() ])
@@ -285,8 +312,8 @@ class OpenBMCRest(object):
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)
error = '[%d] %s' % (code, description)
self._print_error_log(error, cmd)
raise SelfClientException(error, code)
self._print_record_log(data['message'], cmd)
@@ -308,13 +335,16 @@ class OpenBMCRest(object):
response = self.session.request(method, url, httpheaders, data=data, timeout=timeout)
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)
if cmd == 'login':
e.message = "Login to BMC failed: Can't connect to {0} {1}.".format(e.host_and_port, e.detail_msg)
else:
e.message = 'BMC did not respond. ' \
'Validate BMC configuration and retry the command.'
self._print_error_log(e.message, cmd)
raise
except ValueError:
error = 'Error: Received wrong format response: %s' % response
self._print_record_log(error, cmd)
error = 'Received wrong format response: %s' % response
self._print_error_log(error, cmd)
raise SelfServerException(error)
def download(self, method, resource, file_path, headers=None, cmd=''):
@@ -329,15 +359,15 @@ class OpenBMCRest(object):
try:
response = self.session.request_download(method, url, httpheaders, file_path)
except SelfServerException as e:
self._print_record_log(e.message, cmd=cmd)
self._print_error_log(e.message, cmd=cmd)
raise
except SelfClientException as e:
error = e.message
self._print_record_log(error, cmd=cmd)
self._print_error_log(error, cmd=cmd)
raise
if not response:
self._print_record_log('No response received for command %s' % request_cmd, cmd=cmd)
self._print_error_log('No response received for command %s' % request_cmd, cmd)
return True
self._print_record_log(str(response.status_code), cmd=cmd)
@@ -354,22 +384,22 @@ class OpenBMCRest(object):
try:
response = self.session.request_upload(method, url, httpheaders, files)
except SelfServerException:
self._print_record_log(error, cmd=cmd)
except SelfServerException as e:
self._print_error_log(e.message, cmd=cmd)
raise
try:
data = json.loads(response)
except ValueError:
error = 'Error: Received wrong format response when running command \'%s\': %s' % \
error = 'Received wrong format response when running command \'%s\': %s' % \
(request_cmd, response)
self._print_record_log(error, cmd=cmd)
self._print_error_log(error, cmd=cmd)
raise SelfServerException(error)
if data['message'] != '200 OK':
error = 'Error: Failed to upload update file %s : %s-%s' % \
error = 'Failed to upload update file %s : %s-%s' % \
(files, data['message'], \
''.join(data['data']['description']))
self._print_record_log(error, cmd=cmd)
self._print_error_log(error, cmd=cmd)
raise SelfClientException(error, code)
self._print_record_log(data['message'], cmd=cmd)
@@ -392,7 +422,7 @@ class OpenBMCRest(object):
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
error = 'Received wrong format response: %s' % states
raise SelfServerException(error)
def set_power_state(self, state):
@@ -402,11 +432,11 @@ class OpenBMCRest(object):
def get_bmc_state(self):
state = self.request('GET', BMC_URLS['state']['path'], cmd='get_bmc_state')
try:
state = self.request('GET', BMC_URLS['state']['path'], cmd='get_bmc_state')
return {'bmc': state.split('.')[-1]}
except KeyError:
error = 'Error: Received wrong format response: %s' % state
error = 'Received wrong format response: %s' % state
raise SelfServerException(error)
def reboot_bmc(self, optype='warm'):
@@ -418,6 +448,25 @@ class OpenBMCRest(object):
# TODO: Need special handling for bmc reset, as it is normal bmc may return error
pass
def get_host_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 set_one_time_boot_enable(self, enabled):
payload = { "data": enabled }
@@ -448,7 +497,7 @@ class OpenBMCRest(object):
boot_state = BOOTSOURCE_GET_STATE.get(boot_source.split('.')[-1], error)
return boot_state
except KeyError:
error = 'Error: Received wrong format response: %s' % states
error = 'Received wrong format response: %s' % states
raise SelfServerException(error)
def get_beacon_info(self):
@@ -462,7 +511,7 @@ class OpenBMCRest(object):
beacon_dict[key_id] = value['State'].split('.')[-1]
return beacon_dict
except KeyError:
error = 'Error: Received wrong format response: %s' % beacon_data
error = 'Received wrong format response: %s' % beacon_data
raise SelfServerException(error)
def set_beacon_state(self, state):
@@ -494,7 +543,7 @@ class OpenBMCRest(object):
return sensor_dict
except KeyError:
error = 'Error: Received wrong format response: %s' % sensor_data
error = 'Received wrong format response: %s' % sensor_data
raise SelfServerException(error)
def get_inventory_info(self):
@@ -531,9 +580,21 @@ class OpenBMCRest(object):
return inverntory_dict
except KeyError:
error = 'Error: Received wrong format response: %s' % inventory_data
error = 'Received wrong format response: %s' % inventory_data
raise SelfServerException(error)
def activate_firmware(self, activate_id):
payload = { "data": FIRM_URLS['activate']['field'] }
url = FIRM_URLS['activate']['path'] % activate_id
return self.request('PUT', url, payload=payload, cmd='activate_firmware')
def delete_firmware(self, delete_id):
payload = { "data": FIRM_URLS['delete']['field'] }
url = FIRM_URLS['delete']['path'] % delete_id
return self.request('POST', url, payload=payload, cmd='delete_firmware')
def list_firmware(self):
data = self.request('GET', FIRM_URLS['list']['path'], cmd='list_firmware')
@@ -556,10 +617,22 @@ class OpenBMCRest(object):
return bool(func_list), fw_dict
def upload_firmware(self, upload_file):
headers = {'Content-Type': 'application/octet-stream'}
path = HTTP_PROTOCOL + self.bmcip + '/upload/image/'
self.upload('PUT', path, upload_file, headers=headers, cmd='upload_firmware')
def set_priority(self, firm_id):
payload = { "data": FIRM_URLS['priority']['field'] }
url = FIRM_URLS['priority']['path'] % firm_id
return self.request('PUT', url, payload=payload, cmd='set_priority')
# Extract all eventlog info and parse it
def get_eventlog_info(self):
eventlog_data = self.request('GET', EVENTLOG_URL, cmd='get_eventlog_info')
eventlog_data = self.request('GET', EVENTLOG_URLS['list'], cmd='get_eventlog_info')
return self.parse_eventlog_data(eventlog_data)
@@ -584,9 +657,14 @@ class OpenBMCRest(object):
id, event_log_line = self.parse_eventlog_data_record(value, ras_event_mapping)
if int(id) != 0:
eventlog_dict[str(id)] = event_log_line
if not eventlog_dict:
# Nothing was returned from BMC
eventlog_dict['0'] ='No attributes returned from the BMC.'
return eventlog_dict
except KeyError:
error = 'Error: Received wrong format response: %s' % eventlog_data
error = 'Received wrong format response: %s' % eventlog_data
raise SelfServerException(error)
# Parse a single eventlog entry and return data in formatted string
@@ -649,6 +727,21 @@ class OpenBMCRest(object):
formatted_line += LED_tag
return id_str, formatted_line
# Clear all eventlog records
def clear_all_eventlog_records(self):
payload = { "data": [] }
return self.request('POST', EVENTLOG_URLS['clear_all'], payload=payload, cmd='clear_all_eventlog_records')
# Resolve eventlog records
def resolve_event_log_entries(self, eventlog_ids_to_resolve):
payload = { "data": "1" }
for event_id in eventlog_ids_to_resolve:
self.request('PUT', EVENTLOG_URLS['resolve'].format(event_id), payload=payload, cmd='resolve_event_log_entries')
return
def set_apis_values(self, key, value):
attr_info = RSPCONFIG_APIS[key]
if 'set_url' not in attr_info:
@@ -658,7 +751,11 @@ class OpenBMCRest(object):
data = attr_info['attr_values'][value]
else:
data = value
self.request('PUT', set_url, payload={"data": data}, cmd="set_%s" % key)
method = 'PUT'
if key == 'powersupplyredundancy':
method = 'POST'
self.request(method, set_url, payload={"data": data}, cmd="set_%s" % key)
def get_apis_values(self, key):
attr_info = RSPCONFIG_APIS[key]
@@ -717,7 +814,7 @@ class OpenBMCRest(object):
return dump_dict
except KeyError:
error = 'Error: Received wrong format response: %s' % dump_data
error = 'Received wrong format response: %s' % dump_data
raise SelfServerException(error)
def download_dump(self, download_id, file_path):
@@ -732,6 +829,50 @@ class OpenBMCRest(object):
url = HTTP_PROTOCOL + self.bmcip + GARD_CLEAR_URL
return self.request('POST', url, payload=payload, cmd='clear_gard')
def set_vlan(self, nic, vlan_id):
payload = { "data": [nic, vlan_id] }
return self.request('POST', RSPCONFIG_NETINFO_URL['vlan'], payload=payload, cmd='set_vlan')
def set_netinfo(self, nic, ip, netmask, gateway):
payload = { "data": ["xyz.openbmc_project.Network.IP.Protocol.IPv4", ip, netmask, gateway] }
path = RSPCONFIG_NETINFO_URL['nic_ip'].replace('#NIC#', nic)
return self.request('POST', path, payload=payload, cmd='set_netinfo')
def disable_dhcp(self, nic):
payload = { "data": 0 }
path = RSPCONFIG_NETINFO_URL['disable_dhcp'].replace('#NIC#', nic)
return self.request('PUT', path, payload=payload, cmd='disable_dhcp')
def delete_ip_object(self, nic, ip_object):
path = RSPCONFIG_NETINFO_URL['delete_ip_object'].replace('#OBJ#', ip_object).replace('#NIC#', nic)
return self.request('DELETE', path, cmd='delete_ip_object')
def get_nic_netinfo(self, nic):
path = RSPCONFIG_NETINFO_URL['get_nic_netinfo'].replace('#NIC#', nic)
data = self.request('GET', path, cmd='get_nic_netinfo')
try:
netinfo = {}
for k, v in data.items():
dev,match,netid = k.partition("/ipv4/")
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
utils.update2Ddict(netinfo, netid, 'ip', v['Address'])
utils.update2Ddict(netinfo, netid, 'ipsrc', v['Origin'].split('.')[-1])
utils.update2Ddict(netinfo, netid, 'netmask', v['PrefixLength'])
utils.update2Ddict(netinfo, netid, 'gateway', v['Gateway'])
return netinfo
except KeyError:
error = 'Received wrong format response: %s' % data
raise SelfServerException(error)
def get_netinfo(self):
data = self.request('GET', RSPCONFIG_NETINFO_URL['get_netinfo'], cmd="get_netinfo")
try:
@@ -755,11 +896,14 @@ class OpenBMCRest(object):
if 'ip' in netinfo[nicid]:
msg = "%s: Another valid ip %s found." % (node, v["Address"])
self._print_record_log(msg, 'get_netinfo')
continue
del netinfo[nicid]
netinfo['error'] = 'Interfaces with multiple IP addresses are not supported'
break
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"])
utils.update2Ddict(netinfo, nicid, "ipobj", netid)
if dev in data:
info = data[dev]
utils.update2Ddict(netinfo, nicid, "vlanid", info.get("Id", "Disable"))
@@ -771,13 +915,13 @@ class OpenBMCRest(object):
utils.update2Ddict(netinfo, nicid, "ntpservers", ntpservers)
return netinfo
except KeyError:
error = 'Error: Received wrong format response: %s' % data
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")
return self.request('POST', RSPCONFIG_NETINFO_URL['ipdhcp'], payload=payload, cmd="set_bmcip_dhcp")
class OpenBMCImage(object):
@@ -19,13 +19,14 @@ class SensorInterface(object):
"""
return task.run('get_sensor_info', sensor_type)
def get_beacon_info(self, task):
def get_beacon_info(self, task, display_type='full'):
"""Return the beacon info of the task's nodes.
:param task: type of display to produce - full (rvitals leds) or compact (rbeacon stat)
:param task: a Task instance containing the nodes to act on.
:return: beacon info list
"""
return task.run('get_beacon_info')
return task.run('get_beacon_info', display_type)
class DefaultSensorManager(SensorInterface):
"""Interface for sensor-related actions."""
@@ -16,13 +16,14 @@ 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_flash import OpenBMCFlashTask
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.flash import DefaultFlashManager
from hwctl.inventory import DefaultInventoryManager
from hwctl.power import DefaultPowerManager
from hwctl.sensor import DefaultSensorManager
@@ -30,11 +31,13 @@ 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')
try:
if not logger.handlers:
utils.enableSyslog('xcat.agent')
except:
pass
HTTP_PROTOCOL = "https://"
PROJECT_URL = "/xyz/openbmc_project"
@@ -48,41 +51,10 @@ VERBOSE = False
all_nodes_result = {}
# global variables of rbeacon
BEACON_SET_OPTIONS = ('on', 'off')
BEACON_OPTIONS = ('on', 'off', 'stat')
# global variables of rflash
RFLASH_OPTIONS = {
"-a" : "activate",
"--activate" : "activate",
"-c" : "check",
"--check" : "check",
"-d" : "direcory",
"--delete" : "delete",
"-l" : "list",
"--list" : "list",
"-u" : "upload",
"--upload" : "upload",
}
RSPCONFIG_GET_OPTIONS = ['ip','ipsrc','netmask','gateway','vlan','ntpservers','hostname','bootmode','autoreboot','powersupplyredundancy','powerrestorepolicy', 'timesyncmethod']
RFLASH_URLS = {
"activate" : {
"url" : PROJECT_URL + "/software/#ACTIVATE_ID#/attr/RequestedActivation",
"field" : "xyz.openbmc_project.Software.Activation.RequestedActivations.Active",
},
"delete" : {
"url" : PROJECT_URL + "/software/#DELETE_ID#/action/Delete",
"field" : [],
},
"upload" : {
"url" : "/upload/image/",
},
"priority" : {
"url" : PROJECT_URL + "/software/#PRIORITY_ID#/attr/Priority",
"field" : False,
}
}
RSPCONFIG_GET_OPTIONS = ['ip','ipsrc','netmask','gateway','vlan','ntpservers','hostname','bootmode','autoreboot','powersupplyredundancy','powerrestorepolicy']
RSPCONFIG_SET_OPTIONS = {
'ip':'.*',
'netmask':'.*',
@@ -95,6 +67,7 @@ RSPCONFIG_SET_OPTIONS = {
'powerrestorepolicy':"^always_on$|^always_off$|^restore$",
'bootmode':"^regular$|^safe$|^setup$",
'admin_passwd':'.*,.*',
'timesyncmethod':'^ntp$|^manual$',
}
RSPCONFIG_USAGE = """
Handle rspconfig operations.
@@ -124,14 +97,9 @@ The supported attributes and its values to set are:
autoreboot={0|1}
powersupplyredundancy={enabled|disabled}
powerrestorepolicy={always_on|always_off|restore}
timesyncmethod={ntp|manual}
""" % 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')
@@ -151,452 +119,6 @@ VITALS_OPTIONS = ('all', 'altitude', 'fanspeed', 'leds', 'power',
# global variables of reventlog
EVENTLOG_OPTIONS = ('list', 'clear', 'resolved')
class OpenBMC(base.BaseDriver):
headers = {'Content-Type': 'application/json'}
def __init__(self, messager, name, node_info):
super(OpenBMC, self).__init__(messager)
self.node = name
for key, value in node_info.items():
setattr(self, key, value)
global DEBUGMODE
self.client = openbmc_rest.OpenBMCRest(name, messager, DEBUGMODE)
def _login(self):
""" Login
:raise: error message if failed
"""
url = HTTP_PROTOCOL + self.bmcip + '/login'
data = { "data": [ self.username, self.password ] }
self.client.request('POST', url, OpenBMC.headers, data, 'login')
return RESULT_OK
def _msg_process_rflash (self, msg, update_dict, checkv):
"""deal with msg during rflash
:param msg: the msg want to process
"""
if not checkv:
self.messager.info('%s: %s' % (self.node, msg))
elif VERBOSE:
self.messager.info('%s: %s' % (self.node, msg))
self.rflash_log_handle.writelines(msg + '\n')
self.rflash_log_handle.flush()
if update_dict:
utils.update2Ddict(update_dict, self.node, 'result', [msg])
def _firm_info(self, status):
"""List firmware information including additional
called by rflash check and rinv firm
:returns: firmware information
"""
firm_output = []
try:
(has_functional, firm_info) = self._get_firm_info(status)
except (xcat_exception.SelfServerException,
xcat_exception.SelfClientException) as e:
firm_output.append(e.message)
return firm_output
keys = firm_info.keys()
keys.sort()
for key in keys:
flag = ''
if 'is_functional' in firm_info[key]:
flag = '*'
elif ('Priority' in firm_info[key] and
firm_info[key]['Priority'] == '0'):
if not has_functional:
flag = '*'
else:
flag = '+'
if not flag and not VERBOSE:
continue
firm_output.append('%s Firmware Product: %s (%s)%s' %
(firm_info[key]['Purpose'],
firm_info[key]['Version'],
firm_info[key]['Activation'], flag))
if 'ExtendedVersion' in firm_info[key]:
extendeds = firm_info[key]['ExtendedVersion'].split(',')
extendeds.sort()
for extended in extendeds:
firm_output.append('%s Firmware Product: ' \
'-- additional info: %s' % \
(firm_info[key]['Purpose'], extended))
return firm_output
def _get_firm_info(self, status):
"""get firmware information
:param status: current status
:returns: firmware version information
"""
firm_info = {}
has_functional = False
url = HTTP_PROTOCOL + self.bmcip + FIRM_URL
response = self.client.request('GET', url, OpenBMC.headers, '', status)
functional_url = PROJECT_URL + '/software/functional'
for key in response['data']:
key_id = key.split('/')[-1]
if key_id == 'functional':
for endpoint in response['data'][key]['endpoints']:
purpose = response['data'][endpoint]['Purpose'].split('.')[-1]
key_sort = purpose + '-' + endpoint.split('/')[-1]
utils.update2Ddict(firm_info, key_sort, 'is_functional', True)
has_functional = True
if 'Version' in response['data'][key]:
purpose = response['data'][key]['Purpose'].split('.')[-1]
key_sort = purpose + '-' + key_id
if (functional_url in response['data'] and
key in response['data'][functional_url]['endpoints']):
utils.update2Ddict(firm_info, key_sort, 'is_functional', True)
utils.update2Ddict(firm_info, key_sort, 'Version',
response['data'][key]['Version'])
utils.update2Ddict(firm_info, key_sort, 'Purpose', purpose)
utils.update2Ddict(firm_info, key_sort, 'Activation',
response['data'][key]['Activation'].split('.')[-1])
if 'Priority' in response['data'][key]:
utils.update2Ddict(firm_info, key_sort, 'Priority',
str(response['data'][key]['Priority']))
if 'ExtendedVersion' in response['data'][key]:
utils.update2Ddict(firm_info, key_sort, 'ExtendedVersion',
response['data'][key]['ExtendedVersion'])
if 'Progress' in response['data'][key]:
utils.update2Ddict(firm_info, key_sort, 'Progress',
response['data'][key]['Progress'])
return (has_functional, firm_info)
def _get_firm_id(self, firm_list):
"""get firmware id
:param firm_list: the list of firmware versions
:return: result and info list
"""
firm_ids = []
url = HTTP_PROTOCOL + self.bmcip + FIRM_URL
for i in range(6):
try:
response = self.client.request('GET', url, OpenBMC.headers,
'', 'rflash_check_id')
except (xcat_exception.SelfServerException,
xcat_exception.SelfClientException) as e:
self._msg_process_rflash(e.message, all_nodes_result, False)
return (RESULT_FAIL, [])
for key in response['data']:
if 'Version' in response['data'][key]:
if response['data'][key]['Version'] in firm_list:
firm_id = key.split('/')[-1]
upload_msg = 'Firmware upload successful. ' \
'Attempting to activate firmware: ' \
'%s (ID: %s)' % \
(response['data'][key]['Version'], firm_id)
self._msg_process_rflash(upload_msg, {}, False)
firm_ids.append(firm_id)
firm_list.remove(response['data'][key]['Version'])
if firm_list:
for firm_ver in firm_list:
retry_msg = 'Could not find ID for firmware %s to '\
'activate, waiting %d seconds and retry...' \
% (firm_ver, 10)
self._msg_process_rflash(upload_msg, {}, True)
gevent.sleep( 10 )
else:
break
if firm_list:
for firm_ver in firm_list:
error = 'Could not find firmware %s after waiting %d seconds.' \
% (firm_ver, 10*6)
self._msg_process_rflash(upload_msg, {}, False)
error_list.append(error)
utils.update2Ddict(all_nodes_result, self.node, 'result', error_list)
return (RESULT_FAIL, [])
return (RESULT_OK, firm_ids)
def _check_id_status(self, firm_id_list):
"""check firm id status
:param firm_id_list: list of firm ids want to check
:return: result
"""
result = RESULT_OK
set_priority_ids = []
process_status = {}
failed_msg = []
for i in range(80):
try:
(has_functional, firm_info) = self._get_firm_info('rflash_check_status')
except (xcat_exception.SelfServerException,
xcat_exception.SelfClientException) as e:
self._msg_process_rflash(e.message, all_nodes_result, False)
return (RESULT_FAIL, set_priority_ids)
activation_num = 0
for key in firm_info:
firm_id = key.split('-')[-1]
if firm_id in firm_id_list:
activation_state = firm_info[key]['Activation']
firm_version = firm_info[key]['Version']
if activation_state == 'Failed':
activation_msg = 'Firmware %s activation failed.' % (firm_version)
self._msg_process_rflash(activation_msg, {}, False)
failed_msg.append(activation_msg)
result = RESULT_FAIL
firm_id_list.rempove(firm_id)
if activation_state == 'Active':
activation_msg = 'Firmware %s activation successful.' % (firm_version)
self._msg_process_rflash(activation_msg, {}, False)
firm_id_list.remove(firm_id)
priority = firm_info[key]['Priority']
if priority != '0':
set_priority_ids.append(firm_id)
if activation_state == 'Activating':
activating_progress_msg = 'Activating %s ... %s%%' \
% (firm_version, firm_info[key]['Progress'])
self._msg_process_rflash(activating_progress_msg, {}, True)
process_status[firm_id] = activating_progress_msg
if not firm_id_list:
break
gevent.sleep( 15 )
if firm_id_list:
result = RESULT_FAIL
for firm_id in firm_id_list:
if firm_id in process_status:
failed_msg.append('After %d seconds check the current status is %s' \
% (80*15, process_status[firm_id]))
if failed_msg:
utils.update2Ddict(all_nodes_result, self.node, 'result', [failed_msg])
return (result, set_priority_ids)
def _set_priority(self, priority_ids):
"""set firmware priority to 0
:param priority_ids: list of firmware ids
:return ok if success
:return error msg if failed
"""
for priority_id in priority_ids:
url = (HTTP_PROTOCOL + self.bmcip +
RFLASH_URLS['priority']['url'].replace('#PRIORITY_ID#', priority_id))
data = { "data": RFLASH_URLS['priority']['field'] }
try:
response = self.client.request('PUT', url, OpenBMC.headers,
data, 'rflash_set_priority')
except (xcat_exception.SelfServerException,
xcat_exception.SelfClientException) as e:
return e.message
return RESULT_OK
def _rflash_activate_id(self, activate_id):
"""rflash activate id
:param activate_id: the id want to activate
:raise: error message if failed
"""
url = (HTTP_PROTOCOL + self.bmcip +
RFLASH_URLS['activate']['url'].replace('#ACTIVATE_ID#', activate_id))
data = { "data": RFLASH_URLS['activate']['field'] }
try:
response = self.client.request('PUT', url, OpenBMC.headers,
data, 'rflash_activate')
except xcat_exception.SelfServerException as e:
return e.message
except xcat_exception.SelfClientException as e:
code = e.code
if code == 403:
return 'Error: Invalid ID provided to activate. ' \
'Use the -l option to view valid firmware IDs.'
return e.message
return RESULT_OK
def _rflash_activate(self, activate_arg):
"""ACTIVATE firmware
called by rflash activate
:param activate_arg: firmware tar ball or firmware id
:return: ok if success
:raise: error message if failed
"""
activate_id = activate_version = ''
if 'activate_id' in activate_arg:
activate_id = activate_arg['activate_id']
if 'update_file' in activate_arg:
result = self._rflash_upload(activate_arg['update_file'])
if result != RESULT_OK:
self._msg_process_rflash(result, all_nodes_result, False)
return
activate_version = activate_arg['activate_version']
(result, info) = self._get_firm_id([activate_version])
if result == RESULT_OK:
activate_id = info.pop(0)
else:
return
result = self._rflash_activate_id(activate_id)
if result != RESULT_OK:
self._msg_process_rflash(result, all_nodes_result, False)
return
else:
flash_started_msg = 'rflash %s started, please wait...' % activate_version
self._msg_process_rflash(flash_started_msg, {}, False)
firm_id_list = [activate_id]
(result, priority_ids) = self._check_id_status(firm_id_list)
if result == RESULT_OK:
utils.update2Ddict(all_nodes_result, self.node, 'result', 'OK')
if priority_ids:
self._set_priority(priority_ids)
def _rflash_delete(self, delete_id):
"""Delete firmware on OpenBMC
called by rflash delete
:param delete_id: firmware id want to delete
:returns: ok if success
:raise: error message if failed
"""
url = (HTTP_PROTOCOL + self.bmcip +
RFLASH_URLS['delete']['url'].replace('#DELETE_ID#', delete_id))
data = { "data": RFLASH_URLS['delete']['field'] }
try:
response = self.client.request('POST', url, OpenBMC.headers,
data, 'rflash_delete')
except xcat_exception.SelfServerException as e:
return e.message
except xcat_exception.SelfClientException as e:
code = e.code
if code == 404:
return 'Error: Invalid ID provided to delete. ' \
'Use the -l option to view valid firmware IDs.'
return e.message
return RESULT_OK
def _rflash_list(self):
"""List firmware information
called by rflash list
:returns: firmware version if success
:raise: error message if failed
"""
firm_output = []
try:
(has_functional, firm_info) = self._get_firm_info('rflash_list')
except (xcat_exception.SelfServerException,
xcat_exception.SelfClientException) as e:
firm_output.append(e.message)
return firm_output
firm_output.append('%-8s %-7s %-10s %-s' % ('ID', 'Purpose', 'State', 'Version'))
firm_output.append('-' * 55)
for key in firm_info:
status = firm_info[key]['Activation']
if 'is_functional' in firm_info[key]:
status += '(*)'
elif 'Priority' in firm_info[key] and firm_info[key]['Priority'] == '0':
if not has_functional:
status += '(*)'
else:
status += '(+)'
firm_output.append('%-8s %-7s %-10s %-s' % (key.split('-')[-1],
firm_info[key]['Purpose'], status, firm_info[key]['Version']))
return firm_output
def _rflash_upload(self, upload_file):
""" Upload *.tar file to OpenBMC server
:param upload_file: file to upload
"""
url = HTTP_PROTOCOL + self.bmcip + RFLASH_URLS['upload']['url']
headers = {'Content-Type': 'application/octet-stream'}
uploading_msg = 'Uploading %s ...' % upload_file
self._msg_process_rflash(uploading_msg, {}, True)
try:
self.client.request_upload('PUT', url, headers,
upload_file, 'rflash_upload')
except (xcat_exception.SelfServerException,
xcat_exception.SelfClientException) as e:
result = e.message
return result
return RESULT_OK
def rflash(self, args):
"""handle rflash command
:param args: subcommands and parameters for rflash
"""
subcommand = args[0]
if subcommand == 'activate' or subcommand == 'upload':
self.rflash_log_file = XCAT_LOG_RFLASH_DIR + '/' + self.node + '.log'
self.rflash_log_handle = open(self.rflash_log_file, 'a')
try:
result = self._login()
except (xcat_exception.SelfServerException,
xcat_exception.SelfClientException) as e:
result = e.message
if result != RESULT_OK:
self.messager.info('%s: %s'% (self.node,result))
if subcommand == 'activate' or subcommand == 'upload':
self.rflash_log_handle.writelines(result + '\n')
self.rflash_log_handle.flush()
if subcommand == 'activate':
utils.update2Ddict(all_nodes_result, self.node, 'result', [result])
return
if subcommand == 'activate':
activate_arg = args[1]
self._rflash_activate(activate_arg)
if subcommand == 'check':
firm_info = self._firm_info('rflash_check')
for i in firm_info:
result = '%s: %s' % (self.node, i)
self.messager.info(result)
if subcommand == 'delete':
firmware_id = args[1]
result = self._rflash_delete(firmware_id)
if result == RESULT_OK:
result = '%s: [%s] Firmware removed' % (self.node, firmware_id)
self.messager.info(result)
else:
result = '%s: %s' % (self.node, result)
self.messager.info(result)
if subcommand == 'list':
firm_info = self._rflash_list()
for i in firm_info:
result = '%s: %s' % (self.node, i)
self.messager.info(result)
if subcommand == 'upload':
upload_file = args[1]
result = self._rflash_upload(upload_file)
if result == RESULT_OK:
result = 'Firmware upload successful. Use -l option to list.'
self._msg_process_rflash(result, {}, False)
else:
self._msg_process_rflash(result, {}, False)
if subcommand == 'activate' or subcommand == 'upload':
self.rflash_log_handle.close()
class OpenBMCManager(base.BaseManager):
def __init__(self, messager, cwd, nodes=None, envs=None):
super(OpenBMCManager, self).__init__(messager, cwd)
@@ -614,7 +136,7 @@ class OpenBMCManager(base.BaseManager):
# 1, parse args
rbeacon_usage = """
Usage:
rbeacon [-V|--verbose] [on|off]
rbeacon [-V|--verbose] [on|off|stat]
Options:
-V --verbose rbeacon verbose mode.
@@ -631,22 +153,75 @@ class OpenBMCManager(base.BaseManager):
# 2, validate the args
if action is None:
self.messager.error("Not specify the subcommand for rbeacon")
self.messager.error("Subcommand for rbeacon was not specified")
return
if action not in BEACON_SET_OPTIONS:
if action not in BEACON_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)
if action == 'stat':
runner = OpenBMCSensorTask(nodesinfo, callback=self.messager, debugmode=self.debugmode, verbose=self.verbose)
DefaultSensorManager().get_beacon_info(runner, display_type='compact')
else:
runner = OpenBMCBeaconTask(nodesinfo, callback=self.messager, debugmode=self.debugmode, verbose=self.verbose)
DefaultBeaconManager().set_beacon_state(runner, beacon_state=action)
def rflash(self, nodesinfo, args):
# 1, parse agrs
rflash_usage = """
Usage:
rflash [[-a|--activate <arg>] | [-c|--check <arg>] | [-d <arg> [--no-host-reboot]] | [--delete <arg>] | [-l|--list] | [-u|--upload <arg>]] [-V|--verbose]
Options:
-V,--verbose Show verbose message
-a,--activate <arg> Activate firmware
-c,--check Check firmware info
-d <arg> Upload and activate all firmware files under directory
-l,--list List firmware info
-u,--upload <arg> Upload firmware file
--delete <arg> Delete firmware
--no-host-reboot Not reboot host after activate
"""
try:
opts = docopt(rflash_usage, argv=args)
self.verbose = opts.pop('--verbose')
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 rflash: %s" % args)
return
if opts['--check']:
check_arg = None
if opts['<arg>']:
check_arg = opts['<arg>']
runner = runner = OpenBMCInventoryTask(nodesinfo, callback=self.messager, debugmode=self.debugmode, verbose=self.verbose, cwd=self.cwd[0])
DefaultInventoryManager().get_firm_info(runner, check_arg)
return
runner = OpenBMCFlashTask(nodesinfo, callback=self.messager, debugmode=self.debugmode, verbose=self.verbose, cwd=self.cwd[0])
if opts['--activate']:
DefaultFlashManager().activate_firm(runner, opts['--activate'][0])
elif opts['--list']:
DefaultFlashManager().list_firm_info(runner)
elif opts['-d']:
DefaultFlashManager().flash_process(runner, opts['-d'], opts['--no-host-reboot'])
elif opts['--delete']:
DefaultFlashManager().delete_firm(runner, opts['--delete'])
elif opts['--upload']:
DefaultFlashManager().upload_firm(runner, opts['--upload'][0])
def rinv(self, nodesinfo, args):
# 1, parse agrs
if not args:
args = ['all']
if not args or (len(args) == 1 and args[0] in ['-V', '--verbose']):
args.append('all')
rinv_usage = """
Usage:
@@ -715,7 +290,11 @@ class OpenBMCManager(base.BaseManager):
DefaultPowerManager().reboot(runner, optype=action)
else:
DefaultPowerManager().set_power_state(runner, power_state=action)
def rspconfig(self, nodesinfo, args):
from hwctl.executor.openbmc_bmcconfig import OpenBMCBmcConfigTask
try:
opts=docopt(RSPCONFIG_USAGE, argv=args)
except DocoptExit as e:
@@ -768,6 +347,7 @@ class OpenBMCManager(base.BaseManager):
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
@@ -808,8 +388,8 @@ class OpenBMCManager(base.BaseManager):
def rvitals(self, nodesinfo, args):
# 1, parse agrs
if not args:
args = ['all']
if not args or (len(args) == 1 and args[0] in ['-V', '--verbose']):
args.append('all')
rvitals_usage = """
Usage:
@@ -872,7 +452,6 @@ class OpenBMCManager(base.BaseManager):
# 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':
@@ -884,98 +463,3 @@ class OpenBMCManager(base.BaseManager):
else:
DefaultEventlogManager().get_eventlog_info(runner, "all")
def _get_full_path(self,file_path):
if type(self.cwd) == 'unicode':
dir_path = self.cwd
else:
dir_path = self.cwd[0]
return '%s/%s' % (dir_path,file_path)
def _check_verbose(self, args):
verbose_list = ('-V', '--verbose')
for i in verbose_list:
if i in args:
global VERBOSE
VERBOSE = True
args.remove(i)
def _summary(self, nodes_num, title):
if all_nodes_result:
success_num = failed_num = 0
failed_list = []
for key in all_nodes_result:
if all_nodes_result[key]['result'] == 'OK':
success_num += 1
else:
failed_num += 1
for errors in all_nodes_result[key]['result']:
for error in errors:
failed_list.append('%s: %s' % (key, error))
self.messager.info('-' * 55)
self.messager.info('%s complete: Total=%d Success=%d Failed=%d' % \
(title, nodes_num, success_num, failed_num))
if failed_list:
for i in failed_list:
self.messager.info(i)
self.messager.info('-' * 55)
def rflash(self, nodeinfo, args):
if not os.path.exists(XCAT_LOG_RFLASH_DIR):
os.makedirs(XCAT_LOG_RFLASH_DIR)
nodes_num = len(self.nodes)
self._check_verbose(args)
for key,value in RFLASH_OPTIONS.items():
if key in args:
args.remove(key)
args.insert(0, value)
break
upload_file = None
activate_arg = {}
args_num = len(args)
subcommand = args[0]
if (subcommand == 'upload' or subcommand == 'activate' or
(subcommand == 'check' and args_num > 1)):
arg_type = args[1].split('.')[-1]
if arg_type == 'tar':
upload_file = args[1]
if not os.path.isabs(upload_file):
upload_file = self._get_full_path(upload_file)
if (not os.access(upload_file, os.F_OK) or
not os.access(upload_file, os.R_OK)):
error = 'Error: Cannot access %s. Check the management ' \
'node and/or service nodes.' % upload_file
self.messager.error(error)
return
activate_arg['update_file'] = upload_file
else:
activate_arg['activate_id'] = args[1]
if (subcommand == 'check' or subcommand == 'activate') and upload_file:
grep_cmd = '/usr/bin/grep -a'
version_cmd = grep_cmd + ' ^version= ' + upload_file
purpose_cmd = grep_cmd + ' purpose= ' + upload_file
firmware_ver = os.popen(version_cmd).readlines()[0].split('=')[-1].strip()
purpose_ver = os.popen(purpose_cmd).readlines()[0].split('=')[-1].strip()
if subcommand == 'check':
self.messager.info('TAR %s Firmware Product Version: %s' \
% (purpose_ver,firmware_ver))
else:
activate_arg['activate_version'] = firmware_ver
activate_arg['purpose'] = purpose_ver.split('.')[-1]
if subcommand == 'activate':
args[1] = activate_arg
if subcommand == 'upload':
args[1] = upload_file
if subcommand == 'upload' or subcommand == 'activate' and upload_file:
self.messager.info('Attempting to upload %s, please wait...' % upload_file)
super(OpenBMCManager, self).process_nodes_worker('openbmc', 'OpenBMC',
self.nodes, nodeinfo, 'rflash', args)
self._summary(nodes_num, 'Firmware update')
@@ -1,113 +0,0 @@
#!/usr/bin/env python
import requests
import json
import time
from common import rest
from common import exceptions as xcat_exception
class OpenBMCRest:
def __init__(self, name, messager, debugmode):
self.session = rest.RestSession()
self.name = name
self.messager = messager
self.debugmode = debugmode
def _print_record_log (self, log_string, status):
if self.debugmode :
localtime = time.asctime( time.localtime(time.time()) )
log = self.name + ': [openbmc_debug] ' + status + ' ' + log_string
self.messager.info(localtime + ' ' + log)
self.messager.syslog(log)
def _request_log (self, method, url, headers, data, files):
log_string = 'curl -k -c cjar -b cjar'
log_string += ' -X %s' % method
for key,value in headers.items():
header_data = key + ": " + value
log_string += ' -H "' + header_data + '"'
log_string += ' %s' % url
if data:
log_string += ' -d \'%s\'' % data
if files:
log_string += ' -T \'%s\'' % files
return log_string
def _response_check (self, response, response_dict, status):
if response.status_code != requests.codes.ok:
description = ''.join(response_dict['data']['description'])
error = 'Error: [%d] %s' % (response.status_code, description)
self._print_record_log(error, status)
code = response.status_code
raise xcat_exception.SelfClientException(error, code)
else:
self._print_record_log(response_dict['message'], status)
def request (self, method, url, headers, in_data, status):
data = log_data = ''
if in_data:
data = json.dumps(in_data)
log_data = data
if status == 'login':
in_data['data'][1] = 'xxxxxx'
log_data = json.dumps(in_data)
log_string = self._request_log(method, url, headers, log_data, '')
self._print_record_log(log_string, status)
try:
response = self.session.request(method, url, headers, data)
except xcat_exception.SelfServerException as e:
self._print_record_log(e.message, status)
raise xcat_exception.SelfServerException(e.message)
try:
response_dict = response.json()
except ValueError:
error = 'Error: Received wrong format response: %s' % response
self._print_record_log(error, status)
raise xcat_exception.SelfServerException(error)
self._response_check(response, response_dict, status)
return response_dict
def request_upload (self, method, url, headers, files, status):
for key,value in headers.items():
header_data = key + ': ' + value
request_cmd_log = 'curl -k -c cjar -b cjar -H "%s" -X %s -T %s %s -s' \
% (header_data, method, files, url)
log_string = self._request_log(method, url, headers, '', files)
self._print_record_log(log_string, status)
response = self.session.request_upload(method, url, header_data, files)
if not response:
error = 'Error: Did not receive response from OpenBMC after ' \
'running command form \'%s\'' % request_cmd_log
raise xcat_exception.SelfServerException(error)
try:
response_dict = json.loads(response)
except ValueError:
error = 'Error: Received wrong format response: %s: %s' % \
(request_cmd_log, response)
self._print_record_log(error, status)
raise xcat_exception.SelfServerException(error)
if response_dict['message'] != '200 OK':
error = 'Error: Failed to upload update file %s : %s-%s' % \
(files, response_dict['message'], \
''.join(response_dict['data']['description']))
self._print_record_log(error, status)
raise xcat_exception.SelfClientException(error, code)
self._print_record_log(response_dict['message'], status)
return
+2 -1
View File
@@ -20,7 +20,8 @@ BuildArch: noarch
Requires: xCAT-server
Requires: python-gevent >= 1.2.2-2
Requires: python-greenlet >= 0.4.13-2
Requires: python2-docopt python-requests python-paramiko python-scp
Requires: python-paramiko >= 2.0.0
Requires: python2-docopt python-requests python-scp
%description
xCAT-openbmc-py provides openbmc related functions.
+1
View File
@@ -8,6 +8,7 @@ opt/xcat/share/xcat/netboot
opt/xcat/share/xcat/templates
opt/xcat/share/xcat/ca
opt/xcat/share/xcat/scripts
opt/xcat/share/xcat/conf
opt/xcat/share/xcat/tools
opt/xcat/share/xcat/rollupdate
opt/xcat/share/xcat/installp_bundles
+1
View File
@@ -6,6 +6,7 @@ share/xcat/mypostscript/* opt/xcat/share/xcat/mypostscript/
share/xcat/ca/* opt/xcat/share/xcat/ca
share/xcat/scripts/* opt/xcat/share/xcat/scripts
share/xcat/conf/* opt/xcat/share/xcat/conf
share/xcat/tools/* opt/xcat/share/xcat/tools
share/xcat/rollupdate/* opt/xcat/share/xcat/rollupdate
share/xcat/installp_bundles/* opt/xcat/share/xcat/installp_bundles
+1
View File
@@ -47,6 +47,7 @@ binary-arch:
chmod 755 $(rootdir)/bin/*
chmod 755 $(rootdir)/sbin/*
chmod 644 $(rootdir)/share/xcat/ca/*
chmod 644 $(rootdir)/share/xcat/conf/*
chmod 755 $(rootdir)/share/xcat/cons/*
chmod 755 $(rootdir)/share/xcat/ib/*
chmod 755 $(rootdir)/share/xcat/ib/netboot/sles/*
+93 -73
View File
@@ -60,7 +60,7 @@ sub http_request {
sub gen_request_data {
my ($cons_map, $siteondemand, $callback) = @_;
my (@openbmc_nodes, $data);
my (@openbmc_nodes, $data, $rsp);
while (my ($k, $v) = each %{$cons_map}) {
my $ondemand;
if ($siteondemand) {
@@ -73,17 +73,14 @@ sub gen_request_data {
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;
my $env = "";
my $locerror = $isSN ? "PERL_BADLANG=0 " : '';
if (defined($ENV{'XCATSSLVER'})) {
$env = "XCATSSLVER=$ENV{'XCATSSLVER'} ";
}
$data->{$k}->{params}->{env} = $locerror.$env;
$data->{$k}->{driver} = "cmd";
$data->{$k}->{params}->{cmd} = $cmd;
$data->{$k}->{params}->{cmd} = $::XCATROOT . "/share/xcat/cons/$cmeth"." ".$k;
$data->{$k}->{name} = $k;
}
if (defined($v->{consoleondemand})) {
@@ -107,11 +104,7 @@ sub gen_request_data {
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");
}
xCAT::MsgUtils->error_message("$node: Unable to get attribute bmc.", $callback);
delete $data->{$node};
next;
}
@@ -121,11 +114,7 @@ sub gen_request_data {
} 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");
}
xCAT::MsgUtils->error_message("$node: Unable to get attribute username.", $callback);
delete $data->{$node};
next;
}
@@ -134,11 +123,7 @@ sub gen_request_data {
} 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");
}
xCAT::MsgUtils->error_message("$node: Unable to get attribute password.", $callback);
delete $data->{$node};
next;
}
@@ -207,6 +192,10 @@ sub init_local_console {
unless ($_->{cons}) {
$_->{cons} = $_->{mgt};
}
if ( $_->{cons} ne 'openbmc' && ! -x $::XCATROOT . "/share/xcat/cons/".$_->{cons}) {
xCAT::MsgUtils->message("S", $_->{node} .": ignore, ". $::XCATROOT . "/share/xcat/cons/".$_->{cons}." is not excutable. Please check mgt or cons attribute.");
next;
}
if ($_->{conserver} && exists($iphash{ $_->{conserver} })) {
$cons_map{ $_->{node} } = $_;
}
@@ -271,22 +260,12 @@ sub delete_nodes {
$ret = 0;
my $response = http_request("DELETE", $url, $data);
if (!defined($response)) {
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.");
}
xCAT::MsgUtils->error_message("Failed to send delete request.", $callback);
return 1;
} elsif ($delmode) {
while (my ($k, $v) = each %{$response}) {
if ($v ne "Deleted") {
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");
}
xCAT::MsgUtils->error_message("$k: Failed to delete entry in goconserver: $v", $callback);
$ret = 1;
} else {
if ($callback) {
@@ -299,12 +278,7 @@ sub delete_nodes {
}
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.");
}
xCAT::MsgUtils->error_message("Failed to update consoleenabled status in db.", $callback);
}
}
return $ret;
@@ -321,22 +295,12 @@ sub create_nodes {
$ret = 0;
my $response = http_request("POST", $url, $data);
if (!defined($response)) {
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.");
}
xCAT::MsgUtils->error_message("Failed to send create request.", $callback);
return 1;
} elsif ($response) {
while (my ($k, $v) = each %{$response}) {
if ($v ne "Created") {
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");
}
xCAT::MsgUtils->error_message("$k: Failed to create console entry in goconserver: $v", $callback);
$ret = 1;
} else {
$rsp->{data}->[0] = "$k: $v";
@@ -347,12 +311,7 @@ sub create_nodes {
}
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.");
}
xCAT::MsgUtils->error_message("Failed to update consoleenabled status in db.", $callback);
}
}
return $ret;
@@ -364,13 +323,11 @@ sub list_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);
xCAT::MsgUtils->error_message("Failed to send list request. Is goconserver service started?", $callback);
return 1;
}
if (!$response->{nodes}) {
$rsp->{data}->[0] = "Could not find any node.";
xCAT::MsgUtils->message("I", $rsp, $callback);
xCAT::MsgUtils->info_message("Could not find any node.", $callback);
return 0;
}
$rsp->{data}->[0] = sprintf("\n".PRINT_FORMAT, "NODE", "SERVER", "STATE");
@@ -381,8 +338,7 @@ sub list_nodes {
}
$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);
xCAT::MsgUtils->error_message(sprintf(PRINT_FORMAT, $node->{name}, "", "Unable to parse the response message"), $callback);
next;
}
$rsp->{data}->[0] = sprintf(PRINT_FORMAT, $node->{name}, $node->{host}, substr($node->{state}, 0, 16));
@@ -406,12 +362,7 @@ sub cleanup_nodes {
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.");
}
xCAT::MsgUtils->error_message("Failed to send list request. Is goconserver service started?", $callback);
return 1;
}
if (!$response->{nodes}) {
@@ -459,6 +410,11 @@ sub get_cons_map {
if ($_->{cons} or defined($_->{'serialport'})) {
unless ($_->{cons}) { $_->{cons} = $_->{mgt}; } #populate with fallback
if ($isSN && $_->{conserver} && exists($iphash{ $_->{conserver} }) || !$isSN) {
if ( $_->{cons} ne 'openbmc' && ! -x $::XCATROOT . "/share/xcat/cons/".$_->{cons}) {
$rsp->{data}->[0] = $_->{node} .": ignore, ". $::XCATROOT . "/share/xcat/cons/".$_->{cons}." is not excutable. Please check mgt or cons attribute.";
xCAT::MsgUtils->message("I", $rsp, $::callback);
next;
}
$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.";
@@ -531,6 +487,70 @@ sub is_goconserver_running {
#-------------------------------------------------------------------------------
=head3 switch_goconserver
Disable conserver and enable goconserver during startup.
Globals:
none
Example:
xCAT::Goconserver::switch_goconserver()
Comments:
none
=cut
#-------------------------------------------------------------------------------
sub switch_goconserver {
my $callback = shift;
# ignore SN as it is handled by AAsn
if ((-x "/usr/bin/systemctl" || -x "-x /bin/systemctl") && !$isSN) {
my $cmd = "systemctl disable conserver";
xCAT::Utils->runcmd($cmd, -1);
if ($::RUNCMD_RC != 0) {
xCAT::MsgUtils->warn_message("Failed to execute command: $cmd.", $callback);
}
$cmd = "systemctl enable goconserver";
xCAT::Utils->runcmd($cmd, -1);
if ($::RUNCMD_RC != 0) {
xCAT::MsgUtils->warn_message("Failed to execute command: $cmd.", $callback);
}
}
}
#-------------------------------------------------------------------------------
=head3 switch_conserver
Disable goconserver and enable conserver during startup.
Globals:
none
Example:
xCAT::Goconserver::switch_conserver()
Comments:
none
=cut
#-------------------------------------------------------------------------------
sub switch_conserver {
my $callback = shift;
# ignore SN as it is handled by AAsn
if ((-x "/usr/bin/systemctl" || -x "-x /bin/systemctl") && !$isSN) {
my $cmd = "systemctl disable goconserver";
xCAT::Utils->runcmd($cmd, -1);
if ($::RUNCMD_RC != 0) {
xCAT::MsgUtils->warn_message("Failed to execute command: $cmd.", $callback);
}
$cmd = "systemctl enable conserver";
xCAT::Utils->runcmd($cmd, -1);
if ($::RUNCMD_RC != 0) {
xCAT::MsgUtils->warn_message("Failed to execute command: $cmd.", $callback);
}
}
}
#-------------------------------------------------------------------------------
=head3 is_conserver_running
Check if the conserver service is running
+1 -1
View File
@@ -255,7 +255,7 @@ sub run_cmd_in_perl {
}
# List of commands currently not supported in Python
my @unsupported_in_python_commands = ('rflash', 'rspconfig', 'reventlog');
my @unsupported_in_python_commands = ('rflash', 'getopenbmccons');
if ($command ~~ @unsupported_in_python_commands) {
# Command currently not supported in Python
+7
View File
@@ -573,6 +573,13 @@ sub makescript {
$master_ip = "$ipaddr";
}
unless($master_ip){
my $rsp;
$rsp->{data}->[0] = "makescript failed: unable to resolve xcatmaster \"$master\" for $node";
xCAT::MsgUtils->message("SE", $rsp, $callback, 1);
return;
}
#ok, now do everything else..
#$inc =~ s/#XCATVAR:([^#]+)#/envvar($1)/eg;
#$inc =~ s/#ENV:([^#]+)#/xCAT::Template::envvar($1)/eg;
+47 -5
View File
@@ -1554,6 +1554,7 @@ sub defmk
} else {
my $invalidobjname = ();
my $invalidnodename = ();
my $nodewithdomain = ();
foreach my $node (@::allobjnames) {
my $myobjtype=$::opt_t;
if(!$myobjtype and $::FILEATTRS{$node}{'objtype'}){
@@ -1563,10 +1564,22 @@ sub defmk
unless(isobjnamevalid($node,$myobjtype)){
$invalidobjname .= ",$node";
}
if (($node =~ /[A-Z]/) && (((!$::opt_t) && (!$::FILEATTRS{$node}{'objtype'})) || ($::FILEATTRS{$node}{'objtype'} eq "node") || ($::opt_t eq "node"))) {
$invalidnodename .= ",$node";
if (((!$::opt_t) && (!$::FILEATTRS{$node}{'objtype'})) || ($::FILEATTRS{$node}{'objtype'} eq "node") || ($::opt_t eq "node")) {
if($node =~ /[A-Z]/){
$invalidnodename .= ",$node";
}elsif($node =~ /\./){
$nodewithdomain .= ",$node";
}
}
}
if ($nodewithdomain) {
$nodewithdomain =~ s/,//;
my $rsp;
$rsp->{data}->[0] = "The object name \'$nodewithdomain\' is invalid, Cannot use '.' in node name.";
xCAT::MsgUtils->message("E", $rsp, $::callback);
$error = 1;
return 1;
}
if ($invalidobjname) {
$invalidobjname =~ s/,//;
my $rsp;
@@ -2361,7 +2374,8 @@ sub defch
$objTypeListsHash{$objk}{$obj} = 1;
}
}
my $nodewithdomain;
my $invalidobjname = ();
foreach my $obj (keys %::FINALATTRS)
{
@@ -2384,7 +2398,17 @@ sub defch
$error = 1;
next;
}
if ($obj =~ /\./ && $type eq "node")
{
$nodewithdomain .= ",$obj";
delete($::FINALATTRS{$obj});
next;
}
unless(isobjnamevalid($obj,$type)){
$invalidobjname .= ",$obj";
delete($::FINALATTRS{$obj});
next;
}
if (defined($objTypeListsHash{$type}{$obj}) && ($objTypeListsHash{$type}{$obj} == 1))
{
$isDefined = 1;
@@ -2847,7 +2871,17 @@ sub defch
}
} # end - for each object to update
my $rsp;
if ($nodewithdomain) {
$nodewithdomain =~ s/,//;
$rsp->{data}->[0] = "The object name \'$nodewithdomain\' is invalid, Cannot use '.' in node name.";
xCAT::MsgUtils->message("E", $rsp, $::callback);
}
if ($invalidobjname) {
$invalidobjname =~ s/,//;
$rsp->{data}->[0] = "The object name \'$invalidobjname\' is invalid, please refer to \"man xcatdb\" for the valid \"xCAT Object Name Format\"";
xCAT::MsgUtils->message("E", $rsp, $::callback);
}
#
# write each object into the tables in the xCAT database
#
@@ -4710,12 +4744,20 @@ sub initialize_variables
sub isobjnamevalid{
my $objname=shift;
my $objtype=shift;
my %options;
$options{keepmissing}=1;
$options{genericrange}=1;
$objtype="node" unless(defined $objtype and ($objtype ne ""));
if($objtype eq "node"){
#the ip address as a valid node object name is a hack for p7IH support
if(($objname !~ /^[a-zA-Z0-9-_]+$/) and !xCAT::NetworkUtils->isIpaddr($objname)){
return 0;
}
} elsif ($objtype eq "group"){
my @tmpnodes=xCAT::NodeRange::noderange($objname,0,0,%options);
if(scalar(@tmpnodes)>1 || $tmpnodes[0] ne $objname ){
return 0;
}
}
return 1;
}
+4 -1
View File
@@ -1053,7 +1053,7 @@ sub bmcdiscovery_ipmi {
if ($output =~ $bmcstr) {
store_fd({data=>1}, $fd);
if ($output =~ /RAKP 2 message indicates an error : (.+)\nError: (.+)/) {
if ($output =~ /RAKP \d+ message indicates an error : (.+)\nError: (.+)/) {
xCAT::MsgUtils->message("W", { data => ["$2: $1 for $ip"] }, $::CALLBACK);
return;
}
@@ -1127,6 +1127,9 @@ sub bmcdiscovery_ipmi {
} elsif ($output =~ /RAKP \S* \S* is invalid/) {
xCAT::MsgUtils->message("W", { data => ["BMC password is incorrect for $ip"] }, $::CALLBACK);
return;
} else {
xCAT::MsgUtils->message("W", { data => ["Unknown error get from $ip"] }, $::CALLBACK);
return;
}
display_output($opz,$opw,$mtms_node,$mac_node,$node_data,"ipmi",$request_command);
+7 -1
View File
@@ -201,14 +201,16 @@ sub preprocess_request {
sub process_request {
my $req = shift;
my $cb = shift;
$::callback = $cb;
if ($req->{command}->[0] eq "makeconservercf") {
if (-x "/usr/bin/goconserver") {
require xCAT::Goconserver;
if (xCAT::Goconserver::is_goconserver_running()) {
my $rsp->{data}->[0] = "goconserver is started, please stop it at first.";
my $rsp->{data}->[0] = "goconserver is being used as the console service, did you mean: makegocons <noderange>? If not, stop goconserver and retry.";
xCAT::MsgUtils->message("E", $rsp, $cb);
return;
}
xCAT::Goconserver::switch_conserver($cb);
}
makeconservercf($req, $cb);
}
@@ -602,6 +604,10 @@ sub donodeent {
# either there is no console method (shouldnt happen) or not one of the supported terminal servers
return $node;
}
if (!grep(/^$cmeth$/, @cservers) && ! -x $::XCATROOT . "/share/xcat/cons/" . $cmeth) {
xCAT::SvrUtils::sendmsg([ 0, "ignore, ". $::XCATROOT . "/share/xcat/cons/$cmeth is not excutable. Please check mgt or cons attribute." ], $::callback, $node);
next;
}
push @$content, "#xCAT BEGIN $node CONS\n";
push @$content, "console $node {\n";
if (grep(/^$cmeth$/, @cservers)) {
+19
View File
@@ -226,6 +226,25 @@ sub setdestiny {
if ($ient->{initrd}) { $bphash->{initrd} = $ient->{initrd} }
if ($ient->{kcmdline}) { $bphash->{kcmdline} = $ient->{kcmdline} }
}
} elsif ($state =~ /ondiscover/) {
my $target;
if ($state =~ /=/) {
($state, $target) = split '=', $state, 2;
}
if(!$target){
$callback->({ error => "invalid argument: \"$state\"", errorcode => [1] });
return;
}
my @cmds = split '\|', $target;
foreach my $tmpnode (@{ $req->{node} }) {
foreach my $cmd (@cmds) {
my $action;
($cmd, $action) = split ':', $cmd;
my $runcmd = "$cmd $tmpnode $action";
xCAT::Utils->runcmd($runcmd, 0);
xCAT::MsgUtils->trace($verbose, "d", "run ondiscover command: $runcmd");
}
}
} elsif ($state =~ /^install[=\$]/ or $state eq 'install' or $state =~ /^netboot[=\$]/ or $state eq 'netboot' or $state eq "image" or $state eq "winshell" or $state =~ /^osimage/ or $state =~ /^statelite/) {
my $target;
my $action;
+16 -15
View File
@@ -6,6 +6,7 @@ BEGIN {
}
use lib "$::XCATROOT/lib/perl";
use strict;
use File::Copy;
use xCAT::Table;
use xCAT::Utils;
use xCAT::TableUtils;
@@ -142,16 +143,15 @@ sub process_request {
sub start_goconserver {
my ($rsp, $running, $ready, $ret);
unless (-x "/usr/bin/goconserver") {
$rsp->{data}->[0] = "goconserver is not installed.";
xCAT::MsgUtils->message("E", $rsp, $::callback);
xCAT::MsgUtils->error_message("goconserver is not installed.", $::callback);
return 1;
}
# if goconserver is installed, check the status of conserver service.
if (xCAT::Goconserver::is_conserver_running()) {
$rsp->{data}->[0] = "conserver is started, please stop it at first.";
xCAT::MsgUtils->message("E", $rsp, $::callback);
xCAT::MsgUtils->error_message("conserver is started, please stop it at first.", $::callback);
return 1;
}
xCAT::Goconserver::switch_goconserver($::callback);
$running = xCAT::Goconserver::is_goconserver_running();
$ready = xCAT::Goconserver::is_xcat_conf_ready();
if ( $running && $ready ) {
@@ -163,19 +163,19 @@ sub start_goconserver {
if (!$ready) {
$ret = xCAT::Goconserver::build_conf();
if ($ret) {
$rsp->{data}->[0] = "Failed to create configuration file for goconserver.";
xCAT::MsgUtils->message("E", $rsp, $::callback);
xCAT::MsgUtils->error_message("Failed to create configuration file for goconserver.", $::callback);
return 1;
}
if (!copy($::XCATROOT."/share/xcat/conf/goconslogrotate", "/etc/logrotate.d/goconserver")) {
xCAT::MsgUtils->warn_message("Failed to create logrotate configuration for goconserver.", $::callback);
}
}
$ret = xCAT::Goconserver::restart_service();
if ($ret) {
$rsp->{data}->[0] = "Failed to start goconserver service.";
xCAT::MsgUtils->message("E", $rsp, $::callback);
xCAT::MsgUtils->error_message("Failed to start goconserver service.", $::callback);
return 1;
}
$rsp->{data}->[0] = "Starting goconserver service ...";
xCAT::MsgUtils->message("I", $rsp, $::callback);
xCAT::MsgUtils->info_message("Starting goconserver service ...", $::callback);
sleep(3);
return 0;
}
@@ -197,19 +197,20 @@ sub makegocons {
);
my $svboot = 0;
my $rsp;
if (exists($req->{svboot})) {
$svboot = 1;
}
if ($cleanupmode) {
if (exists($req->{_allnodes}) && $req->{_allnodes}->[0] != 1) {
xCAT::SvrUtils::sendmsg([ 1, "Can not specify noderange together with -C|--cleanup." ], $::callback);
xCAT::MsgUtils->error_message("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);
xCAT::MsgUtils->error_message("Could not get any console request entry.", $::callback);
return 1;
}
my $api_url = "https://$host:". xCAT::Goconserver::get_api_port();
@@ -230,13 +231,13 @@ sub makegocons {
}
elsif (lc($site_entry) ne "no") {
# consoleondemand attribute is set, but it is not "yes" or "no"
xCAT::SvrUtils::sendmsg([ 1, "Unexpected value $site_entry for consoleondemand attribute in site table" ], $::callback);
xCAT::MsgUtils->error_message("Unexpected value $site_entry for consoleondemand attribute in site table.", $::callback);
}
}
my (@nodes);
my $data = xCAT::Goconserver::gen_request_data(\%cons_map, $siteondemand, $::callback);
if (! $data) {
xCAT::SvrUtils::sendmsg([ 1, "Could not generate the request data" ], $::callback);
xCAT::MsgUtils->error_message("Could not generate the request data.", $::callback);
return 1;
}
$ret = xCAT::Goconserver::delete_nodes($api_url, $data, $delmode, $::callback);
@@ -245,7 +246,7 @@ sub makegocons {
}
$ret = xCAT::Goconserver::create_nodes($api_url, $data, $::callback);
if ($ret != 0) {
xCAT::SvrUtils::sendmsg([ 1, "Failed to create console entry in goconserver. "], $::callback);
xCAT::MsgUtils->error_message("Failed to create console entry in goconserver.", $::callback);
return $ret;
}
return 0;
+52 -12
View File
@@ -2021,7 +2021,7 @@ sub do_firmware_update {
if (scalar(@pnor_files) > 1) {
# Error if more than one .pnor file in data directory
$exit_with_error_func->($sessdata->{node}, $callback,
"Multiple PNOR update files detected in data directory $pUpdate_directory.");
"Multiple Host update files detected in data directory $pUpdate_directory.");
}
if (scalar(@bmc_files) > 1) {
@@ -2064,7 +2064,7 @@ sub do_firmware_update {
"Timeout to check the bmc status");
}
# step 2 update BMC file or PNOR file, or both
# step 2 update BMC file or Host file, or both
if ($bmc_file) {
# BMC file was found in data directory, run update with it
my $pUpdate_bmc_cmd = "$pUpdate_directory/pUpdate -f $bmc_file -i lan -h $bmc_addr -u $bmc_userid -p $bmc_password >".$rflash_log_file." 2>&1";
@@ -2088,11 +2088,11 @@ sub do_firmware_update {
if ($pnor_file) {
# PNOR file was found in data directory, run update with it
# Host file was found in data directory, run update with it
my $pUpdate_pnor_cmd = "$pUpdate_directory/pUpdate -pnor $pnor_file -i lan -h $bmc_addr -u $bmc_userid -p $bmc_password >>".$rflash_log_file." 2>&1";
if ($verbose) {
xCAT::SvrUtils::sendmsg([ 0,
"rflashing PNOR, see the detail progress :\"tail -f $rflash_log_file\"" ],
"rflashing Host, see the detail progress :\"tail -f $rflash_log_file\"" ],
$callback, $sessdata->{node});
}
my $output = xCAT::Utils->runcmd($pUpdate_pnor_cmd, -1);
@@ -2414,7 +2414,8 @@ sub rflash {
} elsif ($opt !~ /.*\.hpm$/i && $opt !~ /^-V{1,4}$|^--buffersize=|^--retry=/) {
# An unexpected flag was passed, but it could be a directory name. Display error only if not -d option
unless ($directory_flag) {
$callback->({ error => "The option $opt is not supported or invalid update file specified",
my $node = $sessdata->{node};
$callback->({ data => "$node: Error: The option $opt is not supported or invalid update file specified",
errorcode => 1 });
return;
}
@@ -2523,6 +2524,10 @@ sub do_rflash_process {
my $cmd = "/usr/bin/tftp $bmcip -m binary -c put $recover_image ".basename($recover_image);
my $output = xCAT::Utils->runcmd($cmd, -1);
if ($::RUNCMD_RC != 0) {
if ($output =~ "timed out") {
# Time out running tftp command. One possible reason is BMC not in "brick protection" mode
$output .= " BMC might not be in 'Brick protection' state";
}
$callback->({ error => "Running tftp command \'$cmd\' failed. Error Code: $::RUNCMD_RC. Output: $output.",
errorcode => 1 });
exit(1);
@@ -8276,13 +8281,20 @@ sub preprocess_request {
return;
}
my $all_noderange = $realnoderange;
if ($command eq "rpower") {
my $subcmd = $exargs[0];
if ($subcmd eq '') {
#$callback->({data=>["Please enter an action (eg: boot,off,on, etc)", $usage_string]});
#Above statement will miss error code, so replaced by the below statement
$callback->({ errorcode => [1], data => [ "Please enter an action (eg: boot,off,on, etc)", $usage_string ] });
my $error_data = "";
foreach (@$all_noderange) {
$error_data .= "\n" if ($error_data);
$error_data .= "$_: Please enter an action (eg: boot,off,on, etc) when using mgt=ipmi.";
}
$callback->({ errorcode => [1], data => [ $error_data ] });
$request = {};
return 0;
}
@@ -8296,13 +8308,23 @@ sub preprocess_request {
#$callback->({data=>["Unsupported command: $command $subcmd", $usage_string]});
#Above statement will miss error code, so replaced by the below statement
$callback->({ errorcode => [1], data => [ "Unsupported command: $command $subcmd", $usage_string ] });
my $error_data = "";
foreach (@$all_noderange) {
$error_data .= "\n" if ($error_data);
$error_data .= "$_: Error: Unsupported command: $command $subcmd when using mgt=ipmi.";
}
$callback->({ errorcode => [1], data => [ $error_data ] });
$request = {};
return;
}
if (($subcmd eq 'on' or $subcmd eq 'reset' or $subcmd eq 'boot') and $::XCATSITEVALS{syspowerinterval}) {
unless ($::XCATSITEVALS{syspowermaxnodes}) {
$callback->({ errorcode => [1], error => ["IPMI plugin requires syspowermaxnodes be defined if syspowerinterval is defined"] });
my $error_data = "";
foreach (@$all_noderange) {
$error_data .= "\n" if ($error_data);
$error_data .= "$_: 'syspowermaxnodes` is required if 'syspowerinterval' is configured in the site table.";
}
$callback->({ errorcode => [1], error => [$error_data] });
$request = {};
return 0;
}
@@ -8324,10 +8346,15 @@ sub preprocess_request {
if ($realnoderange) {
my $optset;
my $option;
my $error_data = "";
foreach (@exargs) {
if ($_ =~ /^(\w+)=(.*)/) {
if ($optset eq 0) {
$callback->({ errorcode => [1], data => [ "Usage Error: Cannot display and change attributes on the same command."] });
foreach (@$all_noderange) {
$error_data .= "\n" if ($error_data);
$error_data .= "$_: Usage Error: Cannot display and change attributes on the same command when using mgt=ipmi..";
}
$callback->({ errorcode => [1], data => [ $error_data] });
$request = {};
return;
}
@@ -8335,7 +8362,11 @@ sub preprocess_request {
$option = $1;
} else {
if ($optset eq 1) {
$callback->({ errorcode => [1], data => [ "Usage Error: Cannot display and change attributes on the same command."] });
foreach (@$all_noderange) {
$error_data .= "\n" if ($error_data);
$error_data .= "$_: Usage Error: Cannot display and change attributes on the same command when using mgt=ipmi.";
}
$callback->({ errorcode => [1], data => [ $error_data] });
$request = {};
return;
}
@@ -8343,7 +8374,11 @@ sub preprocess_request {
$optset = 0;
}
unless ($option =~ /^USERID$|^ip$|^netmask$|^gateway$|^vlan$|^userid$|^username$|^password$|^snmpdest|^thermprofile$|^alert$|^garp$|^community$|^backupgateway$/) {
$callback->({ errorcode => [1], data => [ "Unsupported command: $command $_"] });
foreach (@$all_noderange) {
$error_data .= "\n" if ($error_data);
$error_data .= "$_: Error: Unsupported command: $command $option when using mgt=ipmi.";
}
$callback->({ errorcode => [1], data => [ $error_data ] });
$request = {};
return;
}
@@ -8353,7 +8388,12 @@ sub preprocess_request {
if ($exargs[0] eq "-t" and $#exargs == 0) {
unshift @{ $request->{arg} }, 'all';
} elsif ((grep /-t/, @exargs) and !(grep /(all|vpd)/, @exargs)) {
$callback->({ errorcode => [1], error => ["option '-t' can only work with 'all' or 'vpd'"] });
my $error_data = "";
foreach (@$all_noderange) {
$error_data .= "\n" if ($error_data);
$error_data .= "$_: option '-t' can only work with 'all' or 'vpd' when using mgt=ipmi.";
}
$callback->({ errorcode => [1], data => [ $error_data ] });
$request = {};
return 0;
}
+181 -50
View File
@@ -60,7 +60,6 @@ $::RSETBOOT_URL_PATH = "boot";
$::UPLOAD_AND_ACTIVATE = 0;
$::UPLOAD_ACTIVATE_STREAM = 0;
$::RFLASH_STREAM_NO_HOST_REBOOT = 0;
$::TAR_FILE_PATH = "";
$::NO_ATTRIBUTES_RETURNED = "No attributes returned from the BMC.";
$::UPLOAD_WAIT_ATTEMPT = 6;
@@ -276,6 +275,10 @@ my %status_info = (
process => \&rflash_response,
},
RFLASH_DELETE_CHECK_STATE_RESPONSE => {
process => \&rflash_response,
},
RINV_REQUEST => {
method => "GET",
init_url => "$openbmc_project_url/inventory/enumerate",
@@ -789,11 +792,11 @@ sub preprocess_request {
# Could not find usage for openbmc section, try getting usage for all sections
$usage_string = xCAT::Usage->parseCommand($command, @exargs);
}
else {
#else {
# Usage for openbmc section was extracted, append autogenerated usage for
# configured commands
$usage_string .= &build_config_api_usage($callback, $command);
}
# $usage_string .= &build_config_api_usage($callback, $command);
#}
$callback->({ data => [$usage_string] });
$request = {};
@@ -908,6 +911,9 @@ sub process_request {
my $rst = parse_command_status($command, \@exargs);
return if ($rst);
if ($::VERBOSE) {
xCAT::SvrUtils::sendmsg("Running command in Perl", $callback);
}
if ($request->{command}->[0] ne "getopenbmccons") {
$cookie_jar = HTTP::Cookies->new({});
$async = HTTP::Async->new(
@@ -977,7 +983,7 @@ sub process_request {
if ($next_status{LOGIN_RESPONSE} eq "RSPCONFIG_SET_HOSTNAME_REQUEST" and $status_info{RSPCONFIG_SET_HOSTNAME_REQUEST}{data} =~ /^\*$/) {
if ($node_info{$node}{bmc} =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) {
my $info_msg = "Invalid OpenBMC Hostname $node_info{$node}{bmc}, can't set to OpenBMC";
xCAT::SvrUtils::sendmsg($info_msg, $callback, $node);
xCAT::SvrUtils::sendmsg([1, $info_msg], $callback, $node);
$wait_node_num--;
next;
}
@@ -1154,8 +1160,8 @@ sub parse_args {
}
if ($command eq "rbeacon") {
unless ($subcommand =~ /^on$|^off$/) {
return ([ 1, "Only 'on' or 'off' is supported for OpenBMC managed nodes."]);
unless ($subcommand =~ /^on$|^off$|^stat$/) {
return ([ 1, "Only 'on', 'off' or 'stat' are supported for OpenBMC managed nodes."]);
}
} elsif ($command eq "rpower") {
unless ($subcommand =~ /^on$|^off$|^softoff$|^reset$|^boot$|^bmcreboot$|^bmcstate$|^status$|^stat$|^state$/) {
@@ -1385,12 +1391,6 @@ sub parse_args {
if ($invalid_options) {
return ([ 1, "Invalid option specified $invalid_options"]);
}
if (!opendir(DIR, $tarball_path[0])) {
return ([1, "Can't open directory : $tarball_path[0]"]);
} else {
$::TAR_FILE_PATH = $tarball_path[0];
closedir(DIR);
}
} elsif ($option_flag =~ /^-c$|^--check$|^-u$|^--upload$|^-a$|^--activate$/) {
return ([ 1, "Invalid firmware specified with $option_flag" ]);
} else {
@@ -1442,6 +1442,10 @@ sub parse_command_status {
} elsif ($subcommand eq "off") {
$next_status{LOGIN_RESPONSE} = "RBEACON_OFF_REQUEST";
$next_status{RBEACON_OFF_REQUEST} = "RBEACON_OFF_RESPONSE";
} elsif ($subcommand eq "stat") {
$next_status{LOGIN_RESPONSE} = "RVITALS_LEDS_REQUEST";
$next_status{RVITALS_LEDS_REQUEST} = "RVITALS_LEDS_RESPONSE";
$status_info{RVITALS_LEDS_RESPONSE}{argv} = "compact";
}
}
@@ -1643,7 +1647,13 @@ sub parse_command_status {
# Everything else is invalid
xCAT::SvrUtils::sendmsg([1, "Invalid value '$subcommand_value' for '$subcommand_key'"], $callback);
my @valid_values = keys %{ $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{attr_value} };
xCAT::SvrUtils::sendmsg([1, "Valid values: " . join(",", @valid_values)], $callback);
if (!@valid_values) {
if ($api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{type} eq "boolean") {
xCAT::SvrUtils::sendmsg([1, "Valid values: 0,1"], $callback);
}
} else {
xCAT::SvrUtils::sendmsg([1, "Valid values: " . join(",", @valid_values)], $callback);
}
return 1;
}
}
@@ -1853,6 +1863,10 @@ sub parse_command_status {
$next_status{LOGIN_RESPONSE} = "RVITALS_REQUEST";
$next_status{RVITALS_REQUEST} = "RVITALS_RESPONSE";
$status_info{RVITALS_RESPONSE}{argv} = "$subcommand";
if ($subcommand eq "all") {
$next_status{RVITALS_RESPONSE} = "RVITALS_LEDS_REQUEST";
$next_status{RVITALS_LEDS_REQUEST} = "RVITALS_LEDS_RESPONSE";
}
}
}
@@ -1894,8 +1908,15 @@ sub parse_command_status {
my $purpose_tag = '"purpose="';
my $purpose_value;
my $version_value;
my $tarfile_path;
if (defined $update_file) {
if ($streamline) {
if ($update_file =~ /^\//){
$tarfile_path = $update_file;
} else {
$tarfile_path =xCAT::Utils->full_path($update_file, $::cwd);
}
}
# Filename or file id was specified
if ($update_file =~ /.*\.tar$/) {
# Filename ending on .tar was specified
@@ -1947,13 +1968,18 @@ sub parse_command_status {
# Display firmware version of the specified .tar file
xCAT::SvrUtils::sendmsg("TAR $purpose_value Firmware Product Version\: $version_value", $callback);
}
} elsif (opendir(DIR, $::TAR_FILE_PATH)) {
} elsif (defined $tarfile_path) {
if (!opendir(DIR, $tarfile_path)) {
xCAT::SvrUtils::sendmsg([1,"Can't open directory : $tarfile_path"], $callback);
closedir(DIR);
return 1;
}
my @tar_files = readdir(DIR);
foreach my $file (@tar_files) {
if ($file !~ /.*\.tar$/) {
next;
} else {
my $full_path_file = $::TAR_FILE_PATH."/".$file;
my $full_path_file = $tarfile_path."/".$file;
$full_path_file=~s/\/\//\//g;
my $firmware_version_in_file = `$grep_cmd $version_tag $full_path_file`;
my $purpose_version_in_file = `$grep_cmd $purpose_tag $full_path_file`;
@@ -1978,7 +2004,7 @@ sub parse_command_status {
$return_code = 1;
}
if (!$::UPLOAD_PNOR) {
xCAT::SvrUtils::sendmsg([1,"No PNOR tar file found in $update_file"], $callback);
xCAT::SvrUtils::sendmsg([1,"No Host tar file found in $update_file"], $callback);
$return_code = 1;
}
if ($return_code) {
@@ -2031,9 +2057,10 @@ sub parse_command_status {
$next_status{RFLASH_LIST_REQUEST} = "RFLASH_LIST_RESPONSE";
}
if ($delete) {
# Delete uploaded image from BMC
$next_status{LOGIN_RESPONSE} = "RFLASH_DELETE_IMAGE_REQUEST";
$next_status{RFLASH_DELETE_IMAGE_REQUEST} = "RFLASH_DELETE_IMAGE_RESPONSE";
# Request to delete uploaded image from BMC or Host
# Firsh check if image is allowed to be deleted
$next_status{LOGIN_RESPONSE} = "RFLASH_LIST_REQUEST";
$next_status{RFLASH_LIST_REQUEST} = "RFLASH_DELETE_CHECK_STATE_RESPONSE";
}
if ($upload) {
# Upload specified update file to BMC
@@ -2400,7 +2427,7 @@ sub deal_with_response {
my $log_id = (split ('/', $cur_url))[5];
$error = "Invalid ID=$log_id provided to be resolved. [$::RESPONSE_FORBIDDEN]";
} else{
$error = "$::RESPONSE_FORBIDDEN - Requested endpoint does not exists and may indicate function is not yet supported by OpenBMC firmware.";
$error = "$::RESPONSE_FORBIDDEN - Requested endpoint does not exist or may indicate function is not yet supported by OpenBMC firmware.";
}
# Handle 404
} elsif ($response->status_line eq $::RESPONSE_NOT_FOUND) {
@@ -2411,7 +2438,7 @@ sub deal_with_response {
$error = "Invalid ID provided to delete. Use the -l option to view valid firmware IDs.";
} elsif (($node_info{$node}{cur_status} eq "RSPCONFIG_API_CONFIG_QUERY_RESPONSE") ||
($node_info{$node}{cur_status} eq "RSPCONFIG_API_CONFIG_ATTR_RESPONSE")) {
$error = "$::RESPONSE_NOT_FOUND - Requested endpoint does not exists and may indicate function is not supported on this OpenBMC firmware.";
$error = "$::RESPONSE_NOT_FOUND - Requested endpoint does not exist or may indicate function is not supported on this OpenBMC firmware.";
} else {
$error = "[" . $response->code . "] " . $response_info->{'data'}->{'description'};
}
@@ -2629,32 +2656,42 @@ sub rpower_response {
my $bmc_short_state = (split(/\./, $bmc_state))[-1];
if (defined($bmc_state) and $bmc_state !~ /State.BMC.BMCState.Ready$/) {
if ($node_info{$node}{bmcstate_check_times} > 0) {
$node_info{$node}{bmcstate_check_times}--;
if ($node_info{$node}{wait_start}) {
$node_info{$node}{wait_end} = time();
$node_info{$node}{bmcstate_check_times}--;
if ($node_info{$node}{wait_start}) {
$node_info{$node}{wait_end} = time();
} else {
$node_info{$node}{wait_start} = time();
}
retry_after($node, "RPOWER_BMC_STATUS_REQUEST", $::BMC_CHECK_INTERVAL);
return;
} else {
$node_info{$node}{wait_start} = time();
my $wait_time_X = $node_info{$node}{wait_end} - $node_info{$node}{wait_start};
xCAT::SvrUtils::sendmsg([1, "Error: Sent bmcreboot but state did not change to BMC Ready after waiting $wait_time_X seconds. (State=BMC $bmc_short_state)."], $callback, $node);
$node_info{$node}{cur_status} = "";
$wait_node_num--;
return;
}
retry_after($node, "RPOWER_BMC_STATUS_REQUEST", $::BMC_CHECK_INTERVAL);
return;
} else {
my $wait_time_X = $node_info{$node}{wait_end} - $node_info{$node}{wait_start};
xCAT::SvrUtils::sendmsg([1, "Error: Sent bmcreboot but state did not change to BMC Ready after waiting $wait_time_X seconds. (State=BMC $bmc_short_state)."], $callback, $node);
$node_info{$node}{cur_status} = "";
$wait_node_num--;
return;
}
}
xCAT::SvrUtils::sendmsg("BMC $bmc_short_state", $callback, $node);
}else {
} else {
if ($chassis_state =~ /Off$/) {
# Chassis state is Off, but check if we can detect transition states
if ((defined($::OPENBMC_PWR) and ($::OPENBMC_PWR eq "YES")) and
$host_state =~ /Off$/ and $host_transition_state =~ /On$/) {
xCAT::SvrUtils::sendmsg("$::POWER_STATE_POWERING_ON", $callback, $node);
} else {
xCAT::SvrUtils::sendmsg("$::POWER_STATE_OFF", $callback, $node) if (!$next_status{ $node_info{$node}{cur_status} });
if (defined $status_info{RPOWER_STATUS_RESPONSE}{argv} and $status_info{RPOWER_STATUS_RESPONSE}{argv} =~ /fw_delete$/) {
# We are here just to check the state of the Host to determine if ok to remove active FW
# The state is Off so FW can be removed
$next_status{"RPOWER_STATUS_RESPONSE"} = "RFLASH_DELETE_IMAGE_REQUEST";
$next_status{"RFLASH_DELETE_IMAGE_REQUEST"} = "RFLASH_DELETE_IMAGE_RESPONSE";
$node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} };
gen_send_request($node);
return;
} else {
xCAT::SvrUtils::sendmsg("$::POWER_STATE_OFF", $callback, $node) if (!$next_status{ $node_info{$node}{cur_status} });
}
}
$all_status = $::POWER_STATE_OFF;
} elsif ($chassis_state =~ /On$/) {
@@ -2670,6 +2707,11 @@ sub rpower_response {
$host_transition_state =~ /Off$/ and $chassis_state =~ /On$/) {
xCAT::SvrUtils::sendmsg("$::POWER_STATE_POWERING_OFF", $callback, $node);
} else {
if (defined $status_info{RPOWER_STATUS_RESPONSE}{argv} and $status_info{RPOWER_STATUS_RESPONSE}{argv} =~ /fw_delete$/) {
xCAT::SvrUtils::sendmsg([1, "Deleting currently active firmware on powered on host is not supported"], $callback, $node);
$wait_node_num--;
return;
}
xCAT::SvrUtils::sendmsg("$::POWER_STATE_ON", $callback, $node) if (!$next_status{ $node_info{$node}{cur_status} });
}
$all_status = $::POWER_STATE_ON;
@@ -3345,6 +3387,7 @@ sub rspconfig_response {
my @gateway = ();
my @vlan = ();
my @ntpservers = ();
my $real_ntp_server = 0;
my @nics = keys %nicinfo;
foreach my $nic (@nics) {
my $addon_info = '';
@@ -3354,6 +3397,7 @@ sub rspconfig_response {
if ($nicinfo{$nic}{ntpservers}) {
push @ntpservers, "BMC NTP Servers$addon_info: $nicinfo{$nic}{ntpservers}";
$real_ntp_server = 1;
} else {
push @ntpservers, "BMC NTP Servers$addon_info: None";
}
@@ -3376,6 +3420,11 @@ sub rspconfig_response {
push @output, "BMC Hostname: $hostname";
} elsif ($opt eq "ntpservers") {
push @output, @ntpservers;
if (($real_ntp_server) && ($status_info{RSPCONFIG_SET_RESPONSE}{argv} =~ "NTPServers")) {
# Display a warning if the host in not powered off
# Time on the BMC is not synced while the host is powered on.
push @output, "Warning: time will not be synchronized until the host is powered off.";
}
}
if ($multiple_error and ($opt =~ /^ip$|^ipsrc$|^netmask$|^gateway$|^vlan$/)) {
@@ -3876,7 +3925,7 @@ sub rspconfig_dump_response {
my $dump_id = $status_info{RSPCONFIG_DUMP_CLEAR_RESPONSE}{argv};
xCAT::MsgUtils->message("I", { data => ["[$dump_id] clear"] }, $callback) unless ($next_status{ $node_info{$node}{cur_status} });
} else {
my $error_msg = "Could not clear BMC diagnostics successfully (". $response_info->{'message'} . "), ignoring...";
my $error_msg = "Could not clear BMC diagnostics successfully (". $response_info->{'message'} . ")";
xCAT::MsgUtils->message("W", { data => ["$node: $error_msg"] }, $callback) if ($next_status{ $node_info{$node}{cur_status} });
}
}
@@ -4099,17 +4148,30 @@ sub rvitals_response {
}
if ($node_info{$node}{cur_status} =~ "RVITALS_LEDS_RESPONSE") {
$content_info = "Front . . . . . : Power:$leds{front_power} Fault:$leds{front_fault} Identify:$leds{front_id}";
push (@sorted_output, $content_info);
$content_info = "Rear . . . . . : Power:$leds{rear_power} Fault:$leds{rear_fault} Identify:$leds{rear_id}";
push (@sorted_output, $content_info);
# Fans
if ($leds{fan0} =~ "Off" and $leds{fan1} =~ "Off" and $leds{fan2} eq "Off" and $leds{fan3} eq "Off") {
$content_info = "Front Fans . . : No LEDs On";
} else {
$content_info = "Front Fans . . : fan0:$leds{fan0} fan1:$leds{fan1} fan2:$leds{fan2} fan3:$leds{fan3}";
}
push (@sorted_output, $content_info);
if ($grep_string =~ "compact") {
# Compact output for "rbeacon stat" command
$content_info = "Front:$leds{front_id} Rear:$leds{rear_id}";
push (@sorted_output, $content_info);
} else {
# Full output for "rvitals leds" command
my @front_rear = ("Front", "Rear");
my @led_types = ("Power", "Fault", "Identify");
foreach my $i (@front_rear) {
foreach my $led_type (@led_types) {
my $tmp_type = lc($led_type);
$tmp_type = "id" if ($led_type eq "Identify");
my $key_type = lc($i) . "_" . $tmp_type;
$content_info = "LEDs $i $led_type: $leds{$key_type}";
push (@sorted_output, $content_info);
}
}
# Fans
for (my $i = 0; $i < 4; $i++) {
my $tmp_key = "fan" . $i;
$content_info = "LEDs Fan$i: $leds{$tmp_key}";
push (@sorted_output, $content_info);
}
}
}
# If sorted array has any contents, sort it and print it
@@ -4224,6 +4286,75 @@ sub rflash_response {
}
xCAT::SvrUtils::sendmsg("", $callback, $node); #Separate output in case more than 1 endpoint
}
if ($node_info{$node}{cur_status} eq "RFLASH_DELETE_CHECK_STATE_RESPONSE") {
# Verify selected FW ID is not active. If active, display error message,
# If not active, proceed to delete
my $to_delete_id = (split ('/', $status_info{RFLASH_DELETE_IMAGE_REQUEST}{init_url}))[4];
# Get the functional IDs to determint if active running FW can be deleted
my $functional = get_functional_software_ids($response_info);
if ((!%{$functional}) ||
(!exists($functional->{$to_delete_id}))) {
# Can not figure out if FW functional, attempt to delete anyway.
# Worst case, BMC will not allow FW deletion if we are wrong
# OR
# FW is not active, it can be deleted. Send the request to do the deletion
$next_status{"RFLASH_DELETE_CHECK_STATE_RESPONSE"} = "RFLASH_DELETE_IMAGE_REQUEST";
$next_status{"RFLASH_DELETE_IMAGE_REQUEST"} = "RFLASH_DELETE_IMAGE_RESPONSE";
} else {
foreach my $key_url (keys %{$response_info->{data}}) {
$update_id = (split(/\//, $key_url))[ -1 ];
if ($update_id ne $to_delete_id) {
# Not a match on the id, try next one
next;
}
# Initialize values to Unknown for each loop, incase they are not defined in the BMC
$update_activation = "Unknown";
$update_purpose = "Unknown";
$update_version = "Unknown";
my %content = %{ ${ $response_info->{data} }{$key_url} };
if (defined($content{Version}) and $content{Version}) {
$update_version = $content{Version};
} else {
# Entry has no Version attribute, skip listing it
next;
}
if (defined($content{Purpose}) and $content{Purpose}) {
$update_purpose = (split(/\./, $content{Purpose}))[ -1 ];
}
my $update_priority = -1;
# Just check defined, because priority=0 is a valid value
if (defined($content{Priority})) {
$update_priority = (split(/\./, $content{Priority}))[ -1 ];
}
if ($update_purpose eq "BMC") {
# Active BMC firmware can not be deleted
xCAT::SvrUtils::sendmsg([1, "Deleting currently active BMC firmware is not supported"], $callback, $node);
$wait_node_num--;
return;
} elsif ($update_purpose eq "Host") {
# Active Host firmware can NOT be deleted if host is ON
# Active Host firmware can be deleted if host is OFF
# Send the request to check Host state
$next_status{"RFLASH_DELETE_CHECK_STATE_RESPONSE"} = "RPOWER_STATUS_REQUEST";
$next_status{"RPOWER_STATUS_REQUEST"} = "RPOWER_STATUS_RESPONSE";
# Set special argv to fw_delete if Host is off
$status_info{RPOWER_STATUS_RESPONSE}{argv} = "fw_delete";
last;
} else {
xCAT::SvrUtils::sendmsg([1, "Unable to determine the purpose of the firmware to delete"], $callback, $node);
# Can not figure out if Host or BMC, attempt to delete anyway.
# Worst case, BMC will not allow FW deletion if we are wrong
$next_status{"RFLASH_DELETE_CHECK_STATE_RESPONSE"} = "RFLASH_DELETE_IMAGE_REQUEST";
$next_status{"RFLASH_DELETE_IMAGE_REQUEST"} = "RFLASH_DELETE_IMAGE_RESPONSE";
last;
}
}
}
}
if ($node_info{$node}{cur_status} eq "RFLASH_FILE_UPLOAD_REQUEST") {
#
# Special processing for file upload
+144 -9
View File
@@ -16,7 +16,6 @@ use Getopt::Long;
use xCAT::Usage;
use xCAT::SvrUtils;
use xCAT::OPENBMC;
use xCAT_plugin::openbmc;
#-------------------------------------------------------
@@ -47,6 +46,7 @@ my $reventlog_no_id_resolved_errormsg = "Provide a comma separated list of IDs t
my %node_info = ();
my $callback;
$::VERBOSE = 0;
#-------------------------------------------------------
@@ -92,6 +92,9 @@ sub preprocess_request {
return;
}
if ($::VERBOSE) {
xCAT::SvrUtils::sendmsg("Running command in Python", $callback);
}
my $sn = xCAT::ServiceNodeUtils->get_ServiceNode($noderange, "xcat", "MN");
foreach my $snkey (keys %$sn) {
my $reqcopy = {%$request};
@@ -142,6 +145,17 @@ sub process_request {
xCAT::OPENBMC::wait_agent($pid, $callback);
}
my @rsp_common_options = qw/autoreboot bootmode powersupplyredundancy powerrestorepolicy timesyncmethod
ip netmask gateway hostname vlan ntpservers/;
my @rspconfig_set_options = (@rsp_common_options, qw/admin_passwd/);
my %rsp_set_valid_values = (
autoreboot => "0|1",
bootmode => "regular|safe|setup",
powersupplyredundancy => "disabled|enabled",
powerrestorepolicy => "restore|always_on|always_off",
timesyncmethod => "ntp|manual",
);
my @rspconfig_get_options = (@rsp_common_options, qw/ipsrc sshcfg gard dump/);
#-------------------------------------------------------
=head3 parse_args
@@ -157,24 +171,23 @@ sub parse_args {
my $noderange = shift;
my $subcommand = undef;
my $verbose;
unless (GetOptions(
'V|verbose' => \$verbose,
'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 =~ /rbeacon|rpower|rflash/) {
} elsif (scalar(@ARGV) == 0 and $command =~ /rbeacon|rspconfig|rpower|rflash/) {
return ([ 1, "No option specified for $command" ]);
} else {
$subcommand = $ARGV[0];
}
if ($command eq "rbeacon") {
unless ($subcommand =~ /^on$|^off$/) {
return ([ 1, "Only 'on' or 'off' is supported for OpenBMC managed nodes."]);
unless ($subcommand =~ /^on$|^off$|^stat$/) {
return ([ 1, "Only 'on', 'off' or 'stat' is supported for OpenBMC managed nodes."]);
}
} elsif ($command eq "rflash") {
my ($activate, $check, $delete, $directory, $list, $upload) = (0) x 6;
@@ -218,7 +231,6 @@ sub parse_args {
}
}
if ($directory) {
return ([ 1, "Unsupported command: $command '-d'" ]);
return ([ 1, "More than one directory specified is not supported."]) if ($#ARGV >= 1);
return ([ 1, "Invalid option specified with '-d'."]) if (!@ARGV);
}
@@ -248,10 +260,116 @@ sub parse_args {
return ([ 1, "Unsupported command: $command $subcommand" ]);
}
} elsif ($command eq 'rspconfig') {
xCAT_plugin::openbmc::parse_args('rspconfig', $extrargs, $noderange);
my $num_subcommand = @ARGV;
my ($set, $get);
my $all_subcommand = "";
my %set_net_info = ();
foreach $subcommand (@ARGV) {
my ($key, $value);
if ($subcommand =~ /^(\w+)=(.*)/) {
$key = $1;
$value = $2;
$set = 1;
} else {
$key = $subcommand;
$get = 1;
}
if ($set and $get) {
return ([1, "Can not set and query OpenBMC information at the same time"]);
} elsif ($set and $value eq '' and ($key ne "ntpservers")) {
return ([1, "Invalid parameter for option $key"]);
} elsif ($set and $value ne '' and exists($rsp_set_valid_values{$key})) {
unless ($value =~ /^($rsp_set_valid_values{$key})$/) {
return([1, "Invalid value '$value' for '$key', Valid values: " . join(',', split('\|',$rsp_set_valid_values{$key}))]);
}
}
if (($set and !grep /$key/, @rspconfig_set_options) or
($get and !grep /$key/, @rspconfig_get_options)) {
return ([1, "Unsupported command: $command $subcommand"]);
}
if ($set) {
if ($key =~ /^hostname$|^admin_passwd$|^ntpservers$/ and $num_subcommand > 1) {
return([1, "The option '$key' can not work with other options"]);
} elsif ($key eq "admin_passwd") {
if ($value =~ /^([^,]*),([^,]*)$/) {
if ($1 eq '' or $2 eq '') {
return([1, "Invalid parameter for option $key: $value"]);
}
} else {
return([1, "Invalid parameter for option $key: $value"]);
}
} elsif ($key eq "netmask") {
if (!xCAT::NetworkUtils->isIpaddr($value)) {
return ([ 1, "Invalid parameter for option $key: $value" ]);
}
$set_net_info{"netmask"} = 1;
} elsif ($key eq "gateway") {
if ($value ne "0.0.0.0" and !xCAT::NetworkUtils->isIpaddr($value)) {
return ([ 1, "Invalid parameter for option $key: $value" ]);
}
$set_net_info{"gateway"} = 1;
} elsif ($key eq "vlan") {
$set_net_info{"vlan"} = 1;
} elsif ($key eq "ip") {
if ($value ne "dhcp") {
if (@$noderange > 1) {
return ([ 1, "Can not configure more than 1 nodes' ip at the same time" ]);
} elsif (!xCAT::NetworkUtils->isIpaddr($value)) {
return ([ 1, "Invalid parameter for option $key: $value" ]);
}
$set_net_info{"ip"} = 1;
} elsif($num_subcommand > 1) {
return ([ 1, "Setting ip=dhcp must be issued without other options." ]);
}
}
} else {
if ($key eq "sshcfg" and $num_subcommand > 1) {
return ([ 1, "Configure sshcfg must be issued without other options." ]);
} elsif ($key eq "gard") {
if ($num_subcommand > 2) {
return ([ 1, "Clear GARD cannot be issued with other options." ]);
} elsif (!defined($ARGV[1]) or $ARGV[1] !~ /^-c$|^--clear$/) {
return ([ 1, "Invalid parameter for $command $key" ]);
}
return;
} elsif ($key eq "dump") {
my $dump_option = "";
$dump_option = $ARGV[1] if (defined $ARGV[1]);
if ($dump_option =~ /^-d$|^--download$/) {
return ([ 1, "No dump file ID specified" ]) unless ($ARGV[2]);
return ([ 1, "Invalid parameter for $command $key $dump_option $ARGV[2]" ]) if ($ARGV[2] !~ /^\d*$/ and $ARGV[2] ne "all");
return ([ 1, "dump $dump_option must be issued without other options." ]) if ($num_subcommand > 3);
} elsif ($dump_option =~ /^-c$|^--clear$/) {
return ([ 1, "No dump file ID specified. To clear all, specify 'all'." ]) unless ($ARGV[2]);
return ([ 1, "Invalid parameter for $command $key $dump_option $ARGV[2]" ]) if ($ARGV[2] !~ /^\d*$/ and $ARGV[2] ne "all");
return ([ 1, "dump $dump_option must be issued without other options." ]) if ($num_subcommand > 3);
} elsif ($dump_option =~ /^-l$|^--list$|^-g$|^--generate$/) {
return ([ 1, "dump $dump_option must be issued without other options." ]) if ($num_subcommand > 2);
} elsif ($dump_option) {
return ([ 1, "Invalid parameter for $command $dump_option" ]);
}
return;
}
}
}
if ($set and scalar(keys %set_net_info) > 0) {
if (!exists($set_net_info{"ip"}) or !exists($set_net_info{"netmask"}) or !exists($set_net_info{"gateway"})) {
if (exists($set_net_info{"vlan"})) {
return ([ 1, "VLAN must be configured with IP, netmask and gateway" ]);
} else {
return ([ 1, "IP, netmask and gateway must be configured together." ]);
}
}
}
} elsif ($command eq "reventlog") {
$subcommand = "all" if (!defined($ARGV[0]));
if ($subcommand =~ /^resolved=(.*)/) {
if (scalar(@ARGV) >= 2) {
if ($ARGV[1] =~ /^-s$/) {
return ([ 1, "The -s option is not supported for OpenBMC." ]);
}
return ([ 1, "Only one option is supported at the same time for $command" ]);
} elsif ($subcommand =~ /^resolved=(.*)/) {
my $value = $1;
if (not $value) {
return ([ 1, "$usage_errormsg $reventlog_no_id_resolved_errormsg" ]);
@@ -390,6 +508,23 @@ sub refactor_args {
unshift @$extrargs, "list";
}
}
if ($command eq "rflash") {
my @new_args = ('') x 4;
foreach my $tmp (@$extrargs) {
if ($tmp =~ /^-/) {
if ($tmp !~ /^-V$|^--verbose$/) {
$new_args[0] = $tmp;
} elsif ($tmp =~ /^--no-host-reboot$/) {
$new_args[2] = $tmp;
} else {
$new_args[3] = $tmp;
}
} else {
$new_args[1] = $tmp;
}
}
@$extrargs = grep(/.+/, @new_args);
}
return 0;
}
+12
View File
@@ -531,6 +531,18 @@ sub process_request {
# before packaging the image
system("umount $rootimg_dir/proc");
#put the image name, uuid and timestamp into diskless image when it is packed.
$callback->({ data => ["add image info to xcatinfo file"] });
`echo IMAGENAME="'$imagename'" > $rootimg_dir/opt/xcat/xcatinfo`;
my $uuid = `uuidgen`;
chomp $uuid;
`echo IMAGEUUID="'$uuid'" >> $rootimg_dir/opt/xcat/xcatinfo`;
my $timestamp = `date`;
chomp $timestamp;
`echo TIMESTAMP="'$timestamp'" >> $rootimg_dir/opt/xcat/xcatinfo`;
my $verb = "Packing";
my $temppath;
@@ -306,6 +306,37 @@ sub preprocess_updatenode
return;
}
# get server names as known by the nodes
my %servernodes =
%{ xCAT::InstUtils->get_server_nodes($callback, $request->{node},1) };
# it's possible that the nodes could have diff server names
# do all the nodes for a particular server at once
my @invalidnodes;
if($servernodes{undef}){
push @invalidnodes,@{$servernodes{undef}};
}
if ($servernodes{""}){
push @invalidnodes,@{$servernodes{""}};
}
if (@invalidnodes){
my %allnodes=map {$_,1} @{$request->{node}};
foreach my $node (@invalidnodes){
xCAT::MsgUtils->report_node_error($callback,$node,"Could not determine or resolve xcatmaster for $node. Will skip this node.");
delete $allnodes{$node};
}
$request->{node}=[];
push @{$request->{node}}, map $_ ,keys %allnodes;
}
unless (scalar @{$request->{node}}){
return;
}
# preprocess generate mypostscripts files (-g) for hierarchy
# if no sharedtftp then we need to broadcast this updatenode -g to all service nodes inorder
# to be able to support service node pools
@@ -1534,6 +1565,7 @@ sub updatenoderunps
if ((!defined($snkey)) or ($snkey eq "")) { # if we could not find the xcatmaster
my $rsp = {};
$rsp->{errorcode}->[0]=1;
$rsp->{error}->[0] = "Could not find xcatmaster for @{$servernodes{$snkey}}. Will skip this node. ";
$callback->($rsp);
next;
+6
View File
@@ -645,6 +645,12 @@ sub process_servicenodes_xdcp
if (grep(/^--nodestatus$/, @$args)) {
push(@{ $addreq->{arg} }, "--nodestatus"); # return nodestatus
}
if (defined($req->{username}) && ($req->{username}->[0] ne "root")) {
# Using `root` when sync temporary files to `site.SNsyncfiledir` (default: /var/xcat/syncfiles)
push(@{ $addreq->{arg} }, "-l");
push(@{ $addreq->{arg} }, "root");
}
push(@{ $addreq->{arg} }, "-v");
push(@{ $addreq->{arg} }, "-s");
push(@{ $addreq->{arg} }, "-F");
+1
View File
@@ -356,6 +356,7 @@ sub runpgsqlcmd
if ($? > 0) # error
{
$rc = $? >> 8;
$cmd = "PGPASSWORD=xxxxxx $psql -d $dbname -h $hostname -U $admin -f $file ";
xCAT::MsgUtils->message("SE",
"The command $cmd had errors. Return=$rc");
}
+104 -69
View File
@@ -332,6 +332,7 @@ sub do_installm_service {
my $socket;
my $installpidfile;
my $retry = 1;
$SIG{TERM} = $SIG{INT} = 'DEFAULT';
$SIG{USR2} = sub {
if ($socket) { # do not mess with pid file except when we still have the socket.
unlink("/var/run/xcat/installservice.pid"); close($socket); $quit = 1;
@@ -385,80 +386,91 @@ sub do_installm_service {
open($installpidfile, ">", "/var/run/xcat/installservice.pid"); # if here, everyone else has unlinked installservicepid or doesn't care
print $installpidfile $$;
close($installpidfile);
xCAT::MsgUtils->trace(0, "I", "xcatd: install monitor process $$ start");
until ($quit) {
$SIG{ALRM} = sub { xCAT::MsgUtils->message("S", "XCATTIMEOUT"); die; };
$SIG{ALRM} = sub { die "XCATTIMEOUT"; };
my $conn;
next unless $conn = $socket->accept;
my $conn_peer_addr;
my $node;
my $validclient = 0;
# check if a rescanplugins request has come in
my @rescans;
if (@rescans = $rescanrselect->can_read(0)) {
foreach my $rrequest (@rescans) {
my $rescan_request = fd_retrieve($rrequest);
if ($$rescan_request =~ /rescanplugins/) {
scan_plugins('', '1');
} else {
print "ignoring unrecognized pipe request received by install monitor from ssl listener: $rescan_request \n";
next unless $conn = $socket->accept;
eval {
# check if a rescanplugins request has come in
my @rescans;
if (@rescans = $rescanrselect->can_read(0)) {
foreach my $rrequest (@rescans) {
my $rescan_request = fd_retrieve($rrequest);
if ($$rescan_request =~ /rescanplugins/) {
scan_plugins('', '1');
} else {
xCAT::MsgUtils->trace(0, "W", "xcatd: ignoring unrecognized pipe request received by install monitor from ssl listener: $rescan_request.");
}
}
}
}
my $conn_peer_addr = $conn->peerhost();
xCAT::MsgUtils->trace(0, "I", "xcatd received a connection request from $conn_peer_addr");
$conn_peer_addr = $conn->peerhost();
xCAT::MsgUtils->trace(0, "I", "xcatd: install monitor received a connection request from $conn_peer_addr");
my $client_name;
my $client_aliases;
my @clients;
if ($inet6support) {
($client_name, $client_aliases) = gethostbyaddr($conn->peeraddr, AF_INET6);
unless ($client_name) { ($client_name, $client_aliases) = gethostbyaddr($conn->peeraddr, AF_INET); }
} else {
($client_name, $client_aliases) = gethostbyaddr($conn->peeraddr, AF_INET);
}
unless ($client_name) {
my $addrfamily=sockaddr_family(getpeername($conn));
my $myaddr=Socket::inet_ntop($addrfamily,$conn->peeraddr);
xCAT::MsgUtils->message("SE", "xcatd received a connection request from unknown host with ip address $myaddr, please check whether the reverse name resolution works correctly. The connection request will be ignored");
#print "xcatd received a connection request from unknown host with ip address $myaddr, please check whether the reverse name resolution works correctly. The connection request will be ignored\n";
close($conn);
next;
}
$clients[0] = $client_name;
if ($client_aliases) {
push @clients, split(/\s+/, $client_aliases);
}
my $validclient = 0;
my $node;
my $domain;
foreach my $client (@clients) {
my @ndn = ($client);
my $nd = xCAT::NetworkUtils->getNodeDomains(\@ndn);
my %nodedomains = %{$nd};
$domain = $nodedomains{$client};
$client =~ s/\..*//;
if ($domain) {
$client =~ s/\.$domain//;
my $client_name;
my $client_aliases;
my @clients;
if ($inet6support) {
($client_name, $client_aliases) = gethostbyaddr($conn->peeraddr, AF_INET6);
unless ($client_name) {
($client_name, $client_aliases) = gethostbyaddr($conn->peeraddr, AF_INET);
}
} else {
($client_name, $client_aliases) = gethostbyaddr($conn->peeraddr, AF_INET);
}
unless ($client_name) {
die "XCATUNKOWNCLIENT"; # use die instead of next to avoid 'Exiting eval via next' message
}
$clients[0] = $client_name;
if ($client_aliases) {
push @clients, split(/\s+/, $client_aliases);
}
my $domain;
my %handled_client=();
foreach my $client (@clients) {
next if (exists $handled_client{$client});
$handled_client{$client}=1;
my @ndn = ($client);
my $nd = xCAT::NetworkUtils->getNodeDomains(\@ndn);
my %nodedomains = %{$nd};
$domain = $nodedomains{$client};
$client =~ s/\..*//;
}
if ($domain) {
$client =~ s/\.$domain//;
} else {
$client =~ s/\..*//;
}
# ensure this is coming from a node IP at least
($node) = noderange($client);
if ($node) { # Means the source isn't valid
$validclient = 1;
last;
# ensure this is coming from a node IP at least
($node) = noderange($client);
if ($node) { # Means the source isn't valid
#$validclient = 1;
xCAT::MsgUtils->trace(0, "I", "xcatd: $conn_peer_addr is matched with node $node");
last;
}
}
unless ($node) {
xCAT::MsgUtils->trace(0, "E", "xcatd: received a connection request from $conn_peer_addr($client_name), which can not be found in xCAT nodelist table. The connection request will be ignored");
}
};
if ($@) {
$node = undef;
if ($@ =~ /XCATUNKOWNCLIENT/) {
xCAT::MsgUtils->trace(0, "E", "xcatd: received a connection request from unknown host with ip address $conn_peer_addr, please check whether the reverse name resolution works correctly. The connection request will be ignored");
} else {
xCAT::MsgUtils->message("SE", "xcatd received a connection request from $client, which can not be found in xCAT nodelist table. The connection request will be ignored");
#print "xcatd received a connection request from $client, which can not be found in xCAT nodelist table. The connection request will be ignored\n";
xCAT::MsgUtils->trace(0, "E", "xcatd: possible BUG encountered by xCAT install monitor service: " . $@);
}
}
unless ($validclient) {
unless ($node) {
close($conn);
sleep 0.01;
next;
}
my $tftpdir = xCAT::TableUtils->getTftpDir();
@@ -469,6 +481,8 @@ sub do_installm_service {
alarm(0);
print $conn "done\n";
$text =~ s/\r//g;
# Clear IP-Name cache, Workaround (#4913) for IP changed cases.
xCAT::NetworkUtils->clearcache();
if ($text =~ /next/) {
my %request = (
command => ['nodeset'],
@@ -481,7 +495,6 @@ sub do_installm_service {
#unless ($pid) { # fork off the nodeset and potential slowness
xCAT::MsgUtils->trace(0, "I", "xcatd: triggering \'nodeset $node next\'...");
plugin_command(\%request, undef, \&build_response);
#exit(0);
#}
close($conn);
@@ -494,7 +507,7 @@ sub do_installm_service {
node => [$node],
arg => ["$newstat"],
);
xCAT::MsgUtils->trace(0, "I", "xcatd: triggering \'updatenodestat $node $newstat\'...");
# node should be blocked, race condition may occur otherwise
#my $pid=xCAT::Utils->xfork();
#unless ($pid) { # fork off the nodeset and potential slowness
@@ -505,14 +518,17 @@ sub do_installm_service {
}
close($conn);
} elsif ($text =~ /^unlocktftpdir/) { # TODO: only nodes in install state should be allowed
xCAT::MsgUtils->trace(0, "I", "xcatd: unlock tftpdir for $node...");
mkpath("$tftpdir/xcat/$node");
chmod 01777, "$tftpdir/xcat/$node";
chmod 0666, glob("$tftpdir/xcat/$node/*");
close($conn);
} elsif ($text =~ /locktftpdir/) {
xCAT::MsgUtils->trace(0, "I", "xcatd: lock tftpdir for $node...");
chmod 0755, "$tftpdir/xcat/$node";
chmod 0644, glob("$tftpdir/xcat/$node/*");
} elsif ($text =~ /^getpostscript/) {
xCAT::MsgUtils->trace(0, "I", "xcatd: handle getpostscript requesting from $node...");
my $reply = plugin_command({ command => ['getpostscript'], _xcat_clienthost => [$node] }, undef, \&build_response);
foreach (@{ $reply->{data} }) {
print $conn $_;
@@ -520,10 +536,12 @@ sub do_installm_service {
print $conn "#END OF SCRIPT\n";
close($conn);
} elsif ($text =~ /^syncfiles/) {
xCAT::MsgUtils->trace(0, "I", "xcatd: handle syncfiles requesting from $node...");
plugin_command({ command => ['syncfiles'], _xcat_clienthost => [$node] }, undef, \&build_response);
print $conn "syncfiles done\n";
close($conn);
} elsif ($text =~ /^setiscsiparms/) {
xCAT::MsgUtils->trace(0, "I", "xcatd: handle setiscsiparms requesting from $node...");
$text =~ s/^setiscsiparms\s+//;
my $kname;
my $iname;
@@ -559,31 +577,44 @@ sub do_installm_service {
arg => ["$text"],
);
xCAT::MsgUtils->trace(0, "I", "xcatd: triggering \'updatenodeappstat $node $text\'...");
plugin_command(\%request, undef, \&build_response);
close($conn);
} elsif ($text =~ /basecustremv/) {
$text =~ s/basecustremv //;
chomp $text;
xCAT::MsgUtils->trace(0, "I", "xcatd: handle basecustremv requesting for $text...");
# remove the BASECUST_REMOVAL line from /tftpboot/hostname.info file
my $myfile = "/tftpboot/$text" . ".info";
`/usr/bin/cat $myfile | /usr/bin/sed "/BASECUST_REMOVAL/d">/tmp/$text.nimtmp`;
`/usr/bin/mv /tmp/$text.nimtmp $myfile`;
close($conn);
} elsif ($text =~ /installmonitor/) {
xCAT::MsgUtils->trace(0, "I", "xcatd: handle installmonitor requesting from $text...");
close($conn);
} else {
sleep 0.01;
chomp $text;
xCAT::MsgUtils->trace(0, "E", "xcatd: install monitor does not support \'$text\', the connection request from $conn_peer_addr will be ignored.");
close($conn); #close it to avoid the DDOS attack
alarm(2);
next;
}
xCAT::MsgUtils->trace(0, "I", "xcatd: finish a connection request for $node from $conn_peer_addr");
alarm(2);
}
alarm(0);
};
if ($@) {
if ($@ =~ /XCATTIMEOUT/) {
xCAT::MsgUtils->message("S", "xcatd: install monitor timed out talking to $node");
xCAT::MsgUtils->trace(0, "W", "xcatd: install monitor timed out talking to $node($conn_peer_addr)");
} else {
xCAT::MsgUtils->message("S", "xcatd: possible BUG encountered by xCAT install monitor service: " . $@);
xCAT::MsgUtils->trace(0, "E", "xcatd: possible BUG encountered by xCAT install monitor service: " . $@);
close($conn);
}
}
}
if (open($installpidfile, "<", "/var/run/xcat/installservice.pid")) {
my $pid = <$installpidfile>;
@@ -634,6 +665,7 @@ sub do_discovery_process {
populate_vpd_hash();
populate_mp_hash();
xCAT::MsgUtils->trace(0, "I", "xcatd: Discovery worker process $$ start");
while (not $quit) {
my $msg = fd_retrieve($broker);
if ((time() - $vintage) > 15) {
@@ -745,6 +777,8 @@ sub do_udp_service { # This function opens up a UDP port
open($udppidfile, ">", "/var/run/xcat/udpservice.pid"); # if here, everyone else has unlinked udpservicepid or doesn't care
print $udppidfile $$;
close($udppidfile);
xCAT::MsgUtils->trace(0, "I", "xcatd: UDP listener process $$ start");
$select->add($socket);
$udpcontext->{socket} = $socket;
$select->add($sslctl);
@@ -945,7 +979,8 @@ unless (xCAT::Utils->isLinux()) { # messes up the output of the service cmd on l
};
}
if ($@) {
print "ERROR: $@";
#print "ERROR: $@";
xCAT::MsgUtils->trace(0, "E", "xcatd: possible BUG encountered: " . $@);
xexit;
}
unless ($foreground) {
@@ -1229,7 +1264,7 @@ unless ($cmdlog_svrpid) {
open($cmdlogpidfile, ">$cmdlogservicefile");
print $cmdlogpidfile $$;
close($cmdlogpidfile);
xCAT::MsgUtils->trace(0, "I", "xcatd: command log process $$ start");
xCAT::MsgUtils->trace(0, "I", "xcatd: Command log writer process $$ start");
my $cmdlog_logfile_path = dirname($cmdlog_logfile);
mkpath("$cmdlog_logfile_path") unless (-d "$cmdlog_logfile_path");
@@ -1411,7 +1446,7 @@ until ($quit) {
if (@pendingconnections) {
while ($listenwatcher->can_read(0)) { # grab everything we can, but don't spend any time waiting for more
$tconn = $listener->accept;
unless ($tconn) { next; }
unless ($tconn) { sleep 0.01; next; } # increase max open file number might cause dead-loop here, sleep for a while
push @pendingconnections, $tconn;
}
} else {
+1 -1
View File
@@ -239,7 +239,7 @@ sub snap_it {
"ls $installdir", "/usr/bin/crontab -l",
"find /tftpboot -size -32k", "ls -lR $xcatroot",
"arp -a", "ps -edlf", "ps -aux", "ulimit -a", "df -k",
"cat /etc/issue", "lsxcatd -a", "cat /proc/meminfo", "cat /proc/cpuinfo");
"cat /etc/issue", "lsxcatd -a", "cat /proc/meminfo", "cat /proc/cpuinfo", "journalctl -b --no-pager -u xcatd");
}
foreach my $item (@Commands_array) {
$Command = $item;
@@ -0,0 +1,9 @@
/var/log/consoles/*.log
/var/log/goconserver/server.log
{
missingok
sharedscripts
postrotate
kill -HUP `systemctl show -p MainPID goconserver.service 2> /dev/null |awk -F= '{print $2}'` 2> /dev/null || true
endscript
}
@@ -8,13 +8,13 @@
./usr/lib64/perl5/Encode/KR*
./lib/kbd/keymaps/i386*
./lib/kbd/keymaps/mac*
./lib/kdb/keymaps/include*
./lib/kbd/keymaps/include*
./usr/local/include*
./usr/local/share/man*
./usr/share/man*
./usr/share/cracklib*
./usr/share/doc*
./usr/share/doc/packages/cyrus-sasl/doc*
#./usr/share/doc/packages/cyrus-sasl/doc*
./usr/share/gnome*
./usr/share/i18n*
+./usr/share/i18n/en_US*
@@ -25,7 +25,6 @@
+./usr/share/locale/locale.alias
+./usr/lib/locale/locale-archive
+./usr/lib/locale/en*
./usr/share/man*
./usr/share/omf*
./usr/share/vim/site/doc*
./usr/share/vim/vim74/doc*
@@ -16,7 +16,7 @@ install() {
local _installs
if type -P rsyslogd >/dev/null; then
_installs="rsyslogd"
inst_libdir_file rsyslog/lmnet.so rsyslog/imklog.so rsyslog/imuxsock.so
inst_libdir_file rsyslog/lmnet.so rsyslog/imklog.so rsyslog/imuxsock.so rsyslog/imjournal.so
elif type -P syslogd >/dev/null; then
_installs="syslogd"
elif type -P syslog-ng >/dev/null; then
@@ -21,7 +21,12 @@ rsyslog_config() {
# echo "${filter} @${server}"
# done
# In dracut 33, default rsyslogd configuration does not use journald. Then when
# rsyslog in debug mode, it causes `/dev/log` is not available after switch_root (#4929)
echo "\$ModLoad imjournal"
echo "\$OmitLocalLogging on"
echo "\$IMJournalStateFile imjournal.state"
if [ -n "$filters" ];then
confline="${filters}";
else
+16 -2
View File
@@ -85,7 +85,7 @@ sub majversion {
my $version = shift;
my $majorrel;
if ($osver =~ /^\D*(\d*)[.\d]*$/) {
if ($osver =~ /^\D*(\d*)[.\d]*.*$/) {
$majorrel = $1;
}
@@ -141,6 +141,9 @@ sub umount_chroot {
#only remove the /dev in rootimg directory if it is not a mount point
system("findmnt $rootimage_dir/dev/ >/dev/null 2>&1 || rm -rf $rootimage_dir/dev/*");
}
#rpm complains "Failed to initialize NSS library" when /dev/urandom does not exist, leave /dev/urandom
use_devurandom();
}
#check whether a dir is NFS mounted
@@ -375,7 +378,6 @@ unless ($onlyinitrd) {
mount_chroot($rootimg_dir);
my %pkg_hash = imgutils::get_package_names($pkglist);
my $index = 1;
@@ -2355,6 +2357,18 @@ sub use_devnull {
}
}
#in rhels7.5, the /dev/urandom does not exist in rootimg directory
#which cause any rpm command fail with `error: Failed to initialize NSS library`
#create urandom in genimage to avoid the error
sub use_devurandom {
if (-e "$rootimg_dir/dev/urandom" and !-c "$rootimg_dir/dev/urandom") {
system("rm -f $rootimg_dir/dev/urandom");
}
if (!-e "$rootimg_dir/dev/urandom") {
system("mknod -m444 $rootimg_dir/dev/urandom c 1 9");
}
}
# Hack uname functions to match what's installed in the rootimg
# instead of what's running on the management node.
# Needed for some RPMs, especially kernel modules via DKMS.
+2 -2
View File
@@ -61,8 +61,8 @@ for i in $*; do
# in the merge file and create a new backup
# first get a list of duplicate lines to remove
# based on only username: the first field in the file
cut -d: -f1 $filebackup > $filebackup.userlist
cut -d: -f1 $mergefile > $mergefile.userlist
cut -d: -f1 $filebackup > $filebackup.userlist
cut -d: -f1 $mergefile > $mergefile.userlist
comm -12 <(sort $filebackup.userlist | uniq) <(sort $mergefile.userlist | uniq) > $filebackup.remove
# now if there is a remove file, use it to remove the dup lines in backup
+162 -28
View File
@@ -2,18 +2,22 @@
#
# go-xcat - Install xCAT automatically.
#
# Version 1.0.21
# Version 1.0.27
#
# Copyright (C) 2016 International Business Machines
# Copyright (C) 2016, 2017, 2018 International Business Machines
# Eclipse Public License, Version 1.0 (EPL-1.0)
# <http://www.eclipse.org/legal/epl-v10.html>
#
# 2016-06-16 GONG Jie <gongjie@linux.vnet.ibm.com>
# - created
# - Draft
# 2016-06-20 GONG Jie <gongjie@linux.vnet.ibm.com>
# - released to the field
# - Released to the field
# 2016-09-20 GONG Jie <gongjie@linux.vnet.ibm.com>
# - bug fix
# - Bug fix
# 2018-03-28 GONG Jie <gongjie@linux.vnet.ibm.com>
# - Use curl when it is available. Otherwise fall back to use wget
# - Improved tarball file extension handling
# - Disable xCAT-core.repo and xCAT-dep.repo if they exist
#
function usage()
@@ -34,8 +38,11 @@ function usage()
repository
--xcat-dep=[URL] use a different URL or path for the xcat-dep
repository
-x, --xcat-version=[VERSION] specify the version of xCAT; cannot use with
--xcat-core
-x, --xcat-version=[VERSION] specify the version of xCAT; imply the subdirectory
of corresponding xCAT version under
http://xcat.org/files/xcat/repos/yum/ or
http://xcat.org/files/xcat/repos/apt/
cannot use with --xcat-core
-y, --yes answer yes for all questions
Actions:
@@ -89,7 +96,7 @@ function verbose_usage()
-h, --help display a simply version of help and exit
--long-help display this help and exit
EOF
println 9
println 12
while read -r ; do echo "${REPLY}" ; done <<-EOF
check check the version of the installed packages
of xCAT and packages in the repository
@@ -98,7 +105,7 @@ function verbose_usage()
while read -r ; do echo "${REPLY}" ; done <<-EOF
smoke-test preform basic tests of the xCAT installation
EOF
println 11
println 10
while read -r ; do echo "${REPLY}" ; done <<-EOF
${script} --xcat-core=/path/to/xcat-core.repo install
${script} --xcat-core=/path/to/xcat-core install
@@ -632,7 +639,112 @@ function get_package_list()
function_dispatch "${FUNCNAME}" "$@"
}
function download_file()
function download_file_curl()
{
local script="${0##*/}"
local version="$(version)"
local user_agent="${script}/${version} (${GO_XCAT_OS}; ${GO_XCAT_ARCH}; ${GO_XCAT_LINUX_DISTRO} ${GO_XCAT_LINUX_VERSION})"
type curl >/dev/null 2>&1 || return 255
local url="$1"
local local_file="$2"
local log_file="${TMP_DIR}/curl.log.${RANDOM}"
local -i rc=0
curl -A "${user_agent}" "${url}" -f -o "${local_file}" -S -s >"${log_file}" 2>&1
rc="$?"
if [[ "${rc}" -ne "0" ]]
then
while read -r ; do echo "${REPLY}" ; done <"${log_file}"
echo -n "${script}: \`curl' exited with an error: (exit code ${rc}, "
case "${rc}" in
1) echo -n "unsupported protocol" ;;
2) echo -n "failed to initialize" ;;
3) echo -n "URL malformed" ;;
4) echo -n "you probably need another build of libcurl!" ;;
5) echo -n "couldn't resolve proxy" ;;
6) echo -n "couldn't resolve host" ;;
7) echo -n "failed to connect to host" ;;
8) echo -n "weird server reply" ;;
9) echo -n "FTP access denied" ;;
10) echo -n "FTP accept failed" ;;
11) echo -n "FTP weird PASS reply" ;;
12) echo -n "During an active FTP session while waiting for the server to connect back to curl, the timeout expired." ;;
13) echo -n "FTP weird PASV reply" ;;
14) echo -n "FTP weird 227 format" ;;
15) echo -n "FTP can't get host" ;;
16) echo -n "HTTP/2 error" ;;
17) echo -n "FTP couldn't set binary" ;;
18) echo -n "Partial file" ;;
19) echo -n "FTP couldn't download/access the given file" ;;
21) echo -n "FTP quote error" ;;
22) echo -n "HTTP page not retrieved" ;;
23) echo -n "write error" ;;
25) echo -n "FTP couldn't STOR file" ;;
26) echo -n "read error" ;;
27) echo -n "out of memory" ;;
28) echo -n "operation timeout" ;;
30) echo -n "FTP PORT failed" ;;
31) echo -n "FTP couldn't use REST" ;;
33) echo -n "HTTP range error" ;;
34) echo -n "HTTP post error" ;;
35) echo -n "SSL connect error" ;;
36) echo -n "bad download resume" ;;
37) echo -n "FILE couldn't read file" ;;
38) echo -n "LDAP cannot bind" ;;
39) echo -n "LDAP search failed." ;;
41) echo -n "function not found" ;;
42) echo -n "aborted by callback" ;;
43) echo -n "internal error" ;;
45) echo -n "interface error" ;;
47) echo -n "too many redirects" ;;
48) echo -n "unknown option specified to libcurl" ;;
49) echo -n "malformed telnet option" ;;
51) echo -n "the peer's SSL certificate or SSH MD5 fingerprint was not OK" ;;
52) echo -n "the server didn't reply anything, which here is considered an error" ;;
53) echo -n "SSL crypto engine not found" ;;
54) echo -n "cannot set SSL crypto engine as default" ;;
55) echo -n "failed sending network data" ;;
56) echo -n "failure in receiving network data" ;;
58) echo -n "problem with the local certificate" ;;
59) echo -n "couldn't use specified SSL cipher" ;;
60) echo -n "peer certificate cannot be authenticated with known CA certificates" ;;
61) echo -n "unrecognized transfer encoding." ;;
62) echo -n "invalid LDAP URL" ;;
63) echo -n "maximum file size exceeded" ;;
64) echo -n "requested FTP SSL level failed" ;;
65) echo -n "sending the data requires a rewind that failed" ;;
66) echo -n "failed to initialise SSL Engine" ;;
67) echo -n "the user name, password, or similar was not accepted and curl failed to log in" ;;
68) echo -n "file not found on TFTP server" ;;
69) echo -n "permission problem on TFTP server" ;;
70) echo -n "out of disk space on TFTP server" ;;
71) echo -n "illegal TFTP operation" ;;
72) echo -n "unknown TFTP transfer ID" ;;
73) echo -n "file already exists (TFTP)" ;;
74) echo -n "no such user (TFTP)" ;;
75) echo -n "character conversion failed" ;;
76) echo -n "character conversion functions required" ;;
77) echo -n "problem with reading the SSL CA cert" ;;
78) echo -n "the resource referenced in the URL does not exist" ;;
79) echo -n "an unspecified error occurred during the SSH session" ;;
80) echo -n "failed to shut down the SSL connection" ;;
82) echo -n "could not load CRL file, missing or wrong format" ;;
83) echo -n "issuer check failed" ;;
84) echo -n "the FTP PRET command failed" ;;
85) echo -n "RTSP: mismatch of CSeq numbers" ;;
86) echo -n "RTSP: mismatch of Session Identifiers" ;;
87) echo -n "unable to parse FTP file list" ;;
88) echo -n "FTP chunk callback reported error" ;;
89) echo -n "no connection available, the session will be queued" ;;
90) echo -n "SSL public key does not matched pinned public key" ;;
*) echo -n "unknown error" ;;
esac
echo ")"
echo " ... while downloading \`${url}'"
fi >&2
[[ "${rc}" -eq "0" ]]
}
function download_file_wget()
{
local script="${0##*/}"
local version="$(version)"
@@ -665,6 +777,11 @@ function download_file()
[[ "${rc}" -eq "0" ]]
}
function download_file()
{
function_dispatch "${FUNCNAME}" "$@"
}
# $1 repo file
# $2 repo id
function add_repo_by_file_yum()
@@ -757,8 +874,8 @@ function extract_archive()
warn_if_bad "${ret}" "Failed to create directory \`${install_path}'" ||
return 1
case "${archive##*.}" in
"Z")
case "${archive##*/}" in
*".tar.Z")
check_executes uncompress tar grep || return 1
uncompress -c "${archive}" | tar -t -f - | grep -v "^${repo_id}/"
[[ "${PIPESTATUS[0]}" -eq 0 && "${PIPESTATUS[1]}" -eq 0 &&
@@ -767,7 +884,7 @@ function extract_archive()
rm -rf "${install_path}/${repo_id}"
uncompress -c "${archive}" | ( cd "${install_path}" && tar -x -f - )
;;
"tz"|"tgz"|"gz")
*".tz"|*".tgz"|*".tar.gz")
check_executes gzip tar grep || return 1
gzip -d -c "${archive}" | tar -t -f - | grep -v "^${repo_id}/"
[[ "${PIPESTATUS[0]}" -eq 0 && "${PIPESTATUS[1]}" -eq 0 &&
@@ -776,7 +893,7 @@ function extract_archive()
rm -rf "${install_path}/${repo_id}"
gzip -d -c "${archive}" | ( cd "${install_path}" && tar -x -f - )
;;
"tbz"|"tbz2"|"bz"|"bz2")
*".tbz"|*".tbz2"|*".tar.bz"|*".tar.bz2")
check_executes bzip2 tar grep || return 1
bzip2 -d -c "${archive}" | tar -t -f - | grep -v "^${repo_id}/"
[[ "${PIPESTATUS[0]}" -eq 0 && "${PIPESTATUS[1]}" -eq 0 &&
@@ -785,7 +902,7 @@ function extract_archive()
rm -rf "${install_path}/${repo_id}"
bzip2 -d -c "${archive}" | ( cd "${install_path}" && tar -x -f - )
;;
"txz"|"xz")
*".txz"|*".tar.xz")
check_executes xz tar grep || return 1
xz -d -c "${archive}" | tar -t -f - | grep -v "^${repo_id}/"
[[ "${PIPESTATUS[0]}" -eq 0 && "${PIPESTATUS[1]}" -eq 0 &&
@@ -794,7 +911,7 @@ function extract_archive()
rm -rf "${install_path}/${repo_id}"
xz -d -c "${archive}" | ( cd "${install_path}" && tar -x -f - )
;;
"tar")
*".tar")
check_executes tar grep || return 1
tar -t -f "${archive}" | grep -v "^${repo_id}/"
[[ "${PIPESTATUS[0]}" -eq 0 && "${PIPESTATUS[1]}" -eq 1 ]]
@@ -823,8 +940,8 @@ function add_repo_by_url_yum_or_zypper()
local install_path="${GO_XCAT_DEFAULT_INSTALL_PATH}"
case "${url%%://*}" in
"ftp"|"http"|"https")
case "${url##*.}" in
"repo"|"Z"|"bz"|"bz2"|"gz"|"tar"|"tbz"|"tbz2"|"tgz"|"tz"|"txz"|"xz")
case "${url##*/}" in
*".repo"|*".tar"|*".tar.Z"|*".tar.bz"|*".tar.bz2"|*".tar.gz"|*".tar.xz"|*".tbz"|*".tbz2"|*".tgz"|*".tz"|*".txz")
# an online repo or tarball
tmp="${TMP_DIR}/tmp_${url##*/}"
download_file "${url}" "${tmp}"
@@ -900,8 +1017,8 @@ function add_repo_by_url_apt()
warn_if_bad "$?" "unknown debian/ubuntu codename" || return 1
case "${url%%://*}" in
"ftp"|"http"|"https"|"ssh")
case "${url##*.}" in
"Z"|"bz"|"bz2"|"gz"|"tar"|"tbz"|"tbz2"|"tgz"|"tz"|"txz"|"xz")
case "${url##*/}" in
*".tar"|*".tar.Z"|*".tar.bz"|*".tar.bz2"|*".tar.gz"|*".tar.xz"|*".tbz"|*".tbz2"|*".tgz"|*".tz"|*".txz")
# an online tarball
tmp="${TMP_DIR}/tmp_${url##*/}"
download_file "${url}" "${tmp}"
@@ -953,9 +1070,17 @@ function remove_repo_yum()
type yum >/dev/null 2>&1 || return 255
local repo_id="$1"
# This deleting method is not good enough. Since there could be more
# than one repostory definitions in a single repo file.
# than one repository definitions in a single repo file.
# This is a quick and dirty method.
rm -f $(grep -l "^\[${repo_id}\]$" "/etc/yum.repos.d/"*".repo" 2>/dev/null)
case "${repo_id}" in
"xcat-core")
mv /etc/yum.repos.d/xCAT-core.repo{,.nouse} 2>/dev/null
;;
"xcat-dep")
mv /etc/yum.repos.d/xCAT-dep.repo{,.nouse} 2>/dev/null
;;
esac
yum clean metadata
:
}
@@ -966,6 +1091,15 @@ function remove_repo_zypper()
type zypper >/dev/null 2>&1 || return 255
local repo_id="$1"
zypper removerepo "${repo_id}"
case "${repo_id}" in
"xcat-core")
mv /etc/zypp/repos.d/xCAT-core.repo{,.nouse} 2>/dev/null
;;
"xcat-dep")
mv /etc/zypp/repos.d/xCAT-dep.repo{,.nouse} 2>/dev/null
;;
esac
:
}
# $1 repo id
@@ -997,10 +1131,10 @@ function add_xcat_core_repo_yum_or_zypper()
then
case "${ver}" in
"devel")
url="${GO_XCAT_DEFAULT_BASE_URL}/yum/devel/core-snap/xCAT-core.repo"
url="${GO_XCAT_DEFAULT_BASE_URL}/yum/devel/core-snap"
;;
*)
url="${GO_XCAT_DEFAULT_BASE_URL}/yum/${ver}/xcat-core/xCAT-core.repo"
url="${GO_XCAT_DEFAULT_BASE_URL}/yum/${ver}/xcat-core"
;;
esac
fi
@@ -1075,8 +1209,8 @@ function add_xcat_dep_repo_yum_or_zypper()
esac
case "${url%%://*}" in
"ftp"|"http"|"https")
case "${url##*.}" in
"Z"|"bz"|"bz2"|"gz"|"tar"|"tbz"|"tbz2"|"tgz"|"tz"|"txz"|"xz")
case "${url##*/}" in
*".tar"|*".tar.Z"|*".tar.bz"|*".tar.bz2"|*".tar.gz"|*".tar.xz"|*".tbz"|*".tbz2"|*".tgz"|*".tz"|*".txz")
# an online archive file
tmp="${TMP_DIR}/tmp_${url##*/}"
download_file "${url}" "${tmp}"
@@ -1679,8 +1813,8 @@ esac # case "${GO_XCAT_ACTION}" in
exit 0
# vim: set filetype=bash
# vim: set noautoindent
# vim: set tabstop=4 shiftwidth=4 softtabstop=4
# vim: filetype=sh
# vim: noautoindent
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# End of file
+2
View File
@@ -106,6 +106,7 @@ mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/xcat/scripts
mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/xcat/samples
mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/xcat/tools
mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/xcat/cons
mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/xcat/conf
mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/xcat/rollupdate
mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/xcat/installp_bundles
mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/xcat/image_data
@@ -151,6 +152,7 @@ chmod 644 $RPM_BUILD_ROOT/%{prefix}/share/xcat/ca/*
cp share/xcat/mypostscript/* $RPM_BUILD_ROOT/%{prefix}/share/xcat/mypostscript
cp share/xcat/scripts/* $RPM_BUILD_ROOT/%{prefix}/share/xcat/scripts
cp share/xcat/conf/* $RPM_BUILD_ROOT/%{prefix}/share/xcat/conf
cp share/xcat/samples/* $RPM_BUILD_ROOT/%{prefix}/share/xcat/samples
cp -r share/xcat/tools/* $RPM_BUILD_ROOT/%{prefix}/share/xcat/tools
cp -r share/xcat/hamn/* $RPM_BUILD_ROOT/%{prefix}/share/xcat/hamn
+3 -3
View File
@@ -13,7 +13,7 @@ my @apigroups = (
groupname => 'nodes',
header => "Node Resources",
desc => "The URI list which can be used to create, query, change and manage node objects.",
resources => [ 'allnode', 'nodeallattr', 'nodeattr', 'nodehost', 'nodedns', 'nodedhcp', 'nodestat', 'subnodes',
resources => [ 'allnode', 'nodeallattr', 'nodeattr', 'nodehost', 'nodedns', 'nodedhcp', 'nodestat', 'nodels', 'subnodes',
'power', 'energy', 'energyattr', 'serviceprocessor', 'nextboot', 'bootstate',
'vitals', 'vitalsattr', 'inventory', 'inventoryattr', 'eventlog', 'beacon',
'updating', 'filesyncing', 'software_maintenance', 'postscript', 'nodeshell', 'nodecopy',
@@ -181,9 +181,9 @@ sub make_rst_format {
my ($uri, $data);
if ($parts[3] =~ /\s+/) {
($uri, $data) = split(/ /, $parts[3]);
print "\n #curl -X $parts[2] -k \'https://127.0.0.1/xcatws$uri$postfix\' -H Content-Type:application/json --data \'$data\'\n";
print "\n curl -X $parts[2] -k \'https://127.0.0.1/xcatws$uri$postfix\' -H Content-Type:application/json --data \'$data\'\n";
} else {
print "\n #curl -X $parts[2] -k \'https://127.0.0.1/xcatws$parts[3]$postfix\'\n";
print "\n curl -X $parts[2] -k \'https://127.0.0.1/xcatws$parts[3]$postfix\'\n";
}
if ($parts[4]) {
+96
View File
@@ -0,0 +1,96 @@
#!/usr/bin/env python
"""Usage:
xcatws_test.py [--xcatmn=<xcatmn>] [--user=<user>] [--password=<password>]
"""
import requests
import json
import sys
XCATMN = "127.0.0.1"
username = "wsuser"
password = "cluster_rest"
#
# Gather user inputs if any, otherwise defaults above are used
#
try:
from docopt import docopt, DocoptExit
arguments = docopt(__doc__)
if arguments['--xcatmn']:
XCATMN = arguments['--xcatmn']
if arguments['--user']:
username = arguments['--user']
if arguments['--password']:
password = arguments['--password']
except ImportError:
print "WARNING: docopt is not installed, will continue with hard coded defaults..."
except DocoptExit as e:
# Invalid arguments
print e
sys.exit(1)
REST_ENDPOINT = "https://" + XCATMN + "/xcatws"
create_node = REST_ENDPOINT + "/nodes/"
get_all_nodes = REST_ENDPOINT + "/nodes/"
get_token = REST_ENDPOINT + "/tokens"
#
# Create a test node object
#
testnode_name = "rest_api_node"
testnode_group = "all"
testnode_mgt = "ipmi"
testnode_data = {'groups': testnode_group,'mgt': testnode_mgt}
try:
new_node = requests.post(create_node + testnode_name + "?userName=" + username + "&userPW=" + password, verify=False, headers={'Content-Type': 'application/json'}, data=json.dumps(testnode_data))
if new_node.content:
# Display node creation error
print "Failed to create new node " + testnode_name
print new_node.content
sys.exit(1)
else:
print "New node definition created for " + testnode_name + ".\n"
except requests.exceptions.HTTPError as e:
print ("Http Error:",e)
sys.exit(1)
except requests.exceptions.ConnectionError as e:
print "Error connecting to xCAT management node " + XCATMN
print e
sys.exit(1)
except requests.exceptions.Timeout as e:
print "Timeout connecting to xCAT management node " + XCATMN
print e
sys.exit(1)
except requests.exceptions.RequestException as e:
print "Unexpected error connecting to xCAT management node " + XCATMN
print e
sys.exit(1)
except AttributeError as e:
print "AttributeError caught, you may need to update the Perl libraries."
print e
sys.exit(1)
except Exception as e:
print "Unexpected error."
print e
sys.exit(1)
#
# Send a request to get all nodes, passing in user and password
#
all_nodes = requests.get(get_all_nodes + "?userName=" + username + "&userPW=" + password, verify=False)
# Display returned data
print "List of all nodes extracted with userid and password:"
print all_nodes.content
#
# Send a request to get all nodes, passing in a token
#
user_data = {'userName': username,'userPW': password}
token = requests.post(get_token, verify=False, headers={'Content-Type': 'application/json'}, data=json.dumps(user_data))
all_nodes = requests.get(get_all_nodes, verify=False, headers={'X-Auth-Token': token.json()['token']['id']})
# Display returned data
print "List of all nodes extracted with authentication token:"
print all_nodes.content
sys.exit(0)
+96 -30
View File
@@ -42,7 +42,7 @@ use IO::Socket::SSL;
my %usagemsg = (
objreturn => "Json format: An object which includes multiple \'<name> : {att:value, attr:value ...}\' pairs.",
objchparam => "Json format: An object which includes multiple \'att:value\' pairs.",
non_getreturn => "No output when execution is successfull. Otherwise output the error information in the Standard Error Format: {error:[msg1,msg2...],errocode:errornum}."
non_getreturn => "No output when execution is successful. Otherwise output the error information in the Standard Error Format: {error:[msg1,msg2...],errocode:errornum}."
);
# ver(1.0): Use array type instread of string split by '|' or ','
@@ -72,16 +72,16 @@ my %URIdef = (
desc => "[URI:/nodes/{noderange}] - The node resource",
matcher => '^/nodes/[^/]*$',
GET => {
desc => "Get all the attibutes for the node {noderange}.",
desc => "Get all the attributes for the node {noderange}.",
desc1 => "The keyword ALLRESOURCES can be used as {noderange} which means to get node attributes for all the nodes.",
usage => "||$usagemsg{objreturn}|",
example => "|Get all the attibutes for node \'node1\'.|GET|/nodes/node1|{\n \"node1\":{\n \"profile\":\"compute\",\n \"netboot\":\"xnba\",\n \"arch\":\"x86_64\",\n \"mgt\":\"ipmi\",\n \"groups\":\"all\",\n ...\n }\n}|",
example => "|Get all the attributes for node \'node1\'.|GET|/nodes/node1|{\n \"node1\":{\n \"profile\":\"compute\",\n \"netboot\":\"xnba\",\n \"arch\":\"x86_64\",\n \"mgt\":\"ipmi\",\n \"groups\":\"all\",\n ...\n }\n}|",
cmd => "lsdef",
fhandler => \&defhdl,
outhdler => \&defout,
},
PUT => {
desc => "Change the attibutes for the node {noderange}.",
desc => "Change the attributes for the node {noderange}.",
usage => "|$usagemsg{objchparam} DataBody: {attr1:v1,att2:v2,...}.|$usagemsg{non_getreturn}|",
example => "|Change the attributes mgt=dfm and netboot=yaboot.|PUT|/nodes/node1 {\"mgt\":\"dfm\",\"netboot\":\"yaboot\"}||",
cmd => "chdef",
@@ -138,6 +138,18 @@ my %URIdef = (
outhdler => \&actionout,
},
},
nodels => {
desc => "[URI:/nodes/{noderange}/nodels}] - Lists the nodes, noderange cannot start with /",
matcher => '^/nodes/[^/]*/nodels$',
GET => {
desc => "Lists the nodes.",
usage => "||Json format: An array of node names.|",
example => "|Get the node names from xCAT database.|GET|/nodes/node[1-3]/nodels|[\n \"node1\",\n \"node2\",\n \"node3\",\n]|",
cmd => "nodels",
fhandler => \&actionhdl,
outhdler => \&nodelsout,
},
},
nodehost => {
desc => "[URI:/nodes/{noderange}/host] - The mapping of ip and hostname for the node {noderange}",
matcher => '^/nodes/[^/]*/host$',
@@ -351,7 +363,7 @@ my %URIdef = (
desc => "[URI:/nodes/{noderange}/vitals] - The vitals resources for the node {noderange}",
matcher => '^/nodes/[^/]*/vitals$',
GET => {
desc => "Get all the vitals attibutes.",
desc => "Get all the vitals attributes.",
usage => "||$usagemsg{objreturn}|",
example => "|Get all the vitails attributes for the node1.|GET|/nodes/node1/vitals|{\n \"node1\":{\n \"SysBrd Fault\":\"0\",\n \"CPUs\":\"0\",\n \"Fan 4A Tach\":\"3330 RPM\",\n \"Drive 15\":\"0\",\n \"SysBrd Vol Fault\":\"0\",\n \"nvDIMM Flash\":\"0\",\n \"Progress\":\"0\"\n ...\n }\n}|",
cmd => "rvitals",
@@ -364,7 +376,7 @@ my %URIdef = (
desc => "[URI:/nodes/{noderange}/vitals/{temp|voltage|wattage|fanspeed|power|leds...}] - The specific vital attributes for the node {noderange}",
matcher => '^/nodes/[^/]*/vitals/\S+$',
GET => {
desc => "Get the specific vitals attibutes.",
desc => "Get the specific vitals attributes.",
usage => "||$usagemsg{objreturn}|",
example => "|Get the \'fanspeed\' vitals attribute.|GET|/nodes/node1/vitals/fanspeed|{\n \"node1\":{\n \"Fan 1A Tach\":\"3219 RPM\",\n \"Fan 4B Tach\":\"2688 RPM\",\n \"Fan 3B Tach\":\"2560 RPM\",\n \"Fan 4A Tach\":\"3330 RPM\",\n \"Fan 2A Tach\":\"3293 RPM\",\n \"Fan 1B Tach\":\"2592 RPM\",\n \"Fan 3A Tach\":\"3182 RPM\",\n \"Fan 2B Tach\":\"2592 RPM\"\n }\n}|",
cmd => "rvitals",
@@ -376,7 +388,7 @@ my %URIdef = (
desc => "[URI:/nodes/{noderange}/inventory] - The inventory attributes for the node {noderange}",
matcher => '^/nodes/[^/]*/inventory$',
GET => {
desc => "Get all the inventory attibutes.",
desc => "Get all the inventory attributes.",
usage => "||$usagemsg{objreturn}|",
example => "|Get all the inventory attributes for node1.|GET|/nodes/node1/inventory|{\n \"node1\":{\n \"DIMM 21 \":\"8GB PC3-12800 (1600 MT/s) ECC RDIMM\",\n \"DIMM 1 Manufacturer\":\"Hyundai Electronics\",\n \"Power Supply 2 Board FRU Number\":\"94Y8105\",\n \"DIMM 9 Model\":\"HMT31GR7EFR4C-PB\",\n \"DIMM 8 Manufacture Location\":\"01\",\n \"DIMM 13 Manufacturer\":\"Hyundai Electronics\",\n \"DASD Backplane 4\":\"Not Present\",\n ...\n }\n}|",
cmd => "rinv",
@@ -388,7 +400,7 @@ my %URIdef = (
desc => "[URI:/nodes/{noderange}/inventory/{pci|model...}] - The specific inventory attributes for the node {noderange}",
matcher => '^/nodes/[^/]*/inventory/\S+$',
GET => {
desc => "Get the specific inventory attibutes.",
desc => "Get the specific inventory attributes.",
usage => "||$usagemsg{objreturn}|",
example => "|Get the \'model\' inventory attribute for node1.|GET|/nodes/node1/inventory/model|{\n \"node1\":{\n \"System Description\":\"System x3650 M4\",\n \"System Model/MTM\":\"7915C2A\"\n }\n}|",
cmd => "rinv",
@@ -632,15 +644,15 @@ my %URIdef = (
desc => "[URI:/groups/{groupname}] - The group resource",
matcher => '^/groups/[^/]*$',
GET => {
desc => "Get all the attibutes for the group {groupname}.",
desc => "Get all the attributes for the group {groupname}.",
usage => "||$usagemsg{objreturn}|",
example => "|Get all the attibutes for group \'all\'.|GET|/groups/all|{\n \"all\":{\n \"members\":\"zxnode2,nodexxx,node1,node4\"\n }\n}|",
example => "|Get all the attributes for group \'all\'.|GET|/groups/all|{\n \"all\":{\n \"members\":\"zxnode2,nodexxx,node1,node4\"\n }\n}|",
cmd => "lsdef",
fhandler => \&defhdl,
outhdler => \&defout,
},
PUT => {
desc => "Change the attibutes for the group {groupname}.",
desc => "Change the attributes for the group {groupname}.",
usage => "|$usagemsg{objchparam} DataBody: {attr1:v1,att2:v2,...}.|$usagemsg{non_getreturn}|",
example => "|Change the attributes mgt=dfm and netboot=yaboot.|PUT|/groups/all {\"mgt\":\"dfm\",\"netboot\":\"yaboot\"}||",
cmd => "chdef",
@@ -830,16 +842,16 @@ my %URIdef = (
desc => "[URI:/networks/{netname}] - The network resource",
matcher => '^\/networks\/[^\/]*$',
GET => {
desc => "Get all the attibutes for the network {netname}.",
desc => "Get all the attributes for the network {netname}.",
desc1 => "The keyword ALLRESOURCES can be used as {netname} which means to get network attributes for all the networks.",
usage => "||$usagemsg{objreturn}|",
example => "|Get all the attibutes for network \'network1\'.|GET|/networks/network1|{\n \"network1\":{\n \"gateway\":\"<xcatmaster>\",\n \"mask\":\"255.255.255.0\",\n \"mgtifname\":\"eth2\",\n \"net\":\"10.0.0.0\",\n \"tftpserver\":\"10.0.0.119\",\n ...\n }\n}|",
example => "|Get all the attributes for network \'network1\'.|GET|/networks/network1|{\n \"network1\":{\n \"gateway\":\"<xcatmaster>\",\n \"mask\":\"255.255.255.0\",\n \"mgtifname\":\"eth2\",\n \"net\":\"10.0.0.0\",\n \"tftpserver\":\"10.0.0.119\",\n ...\n }\n}|",
cmd => "lsdef",
fhandler => \&defhdl,
outhdler => \&defout,
},
PUT => {
desc => "Change the attibutes for the network {netname}.",
desc => "Change the attributes for the network {netname}.",
usage => "|$usagemsg{objchparam} DataBody: {attr1:v1,att2:v2,...}.|$usagemsg{non_getreturn}|",
example => "|Change the attributes mgtifname=eth0 and net=10.1.0.0.|PUT|/networks/network1 {\"mgtifname\":\"eth0\",\"net\":\"10.1.0.0\"}||",
cmd => "chdef",
@@ -919,7 +931,7 @@ my %URIdef = (
desc => "[URI:/osimages/{imgname}] - The osimage resource",
matcher => '^\/osimages\/[^\/]*$',
GET => {
desc => "Get all the attibutes for the osimage {imgname}.",
desc => "Get all the attributes for the osimage {imgname}.",
desc1 => "The keyword ALLRESOURCES can be used as {imgname} which means to get image attributes for all the osimages.",
usage => "||$usagemsg{objreturn}|",
example => "|Get the attributes for the specified osimage.|GET|/osimages/sles11.2-x86_64-install-compute|{\n \"sles11.2-x86_64-install-compute\":{\n \"provmethod\":\"install\",\n \"profile\":\"compute\",\n \"template\":\"/opt/xcat/share/xcat/install/sles/compute.sles11.tmpl\",\n \"pkglist\":\"/opt/xcat/share/xcat/install/sles/compute.sles11.pkglist\",\n \"osvers\":\"sles11.2\",\n \"osarch\":\"x86_64\",\n \"osname\":\"Linux\",\n \"imagetype\":\"linux\",\n \"otherpkgdir\":\"/install/post/otherpkgs/sles11.2/x86_64\",\n \"osdistroname\":\"sles11.2-x86_64\",\n \"pkgdir\":\"/install/sles11.2/x86_64\"\n }\n}|",
@@ -937,7 +949,7 @@ my %URIdef = (
outhdler => \&noout,
},
PUT => {
desc => "Change the attibutes for the osimage {imgname}.",
desc => "Change the attributes for the osimage {imgname}.",
usage => "|$usagemsg{objchparam} DataBody: {attr1:v1,attr2:v2...}|$usagemsg{non_getreturn}|",
example => "|Change the 'osvers' and 'osarch' attributes for the osiamge.|PUT|/osimages/sles11.2-ppc64-install-compute/ {\"osvers\":\"sles11.3\",\"osarch\":\"x86_64\"}||",
cmd => "chdef",
@@ -968,7 +980,7 @@ my %URIdef = (
# TD, the implementation may need to be change.
PUT_backup => {
desc => "Change the attibutes for the osimage {imgname}.",
desc => "Change the attributes for the osimage {imgname}.",
usage => "|$usagemsg{objchparam} DataBody: {attr1:v1,attr2:v2...}|$usagemsg{non_getreturn}|",
example => "|Change the 'osvers' and 'osarch' attributes for the osiamge.|PUT|/osimages/sles11.2-ppc64-install-compute/attrs/osvers;osarch {\"osvers\":\"sles11.3\",\"osarch\":\"x86_64\"}||",
cmd => "chdef",
@@ -1020,7 +1032,7 @@ my %URIdef = (
desc => "[URI:/policy/{policy_priority}] - The policy resource",
matcher => '^\/policy\/[^\/]*$',
GET => {
desc => "Get all the attibutes for a policy {policy_priority}.",
desc => "Get all the attributes for a policy {policy_priority}.",
desc1 => "It will display all the policy attributes for one policy resource.",
desc2 => "The keyword ALLRESOURCES can be used as {policy_priority} which means to get policy attributes for all the policies.",
usage => "||$usagemsg{objreturn}|",
@@ -1030,7 +1042,7 @@ my %URIdef = (
outhdler => \&defout,
},
PUT => {
desc => "Change the attibutes for the policy {policy_priority}.",
desc => "Change the attributes for the policy {policy_priority}.",
desc1 => "It will change one or more attributes for a policy.",
usage => "|$usagemsg{objchparam} DataBody: {attr1:v1,att2:v2,...}.|$usagemsg{non_getreturn}|",
example => "|Set the name attribute for policy 3.|PUT|/policy/3 {\"name\":\"root\"}||",
@@ -1144,7 +1156,7 @@ my %URIdef = (
desc1 => "For a large number of nodes, this API call can be faster than using the corresponding nodes resource. The disadvantage is that you need to know the table names the attributes are stored in.",
matcher => '^/tables/[^/]+/nodes/[^/]+$',
GET => {
desc => "Get attibutes of tables for a noderange.",
desc => "Get attributes of tables for a noderange.",
usage => "||An object containing each table. Within each table object is an array of node objects containing the attributes.|",
example1 => qq(|Get all the columns from table nodetype for node1 and node2.|GET|/tables/nodetype/nodes/node1,node2|{\n \"nodetype\":[\n {\n \"provmethod\":\"rhels6.4-x86_64-install-compute\",\n \"profile\":\"compute\",\n \"arch\":\"x86_64\",\n \"name\":\"node1\",\n \"os\":\"rhels6.4\"\n },\n {\n \"provmethod\":\"rhels6.3-x86_64-install-compute\",\n \"profile\":\"compute\",\n \"arch\":\"x86_64\",\n \"name\":\"node2\",\n \"os\":\"rhels6.3\"\n }\n ]\n}|),
example2 => qq(|Get all the columns from tables nodetype and noderes for node1 and node2.|GET|/tables/nodetype,noderes/nodes/node1,node2|{\n \"noderes\":[\n {\n \"installnic\":\"mac\",\n \"netboot\":\"xnba\",\n \"name\":\"node1\",\n \"nfsserver\":\"192.168.1.15\"\n },\n {\n \"installnic\":\"mac\",\n \"netboot\":\"pxe\",\n \"name\":\"node2\",\n \"proxydhcp\":\"no\"\n }\n ],\n \"nodetype\":[\n {\n \"provmethod\":\"rhels6.4-x86_64-install-compute\",\n \"profile\":\"compute\",\n \"arch\":\"x86_64\",\n \"name\":\"node1\",\n \"os\":\"rhels6.4\"\n },\n {\n \"provmethod\":\"rhels6.3-x86_64-install-compute\",\n \"profile\":\"compute\",\n \"arch\":\"x86_64\",\n \"name\":\"node2\",\n \"os\":\"rhels6.3\"\n }\n ]\n}|),
@@ -1152,7 +1164,7 @@ my %URIdef = (
outhdler => \&tableout,
},
PUT => {
desc => "Change the node table attibutes for {noderange}.",
desc => "Change the node table attributes for {noderange}.",
usage => "|A hash of table names and attribute objects. DataBody: {table1:{attr1:v1,att2:v2,...}}.|$usagemsg{non_getreturn}|",
example => '|Change the nodetype.arch and noderes.netboot attributes for nodes node1,node2.|PUT|/tables/nodetype,noderes/nodes/node1,node2 {"nodetype":{"arch":"x86_64"},"noderes":{"netboot":"xnba"}}||',
fhandler => \&tablenodeputhdl,
@@ -1164,14 +1176,14 @@ my %URIdef = (
desc1 => "For a large number of nodes, this API call can be faster than using the corresponding nodes resource. The disadvantage is that you need to know the table names the attributes are stored in.",
matcher => '^/tables/[^/]+/nodes/[^/]+/[^/]+$',
GET => {
desc => "Get table attibutes for a noderange.",
desc => "Get table attributes for a noderange.",
usage => "||An object containing each table. Within each table object is an array of node objects containing the attributes.|",
example => qq(|Get OS and ARCH attributes from nodetype table for node1 and node2.|GET|/tables/nodetype/nodes/node1,node2/os,arch|{\n \"nodetype\":[\n {\n \"arch\":\"x86_64\",\n \"name\":\"node1\",\n \"os\":\"rhels6.4\"\n },\n {\n \"arch\":\"x86_64\",\n \"name\":\"node2\",\n \"os\":\"rhels6.3\"\n }\n ]\n}|),
fhandler => \&tablenodehdl,
outhdler => \&tableout,
},
PUT_backup => {
desc => "[URI:/tables/nodes/{noderange}] - Change the node table attibutes for the {noderange}.",
desc => "[URI:/tables/nodes/{noderange}] - Change the node table attributes for the {noderange}.",
usage => "|A hash of table names and attribute objects. DataBody: {table1:{attr1:v1,att2:v2,...}}.|$usagemsg{non_getreturn}|",
example => '|Change the nodehm.mgmt and noderes.netboot attributes for nodes node1-node5.|PUT|/tables/nodes/node1-node5 {"nodehm":{"mgmt":"ipmi"},"noderes":{"netboot":"xnba"}}||',
fhandler => \&tablenodeputhdl,
@@ -1196,14 +1208,14 @@ my %URIdef = (
desc2 => "{keys} should be the name=value pairs which are used to search table. e.g. {keys} should be [net=192.168.1.0,mask=255.255.255.0] for networks table query since the net and mask are the keys of networks table.",
matcher => '^/tables/[^/]+/rows/[^/]+$',
GET => {
desc => "Get attibutes for rows from non-node tables.",
desc => "Get attributes for rows from non-node tables.",
usage => "||An object containing each table. Within each table object is an array of row objects containing the attributes.|",
example => qq(|Get row which net=192.168.1.0,mask=255.255.255.0 from networks table.|GET|/tables/networks/rows/net=192.168.1.0,mask=255.255.255.0|{\n \"networks\":[\n {\n \"mgtifname\":\"eth0\",\n \"netname\":\"192_168_1_0-255_255_255_0\",\n \"tftpserver\":\"192.168.1.15\",\n \"gateway\":\"192.168.1.100\",\n \"staticrangeincrement\":\"1\",\n \"net\":\"192.168.1.0\",\n \"mask\":\"255.255.255.0\"\n }\n ]\n}|),
fhandler => \&tablerowhdl,
outhdler => \&tableout,
},
PUT => {
desc => "Change the non-node table attibutes for the row that matches the {keys}.",
desc => "Change the non-node table attributes for the row that matches the {keys}.",
usage => "|A hash of attribute names and values. DataBody: {attr1:v1,att2:v2,...}.|$usagemsg{non_getreturn}|",
example => '|Create a route row in the routes table.|PUT|/tables/routes/rows/routename=privnet {"net":"10.0.1.0","mask":"255.255.255.0","gateway":"10.0.1.254","ifname":"eth1"}||',
fhandler => \&tablerowputhdl,
@@ -1222,7 +1234,7 @@ my %URIdef = (
desc1 => "Use this for tables that don't have node name as the key of the table, for example: passwd, site, networks, polciy, etc.",
matcher => '^/tables/[^/]+/rows/[^/]+/[^/]+$',
GET => {
desc => "Get specific attibutes for rows from non-node tables.",
desc => "Get specific attributes for rows from non-node tables.",
usage => "||An object containing each table. Within each table object is an array of row objects containing the attributes.|",
example => qq(|Get attributes mgtifname and tftpserver which net=192.168.1.0,mask=255.255.255.0 from networks table.|GET|/tables/networks/rows/net=192.168.1.0,mask=255.255.255.0/mgtifname,tftpserver|{\n \"networks\":[\n {\n \"mgtifname\":\"eth0\",\n \"tftpserver\":\"192.168.1.15\"\n }\n ]\n}|),
fhandler => \&tablerowhdl,
@@ -1239,7 +1251,7 @@ my %URIdef = (
POST => {
desc => "Create a token.",
usage => "||An array of all the global configuration list.|",
example => "|Aquire a token for user \'root\'.|POST|/tokens {\"userName\":\"root\",\"userPW\":\"cluster\"}|{\n \"token\":{\n \"id\":\"a6e89b59-2b23-429a-b3fe-d16807dd19eb\",\n \"expire\":\"2014-3-8 14:55:0\"\n }\n}|",
example => "|Acquire a token for user \'root\'.|POST|/tokens {\"userName\":\"root\",\"userPW\":\"cluster\"}|{\n \"token\":{\n \"id\":\"a6e89b59-2b23-429a-b3fe-d16807dd19eb\",\n \"expire\":\"2014-3-8 14:55:0\"\n }\n}|",
fhandler => \&nonobjhdl,
outhdler => \&tokenout,
},
@@ -1279,7 +1291,7 @@ my %URIdef = (
GET => {
desc => "Show attributes of a node template.",
usage => "||$usagemsg{objreturn}|",
example => "|GET all the attibutes of node template \'x86_64kvmguest-template\'.|GET|/templates/node {\"options\":{\"--template\":\"x86_64kvmguest-template\"}} |{\n \"arch\":{\n \"x86_64\":\"compute\",\n \"bmc\":\"MANDATORY:The hostname or ip address of the BMC adapater\",\n \bmcpassword\":\"MANDATORY:the password of the BMC\",\n \"mgt\":\"ipmi\",\n \"groups\":\"all\",\n ...\n }\n}",
example => "|GET all the attributes of node template \'x86_64kvmguest-template\'.|GET|/templates/node {\"options\":{\"--template\":\"x86_64kvmguest-template\"}} |{\n \"arch\":{\n \"x86_64\":\"compute\",\n \"bmc\":\"MANDATORY:The hostname or ip address of the BMC adapater\",\n \bmcpassword\":\"MANDATORY:the password of the BMC\",\n \"mgt\":\"ipmi\",\n \"groups\":\"all\",\n ...\n }\n}",
cmd => "lsdef",
fhandler => \&defhdl,
outhdler => \&defout,
@@ -1755,6 +1767,56 @@ sub defout_remove_appended_info {
}
}
#handle output of nodels command
#input data like:
#$VAR1 = [
# {
# 'xcatdsource' => [
# 'bybc0602'
# ],
# 'node' => [
# {
# 'name' => [
# 'node1'
# ]
# },
# {
# 'name' => [
# 'node2'
# ]
# },
# {
# 'name' => [
# 'node3'
# ]
# }
# ]
# }
# ];
#TO:
#------------
# [
# 'node1',
# 'node2',
# 'node3'
# ];
sub nodelsout {
my $data = shift;
my $json;
foreach my $d (@$data) {
my $jsonnode;
my $lines = $d->{node};
foreach my $l (@$lines) {
push(@{$json}, $l->{name}[0]);
}
}
if ($json) {
addPageContent($JSON->encode($json), 1);
}
}
sub localresout {
my $data = shift;
@@ -2060,6 +2122,10 @@ sub actionhdl {
} else {
error("Missed Action.", $STATUS_NOT_FOUND);
}
} elsif ($params->{'resourcename'} eq "nodels") {
if (isGET()) {
}
} elsif ($params->{'resourcename'} =~ /(energy|energyattr)/) {
if (isGET()) {
if ($params->{'resourcename'} eq "energy") {
@@ -2828,7 +2894,7 @@ sub tablenodeputhdl {
my $params = shift;
# from the %URIdef:
# desc => "[URI:/tables/nodes/{noderange}] - Change the table attibutes for the {noderange}.",
# desc => "[URI:/tables/nodes/{noderange}] - Change the table attributes for the {noderange}.",
# usage => "|An array of table objects. Each table object contains the table name and an object of attribute values. DataBody: {table1:{attr1:v1,att2:v2,...}}.|$usagemsg{non_getreturn}|",
# example => '|Change the nodehm.mgmt and noderes.netboot attributes for nodes node1-node5.|PUT|/tables/nodes/node1-node5 {"nodehm":{"mgmt":"ipmi"},"noderes":{"netboot":"xnba"}}||',
@@ -2895,7 +2961,7 @@ sub tablerowputhdl {
my $params = shift;
# from %URIdef:
# desc => "[URI:/tables/{table}/rows/{keys}] - Change the non-node table attibutes for the row that matches the {keys}.",
# desc => "[URI:/tables/{table}/rows/{keys}] - Change the non-node table attributes for the row that matches the {keys}.",
# usage => "|A hash of attribute names and values. DataBody: {attr1:v1,att2:v2,...}.|$usagemsg{non_getreturn}|",
# example => '|Creat a route row in the routes table.|PUT|/tables/routes/rows/routename=privnet {"net":"10.0.1.0","mask":"255.255.255.0","gateway":"10.0.1.254","ifname":"eth1"}||',
@@ -33,3 +33,30 @@ cmd:reventlog $$CN resolved=-1
check:rc==1
check:output=~Error: Invalid ID=
end
start:reventlog_resolved_parse_error5
description: Pass in a string
os:Linux
hcp:openbmc
cmd:reventlog $$CN resolved=abc
check:rc==1
check:output=~Error: Invalid ID=
end
start:reventlog_resolved_list
description: Pass in a list of ids
os:Linux
hcp:openbmc
cmd:reventlog $$CN resolved=100,101
check:rc==0
check:output=~Attempting to resolve the following log entries: 100,101...
end
start:reventlog_resolved_LED
description: Pass in a LED keyword
os:Linux
hcp:openbmc
cmd:reventlog $$CN resolved=Led
check:rc==0
check:output=~Attempting to resolve the following log entries: Led...
end
@@ -70,3 +70,12 @@ cmd: rflash $$CN --delete 221d9020 221d9020
check:rc==1
check:output=~Error: More than one firmware specified is not supported
end
start:rflash_delete_active_bmc
description: Attempt to delete the active BMC firmware
os:Linux
hcp:openbmc
cmd: rflash $$CN -l | grep \* | grep BMC | awk '{print $2}' | xargs -i{} rflash $$CN --delete {}
check:rc==1
check:output=~$$CN: Error: Deleting currently active BMC firmware is not supported
end
@@ -0,0 +1,156 @@
start:supported_cmds_rpower
description: Make sure the rpower command works ...
os:Linux
hcp:openbmc
cmd:rpower $$CN state
check:rc==0
check:output=~$$CN:
cmd: rpower $$CN bmcstate
check:rc==0
check:output=~$$CN: BMC
end
start:supported_cmds_rinv
description: Make sure that the rinv command works...
os:Linux
hcp:openbmc
cmd: rinv $$CN
check:rc==0
check:output=~$$CN:
cmd: rinv $$CN model
check:rc==0
check:output=~$$CN: SYSTEM Model
cmd: rinv $$CN serial
check:rc==0
check:output=~$$CN: SYSTEM SerialNumber
cmd: rinv $$CN firm
check:rc==0
check:output=~$$CN: Host Firmware
check:output=~$$CN: BMC Firmware
cmd: rinv $$CN cpu
check:rc==0
check:output=~$$CN: CPU
cmd: rinv $$CN dimm
check:rc==0
check:output=~$$CN: DIMM
end
start:supported_cmds_rvitals
description: Make sure that the rvitals command works...
os:Linux
hcp:openbmc
cmd: rvitals $$CN
check:rc==0
check:output=~$$CN:
cmd: rvitals $$CN temp
check:rc==0
check:output=~$$CN: Ambient:
cmd: rvitals $$CN voltage
check:rc==0
check:output=~$$CN: Ps0 Input Voltage:
cmd: rvitals $$CN wattage
check:rc==0
check:output=~$$CN: Total Power:
cmd: rvitals $$CN fanspeed
check:rc==0
check:output=~$$CN: Fan
cmd: rvitals $$CN power
check:rc==0
check:output=~$$CN: Total Power:
cmd: rvitals $$CN leds
check:rc==0
check:output=~$$CN: Front
check:output=~$$CN: Front Fans
check:output=~$$CN: Rear
cmd: rvitals $$CN all
check:rc==0
check:output=~$$CN: Ambient:
end
start:supported_cmds_rbeacon
description: Make sure the rbeacon command works ...
os:Linux
hcp:openbmc
cmd:rbeacon $$CN on
check:rc==0
check:output=~$$CN: on
cmd: rbeacon $$CN off
check:rc==0
check:output=~$$CN: off
end
start:supported_cmds_reventlog
description: Make sure the reventlog command works ...
os:Linux
hcp:openbmc
cmd:reventlog $$CN
check:rc==0
check:output=~$$CN:
cmd: reventlog $$CN 1
check:rc==0
check:output=~$$CN:
cmd: reventlog $$CN all
check:rc==0
check:output=~$$CN:
end
start:supported_cmds_rflash
description: Make sure the rflash command works ...
os:Linux
hcp:openbmc
cmd:rflash $$CN -c
check:rc==0
check:output=~$$CN: BMC Firmware Product:
check:output=~$$CN: HOST Firmware Product:
cmd:rflash $$CN -l
check:rc==0
check:output=~$$CN: ID
end
start:supported_cmds_rsetboot
description: Make sure the rsetboot command works ...
os:Linux
hcp:openbmc
cmd:rsetboot $$CN stat
check:rc==0
check:output=~$$CN:
end
start:supported_cmds_rspconfig
description: Make sure the rspconfig command works ...
os:Linux
hcp:openbmc
cmd:rspconfig $$CN ipsrc
check:rc==0
check:output=~$$CN: BMC IP Source:
cmd:rspconfig $$CN ip
check:rc==0
check:output=~$$CN: BMC IP:
cmd:rspconfig $$CN netmask
check:rc==0
check:output=~$$CN: BMC Netmask:
cmd:rspconfig $$CN gateway
check:rc==0
check:output=~$$CN: BMC Gateway:
cmd:rspconfig $$CN hostname
check:rc==0
check:output=~$$CN: BMC Hostname:
cmd:rspconfig $$CN vlan
check:rc==0
check:output=~$$CN: BMC VLAN ID:
cmd:rspconfig $$CN dump -l
check:rc==0
check:output=~$$CN:
cmd:rspconfig $$CN powerrestorepolicy
check:rc==0
check:output=~$$CN: BMC PowerRestorePolicy
cmd:rspconfig $$CN powersupplyredundancy
check:rc==0
check:output=~$$CN: BMC PowerSupplyRedundancy
cmd:rspconfig $$CN autoreboot
check:rc==0
check:output=~$$CN: BMC AutoReboot
cmd:rspconfig $$CN bootmode
check:rc==0
check:output=~$$CN: BMC BootMode
end

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